從壹開始前後端分離 [ Vue2.0+.NET Core2.1] 二十║Vue基礎終篇:元件詳解+專案說明
緣起
新的一天又開始啦,大家也應該看到我的標題了,是滴,Vue基礎基本就到這裡了,咱們回頭看看這一路,如果你都看了,並且都會寫了,那麼現在你就可以自己寫一個Demo了,如果再瞭解一點路由,ajax請求(這裡是axios),那麼你就可以準備面試前端了,哈哈,當然沒有這麼誇張,往後的路還很長,至少咱們基礎都會了。
這裡咱們再溫習下之前講了哪些基礎知識:
《 ofollow,noindex" target="_blank">十五 ║Vue前篇:瞭解JS面向物件原理 & 學會巢狀字面量等4種函式定義 & this指向 》
《 十六 ║Vue前篇:ES6知識詳細說明 & 如何在JS中進行模組化程式設計 》
《 十七 ║Vue基礎:第一次頁面引入Vue.js,瞭解 Vue例項是如何通過資料驅動來操作DOM的 》
《 十八 ║Vue基礎: 學習了常用的十大指令並一一舉例,然後瞭解到了Vue的計算屬性,偵聽器,當然還有過濾器 》
《 十九 ║Vue基礎: 通過樣式的動態繫結,進一步學習Vue是如何操作DOM的,然後深入瞭解生命週期的八個階段,以及其中的職能 》
一共是五篇,基本已經涵蓋了Vue的基礎知識,今天呢,再說完元件以後,明天就正式開始搭建本地腳手架,終於開始安裝軟體了[ 哭笑 ],我這幾天考慮了一下,在之後的講解中,可能需要兩個小專案的講解,第一個就是我現在自己用到的一個,大家其實也可以看看 http://vue.blog.azlinli.com (買的伺服器不好,首次載入慢),也不是啥隱私,這個是我之前練習的時候自己瞎玩的,只有首頁和詳情頁,用的資料就是咱們在之前系列裡講到的.net core api,這個可能在本週,或者本週末說到,主要的就是把之前的講解給穿起來,然後再說下如何使用路由 v-router 和 ajax請求——axios,這樣我這個專案就說到這裡, 然後第二個也是一個部落格系統 ,用的是一套資料,只不過是用到了 Nuxt 框架了,基本結構又發生了變化,專案整體被封裝了,更趨於工程化,至於為什麼要用到這個,就是因為它可以解決 MVVM 前後端分離的 SEO 的老大難的問題,大家可以先問問度娘,到時候都會說到滴。好啦,開始今天的基礎篇最後一章節 —— 深入瞭解下元件。
零、今天要完成 天青色 的部分
一、元件的基本使用
1、註冊元件
上篇檔案我們也說到了,註冊元件的其中一個辦法就是 Vue.component()
方法,先傳入一個自定義元件的名字,然後傳入這個元件的配置。
Vue.component('mycomponent',{ template: `<div>我的元件</div>`, data () { return { message: '老張的哲學' } } })
定義好後,我們就可以在Vue例項所定義的DOM元素內使用它(就是我們在new vue的時候的 el 節點),這裡我們的頁尾元件,全域性元件,可以在其他地方使用
<div id="app"> <mycomponent></mycomponent> <my-component></my-component> </div> <script> //注意要在vue例項之前去定義,不然渲染頁面的時候,會報錯 // 定義一個名為 footer-vue 的新元件 Vue.component('footer-vue', { template: ` <div id="footer-vue"> <p>2018 <a href="#">LZ's Blog</a> - Hosted by <a href="#" style="font-weight: bold">Coding Pages</a></p> <p> <a href="#">京ICP備00000000號</a> </p> </div> `, data () { return { message: 'hello world' } } }) var app = new Vue({ el: '#app',//沒錯,vue例項所定義的DOM元素就是這個,超過了這個區域,定義的元件會無效 data: { }, }) </script>
這個時候,我們定義的元件是一個全域性的元件,也就是說如果我們定義了多個 vue例項,我們都可以使用這一個元件,這就是全域性的,當然,既然有全域性的,我們也有區域性的(我們對聯絡方法定義區域性元件,表示只有在當前頁面的app元素內使用):
var app = new Vue({ el: '#app', data: { }, components: { 'my-component': { template: ` <ul class ="contact-list non-style-list"> <li> <b class ="twitter">TWITTER</b>: <a href="#">@laozhang</a> </li> <li> <b class ="weibo">微博</b>: <a href="#">@laozhang</a> </li> <li> <b class ="zhihu">知乎</b>: <a href="#" ></a> </li> <li> <b class ="github">GITHUB</b>: <a href="https://github.com/anjoy8">anjoy8</a> </li> <li> <b class ="email">EMAIL</b>: <a href="mailto:[email protected]">randypriv at azlinli</a> </li> </ul> `, data () { return { message: 'hello world two' } } } } })
2、元件的規範定義——單個根元素 + 函式
觀察一下上邊兩種寫法與的特點,大家應該也能說出來:
相同點:元件的模板只能有一個根節點,或者說根標籤只能有一個(第一個的根元素是 <div>,第二個根元素是 <ul>),如果定義成這樣就是不允許的,這裡是兩個根元素 <div> 和 <a>:
template: `<div>我的地盤聽我的,哈哈,只能在當前我的Vue例項中使用</div> <a>我的一個標籤</a> `,
不同點:
我們看到在定義元件的時候和平時定義的data不一樣,這裡的 定義一定要是一個函式 ,因為如果像Vue例項那樣,傳入一個物件,由於JS中物件型別的變數實際上儲存的是物件的 引用
,所以當存在多個這樣的元件時,會共享資料,導致一個元件中資料的改變會引起其他元件資料的改變。而使用一個返回物件的函式,每次使用元件都會建立一個新的物件,這樣就不會出現 共享資料 的問題來了。
Vue.component('footer-vue', { template: ` <div id="footer-vue"> <p> <a href="#">京ICP備00000000號</a> </p> </div> `, data :{ message: 'hello world'//我們用普通屬性的方法 } })
如果我們按照一個 屬性的寫法 的話,頁面會成功的報了一個這樣的錯誤,而且大家注意,這個錯誤是出現在哪裡的,沒錯就是 掛載結束前 ,也就是說,和例項化資料沒影響,但是在掛載到頁面,頁面渲染的時候,出現了這個錯誤,所以大家在初學的時候,還是要多瞭解下生命週期的概念。
3、另外一種註冊方式,通過 全域性API: Vue.extend()建立,然後由component來註冊
//extend 建立元件 var MyComponent = Vue.extend({ template: '<div>A custom component!</div>' }); // component註冊 元件 Vue.component('my-component', MyComponent);//使用到了 extend 建立的元件 var vm = new Vue({ el: '#example', data: { } })
兩種寫法沒有什麼太多的區別,基本來說
extend 是構造一個元件的語法器,你給它引數 他給你一個元件 然後這個元件,你可以作用到Vue.component 這個全域性註冊方法裡, 也可以在任意vue模板裡使用apple元件
var apple = Vue.extend({
….
})
Vue.component(‘apple’,apple)
你可以作用到vue例項或者某個元件中的components屬性中並在內部使用apple元件
new Vue({
components:{
apple:apple
}
})
Vue.component 你可以建立 ,也可以取元件 例如下
var apple = Vue.component(‘apple’)
二、屬性Props —— 父子通訊(父傳子)
在 Vue 中,父子元件的關係可以總結為 prop
向下傳遞, 事件
向上傳遞。父元件通過 prop
給子元件下發資料,子元件通過 事件
給父元件傳送訊息,這裡咱們先說下向下傳遞,通過屬性Props屬性來完成。
1、使用動態屬性Props,可以將父元件的資料傳遞給子元件,從而達到父子通訊的第一步,舉個栗子
還記得之前咱們說的,Vue 其實就是由許許多多個元件拼接而成,高效複用,相互之間可以傳值,但是又不受影響,最常見的應用就是:元件 A 在它的模板中使用了元件 B。它們之間必然需要相互通訊:父元件可能要給子元件下發資料,子元件則可能要將它內部發生的事情告知父元件。大家第一次使用的時候可能會有點兒不舒服,但是使用熟練以後,就會發現真的得心應手,所以咱們就先看看元件是如何通訊的。
首先大家還記得咱們定義的頁尾元件麼,就是剛剛說到的。咱們看到最下邊是備案號,現在想在備案號旁邊加上咱的暱稱”老張的哲學“,想想很簡單嘛,想想肯定不能直接寫死資料吧,正好看到頁面內定義vue例項的時候,有這個屬性嘛,直接放到咱們的頁尾元件裡,嗯就是這樣:
// 定義一個名為 footer-vue 的新元件 Vue.component('footer-vue', { template: ` <div id="footer-vue"> <p>2018 <a href="#">LZ's Blog</a> - Hosted by <a href="#" style="font-weight: bold">Coding Pages</a></p> <p> <a href="#">京ICP備00000000號{{authorHtml}}</a> </p> </div> `, data () { return { message: 'hello world' } } })
然後滿懷開心的重新整理頁面一看,額報錯了:

然後很熟練的必應翻譯了一下(這是一個反面教材,大家要好好學習英文,多看國外教程 [苦笑] ),得到這樣的:屬性或方法 "authorHtml " 不應該是在例項上定義的, 而是在呈現過程中引用的。通過初始化屬性, 確保此屬性在資料選項或基於類的元件中是被動的。說人話就是,這裡不能使用例項上定義的值,好吧,查閱資料發現,元件只能被動的接受父元件的傳引數,嗯於是乎我們這樣寫:
<footer-vue :foo="author"></footer-vue>//在自定義的元件上,新增一個動態屬性,然後屬性的值 author 是父元件的,這個時候父元件就是已經把值給發過去了
這個時候,我們就需要在子元件裡接受一下
// 定義一個名為 footer-vue 的新元件 Vue.component('footer-vue', { template: ` <div id="footer-vue"> <p>2018 <a href="#">LZ's Blog</a> - Hosted by <a href="#" style="font-weight: bold">Coding Pages</a></p> <p> <a href="#">京ICP備00000000號{{foo}}</a>//這裡根據自身的props的引數來賦值 </p> </div> `, props: ['foo'],//這裡根據元件的props屬性,來被動接受元件傳遞來的引數 data () { return { message: 'hello world' } } })
重新整理頁面,這時候就真正的成功了。
2、使用靜態Props傳值
這裡我們得到的結果和上邊的是一樣的,直接是一個字串結果,而不是一個變數屬性。
Vue.component('child', { // 宣告 props props: ['message'], // 就像 data 一樣,prop 也可以在模板中使用 // 同樣也可以在 vm 例項中通過 this.message 來使用 template: '<span>{{ message }}</span>' }) <child message="老張的哲學"></child>
3、注意大小寫的命名的寫法
注意:HTML 特性是不區分大小寫的。所以,當使用的不是字串模板時,camelCase (駝峰式命名) 的 prop 需要轉換為相對應的 kebab-case (短橫線分隔式命名),比如 如何上邊的foo 寫成了 fooPro ,那我們定義屬性的時候,就應該寫 foo-pro
<footer-vue :foo-pro="author"></footer-vue>
如果我們寫了 fooPro 這樣的寫法,掛載頁面的時候,就會警告,並且不會成功渲染
如果你使用字串模板,則沒有這些限制。(字串模板:指的是在元件選項裡用 template:"" 指定的模板,換句話說,寫在 js 中的 template:"" 中的就是字串模板。)
三、自定義事件 —— 子傳父
我們知道,父元件使用 prop 傳遞資料給子元件。但子元件怎麼跟父元件通訊呢?這個時候 Vue 的自定義事件系統就派得上用場了。
1、使用 v-on 繫結自定義事件
每個 Vue 例項都實現了事件介面,即:
- 使用 $on(eventName) 監聽事件
- 使用 $emit(eventName) 觸發事件
Vue 的事件系統與瀏覽器的 EventTarget API
有所不同。儘管它們的執行起來類似,但是 $on
和 $emit
並不是 addEventListener
和 dispatchEvent
的別名。
另外,父元件可以在使用子元件的地方直接用 v-on
來監聽子元件觸發的事件。
<div id="counter-event-example"> <p>{{ total }}</p> <button-counter v-on:increment="incrementTotal"></button-counter> <button-counter v-on:increment="incrementTotal"></button-counter> </div> Vue.component('button-counter', { template: '<button v-on:click="incrementCounter">{{ counter }}</button>', data: function () { return { counter: 0 } }, methods: { incrementCounter: function () { this.counter += 1 this.$emit('increment') } }, }) new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal: function () { this.total += 1 } } })
2、使用自定義事件的表單輸入元件
自定義事件可以用來建立自定義的表單輸入元件,使用 v-model 來進行資料雙向繫結。要牢記:
<input v-model="something">
這不過是以下示例的語法糖:
<input v-bind:value="something" v-on:input="something = $event.target.value">
所以在元件中使用時,它相當於下面的簡寫:
<custom-input v-bind:value="something" v-on:input="something = arguments[0]"> </custom-input>
<div id="app"> <custom-input v-model="something"></custom-input> <br/> {{something}} </div> // 註冊 Vue.component('custom-input', { props:['something'], template: '<input type="text"v-bind:value="something" v-on:input="updateValue($event.target.value)"/>', methods:{ updateValue:function(value){ this.$emit('input', value) } } }) var vm = new Vue({ el: '#app', data: { something:'' } })
四、使用插槽slot分發內容(完善中)
在使用元件時,我們常常要像這樣組合它們:
<app> <app-header></app-header> <app-footer></app-footer> </app>
注意兩點:
-
<app>
元件不知道它會收到什麼內容。這是由使用<app>
的父元件決定的。 -
<app>
元件很可能有它自己的模板。
為了讓元件可以組合,我們需要一種方式來混合父元件的內容與子元件自己的模板。使用特殊的 <slot>
元素作為原始內容的插槽。
一個常見錯誤是試圖在父元件模板內將一個指令繫結到子元件的屬性/方法:
<!-- 無效 --> <child-component v-show="someChildProperty"></child-component>
正確做法:
Vue.component('child-component', { // 有效,因為是在正確的作用域內 template: '<div v-show="someChildProperty">Child</div>', data: function () { return { someChildProperty: true } } })
單個插槽
假定 my-component 元件有如下模板:
<div> <h2>我是子元件的標題</h2> <slot> 只有在沒有要分發的內容時才會顯示。 </slot> </div>
父元件模板:
<div> <h1>我是父元件的標題</h1> <my-component> <p>這是一些初始內容</p> <p>這是更多的初始內容</p> </my-component> </div>
渲染結果:
<div> <h1>我是父元件的標題</h1> <div> <h2>我是子元件的標題</h2> <p>這是一些初始內容</p> <p>這是更多的初始內容</p> </div> </div>
五、結語
今天簡單的說了下關於元件的一些問題,因為事件的問題,還沒有說完,還在進一步整理當中,大家可以以後進一步的瀏覽本博文,通過元件的學習,大家在Vue開發的道路上又進了一步,好啦,關於Vue的基礎知識就是這麼多了,明天開始進入程式碼練習啦~~