文章涉及的內容可能不全面,但量不少,須要慢慢看。我花了很長的時間整理,用心分享心得,但願對你們有所幫助。可是不免會有打字的錯誤或理解的錯誤點,但願發現的能夠郵箱告訴我1163675970@qq.com,我會及時的進行修改,只但願對你有所幫助,謝謝。javascript
咱們能夠很直觀的將一個複雜的頁面分割成若干個獨立組件html
每一個組件包含本身的邏輯和樣式再將這些獨立組件組合完成一個複雜的頁面。vue
將頁面中重複的的功能抽離出來封裝成一個單獨的組件,在任何須要的地方使用該組件便可;java
這樣既減小了 邏輯複雜度 , 提升代碼的可複用程度和可維護性;node
頁面是組件的容器,組件自由組合造成完整的界面,當不須要某個組件時,或者想要替換某個組件時,能夠隨時進 行替換和刪除,而不影響整個應用的運行。數組
每一個組件都是一個 Vue 的實例,那麼這個組件也有本身的生命週期,而且也有 data、computed、methods、watch這些屬性,每一個組件都有本身私有的數據;還能夠接受來自上層組件傳入的數據;瀏覽器
全局組件:無需單獨引用或者配置,直接在大組件中調取全局組件便可bash
能夠聲明一次在任何地方使用app
通常在寫插件時全局組件使用的多一些ide
vue.filters 它也是放到全局中,不用聲明直接用
全局組件是聲明在 vue類 上的
<!-- IMPORT CSS-->
<body> <div id="app"> <h3 v-text="title"></h3> <my-handlesome></my-handlesome> <!-- 我但願 my-handlesome 實現效果和下面的div實現一樣的效果 <div> 我很帥氣!!!</div> --> </div> <!-- IMPORT JS--> <script src="./20191007/node_modules/vue/dist/vue.js"></script> <script> /* * 全局組件:無需單獨引用或者配置,直接在大組件中調取全局組件便可 * Vue.component(componentName,options) * + options可使用的有VM實例具有的大部分(DATA、METHODS、生命週期函數...) * + 每調用一次組件都是建立一個單獨的VUE實例(VueComponent -> Vue) * * 組件命名的規範: * 1.組件名不要帶有大寫 多個單詞用 — 中劃線分隔 kebab-case * 2.只要組件名和定義名字相同是能夠的 (只有首字母能夠大寫) PasalCase * 3.html採用短橫線隔開命名法js中轉駝峯也是能夠的 * */ Vue.component('my-handlesome',{ //=> 一個對象能夠成一個組件 /* 至關於用 template 中的 div 標籤替換 咱們自定義的 my-handlesome 標籤*/ template:'<div>{{msg}}</div>', //=> 組件是中data數據必須是一個函數 ,返回一個實例(對象)做爲組件的數據 data(){ return{ msg:'我很帥氣!!!' } } }); let vm = new Vue({ el:'#app', data:{ title:"你自認爲本身顏值???" } }); </script> </body> 複製代碼
局部組件 :1- 建立 2- 註冊 3- 引用
必須告訴這個組建屬於誰
局部組件是聲明在 實例 vm 上的
組件是相互獨立的 不能直接跨做用域 實例(vm)也是一個組件, 組件中擁有生命週期函數
<!-- IMPORT CSS-->
<body> <div id="app"> <h3 v-text="title"></h3> <handelesome1></handelesome1> <handelesome2></handelesome2> </div> <!-- IMPORT JS--> <script src="./20191007/node_modules/vue/dist/vue.js"></script> <script> /* * 局部組件-使用三部曲: * 1. 建立組件 * 2. 註冊組件 * 3. 引用組件 * 組件是相互獨立的 不能直接跨做用域 實例(vm)也是一個組件, 組件中擁有生命週期函數 * * */ let obj ={ face:'醜到爆' }; //=> 若是組件共用了數據,會致使數據同時更新 (=錯誤寫法=) (可是組件 特色 獨立性) /* 子組件不能直接使用父組件的數據 (組件之間的數據交互) 組件理論上能夠無限嵌套 */ //=> 1. 建立這個組件 let handelesome1 ={ template:`<div @click="fn">1.帥氣 {{face}} {{a}}</div>`, /* face='顏值爆表' === @click="fn"*/ data(){ //=> 這裏的data 必須是一個函數 return obj }, methods:{ fn(){ //=> this 爲當前的組件 this.face = '顏值爆表' } } } ; let handelesome2 ={ template:'<div>2.霸氣 {{face}}{{a}}</div>', data(){ return obj } } ; let vm = new Vue({ el:'#app', data:{ //=> 只有這裏的data是 對象 title:"你自認爲本身顏值???", //=> 這裏的a 屬性 在 局部組件中調用引起報錯 //=> a:1 }, components:{ //=> 2. 註冊這個組件 ES6名字同樣寫一個 handelesome1, handelesome2 } }); </script> </body>
複製代碼
<body>
<div id="app">
</div>
<!-- IMPORT JS-->
<script src="./20191007/node_modules/vue/dist/vue.js"></script>
<script>
/*
最終頁面渲染效果
parent
son
grandson
*/
//=> 首先建立三個 組件 順序顛倒過來 父親 兒子 孫子 、
/*
* 若是要在一個組件使用另外一個組件,
* 1.先保證使用的組件得是真實存在,
* 2.在須要引用這個組件的實例上經過components註冊這個組件,
* 3.組件須要在父級的模板中經過標籤的形式引入
* */
//=> 孫子
let grandson = { template:'<div>grandson</div>'};
//=> 兒子
let son = { template:'<div>son <grandson></grandson></div>',
components:{
grandson
}
};
//=> 父親
let parent = {
template:'<div>parent <son></son></div>',
components: {
son
}
};
let vm = new Vue({
el:'#app',
//=> 在此處註冊組件
template:"<parent></parent>",
components:{
parent
},
data:{
}
});
</script>
</body>
複製代碼
<body>
<div id="app">
<!--父親基於鬍子語法取本身的 money 屬性 -->
父親:{{money}}
<!--
當前組件的屬性 = 父級的值
給兒子加了一個m屬性,屬性對應的數據是屬於父親的 傳遞給兒子,能夠傳遞多個
-->
<child :m="money"></child> <!--若是想傳的是一個數字就加 : 否則是字符串-->
<!--<child> </child> //=>這樣纔是沒有傳 而不是 :m="" -->
</div>
<!-- IMPORT JS-->
<script src="./20191007/node_modules/vue/dist/vue.js"></script>
<script>
<!--vm 組件也是根實例-->
//=> 父傳遞子 屬性傳遞
let vm = new Vue({ //=> parent
el:'#app',
data:{
money:400
},
components:{
child:{
/*
template:'<div>兒子 {{money}}</div>'
兒子 組件取 父親的 money 屬性
屬性沒有拿到還引起了報錯
由於 兩個組件間做用域是獨立的
*/
props:{ //=> 對象的形式能夠對傳的值進行檢驗 ,校驗時不能阻斷代碼執行,只是阻斷而已
m:{ //=> 校驗屬性的類型 不帶 : 號獲得的是字符串money :m='1' :m='true'
type:[String,Function,Boolean,Array,Number],
/* default:0, //=> 能夠給m設置默認值,若是不傳默認調用 default*/
required: true, //=> 此屬性是必須傳遞,可是不能和default同時使用
validator(val){ //=> val===money第一個參數是當前傳遞的值,返回true表示經過 false 反之
return val>300//=> 自定義校驗器
}
}
},
//=> 基於 props:[]屬性 兒子這裏要接受一下父親的’money‘
/* props:['m'],
//=> this.m = 100;會在當前 子組件實例上 聲明一個 m的屬性,存的父親傳過來的money
也和data同樣會影響視圖渲染嗎,可是子組件不能基於this.xxx來直接修改屬性
*/
template:'<div>兒子:{{m}}</div>'
}
}
});
</script>
</body>
複製代碼
訂閱發佈模式定義了一種一對多的依賴關係,讓多個訂閱者對象同時監聽某一個主題對象
全部的 prop 都使得其父子 prop 之間造成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,可是反過來則不行。
加載渲染過程:父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
子組件更新過程:父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
父組件更新過程:父 beforeUpdate -> 父 updated
銷燬過程:父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
每次父級組件發生更新時,子組件中全部的 prop 都將會刷新爲最新的值。這意味着你不該該在一個子組件內部改變 prop。若是你這樣作了,Vue 會在瀏覽器的控制檯中發出警告。子組件想修改時,只能經過 $emit 派發一個自定義事件,父組件接收到後,由父組件修改。
<!DOCTYPE html>
<html> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <son :msg="pmsg"></son> </div> <script src="vue.js"></script> <script> let son = { data() { return { hello: 'xxxx' } }, props: ['msg', 'changePMSG'], template: '<span>{{msg}} <button @click="fn">dddd</button></span>', methods: { fn() { this.msg = 1233; // props 中的數據也會代理到子組件的實例身上,能夠直接經過 this 訪問 } } }; let vm = new Vue({ el: '#app', data: { pmsg: 'msg from parent' }, methods: { changeMsg() { this.pmsg = 123445 } }, components: { son } }); // 1. 子組件中的數據不能全是寫死的,而是有一部分從父組件傳遞過來的 // 2. 爲了把父組件的數據傳遞給子組件,子組件在標籤上動態綁定一個屬性,這個屬性綁定父組件的數據,而且在子組件的props中註冊這個屬性 // 3. 子組件若是想使用父組件的數據,就使用對應的 props 就能夠(父傳子用props) // 單向數據流:數據只能經過父組件傳遞給子組件,而不能直接從子組件傳給父組件,子組件也不能直接修改父組件的數據;當父組件的數據發生改變以後,子組件的收到的數據也會跟着變化;如上面的例子,直接修改從父組件中的數據會引起Vue的報錯; // 若是子組件想修改父組件的數據,只能通知父組件,讓父組件修改數據; </script> </body> </html> 複製代碼
<body>
<div id="app"> 父親:{{money}} <!-- 兒子裏面綁定了一個事件 child.$on('child-msg', things) 綁定的事叫作 child-msg ,事情主體是父親的 things 此時咱們已經在兒子上綁定了一個child-msg ,當咱們點擊的時候讓child-msg觸發,觸發時能夠傳參, --> <child :m="money" @child-msg="things"></child> </div>
<!--
父親綁定一些事件,兒子觸發這個事件將參數傳遞過去 ,
單項數據流, 父親數據刷新,兒子就刷新
-->
<!-- IMPORT JS--> <script src="./20191007/node_modules/vue/dist/vue.js"></script> <script> //=> let vm = new Vue({ //=> parent el:'#app', data:{ money:400 }, methods:{ //=> 兒子要觸發這個事件,而且傳一個參數 , 將這次事件綁定給 things(val){ //=> 至關於 $on('xxx',things) //=>兒子通知父親多給點錢 當父親接收到過來的800 更新本身的價格 //=> this爲父親 this.money=val; } }, components:{ child:{ props:['m'], template:'<div>兒子:{{m}} <button @click="getMoney()">多要錢</button></div>', methods: { getMoney(){ /* this爲當前的 child 當點擊兒子組件時觸發的事件child-msg , 當child-msg事件觸發的時候,會觸發 things 而且將參數 800 傳給 父親的things 的 val */ this.$emit('child-msg',800);//=> 觸發本身的自定義事件,讓父親的方法執行 ,方法是父親的,屬性永遠是當前組件的 } } } } }); </script> </body>
複製代碼
每一個組件都是一個 Vue 的實例,相互之間不能互通數據;
要修改數據必定要通知,因此找一個第三方,讓第三方監聽事件,在事件觸發時執行對應的修改數據的操做,這個第三方就是事件總線;
建立一個空的 Vue 實例;let eventBus = new Vue();
eventBus.$on(自定義事件名, 事件函數) 監聽事件
eventBus.$emit(事件名) 觸發事件
<!DOCTYPE html>
<html> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <prev></prev> <next></next> </div> <script src="vue.js"></script> <script> // 每一個組件都是一個 Vue的實例,相互之間不能互通數據; // 要修改數據必定要通知,因此找一個第三方,讓第三方監聽事件,在事件觸發時執行對應的修改數據的操做; // eventBus.$on(自定義事件名, 事件函數) 監聽事件 // eventBus.$emit(事件名) 觸發事件 let eventBus = new Vue(); // 這第三方就是一個空的 Vue 實例,叫作事件總線 EventBus let prev = { data() { return { color: 'green' } }, created() { eventBus.$on('changeRed', this.toRed) // 監聽 changeRed 事件,當事件觸發時,會執行 this.toRed 方法 }, methods: { toRed(x) { console.log(x); x 是事件觸發時,傳遞的數據 this.color = 'red'; } }, template: `<div :style="{background: color}">{{color}}</div>` }; let next = { data () { return { color: '紅色' } }, methods: { red() { eventBus.$emit('changeRed', 'hahaha') } }, template: `<div><button @click="red">變紅</button></div>` }; let vm = new Vue({ el: '#app', data: {}, components: { prev, next } }); // 兄弟組件之間通訊,經過 EventBus,誰的數據須要被改變,誰監聽事件,誰發起改變誰觸發事件;例如本例中,next 要修改 prev 的數據,因此在 prev 的 created 中 eventBus.$on() 監聽事件,而 next 發起改變,因此在 next 中 $emit() 事件; // 哥哥改弟弟同理; </script> </body> </html> 複製代碼
當引用組件時,咱們能夠向組件的標籤中嵌入內容。這些內容能夠嵌入到子組件中,可是須要使用插槽機制即,slot;
首先在建立子組件時須要聲明一個 slot 標籤佔位;
在組件標籤中嵌入內容
匿名 slot,在聲明 slot 時不寫 name 屬性,嵌入在組件標籤中沒有寫 slot 屬性的標籤都會放在匿名 slot 中
具名 slot,在聲明 slot 時要寫上 name 屬性;嵌入在組件標籤中的內容須要指定 slot=「slot的名字」
<!DOCTYPE html>
<html> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <panel> <div>這是默認的內容</div> <p>hahahah </p> <div slot="header">這是個頭</div> <div slot="body">主體</div> <div slot="footer">尾部</div> </panel> </div> <template id="tpl"> <div> <slot></slot> <slot name="header"></slot> <slot name="body"></slot> <slot name="footer"></slot> </div> </template> <script src="vue.js"></script> <script> let panel = { template: '#tpl', data() { return { x: 1 } } }; let vm = new Vue({ el: '#app', data: {}, components: { panel } }); // 若是要想子組件中嵌入內容,須要使用插槽 slot;而且須要在子組件中提早用 slot 標籤佔位; // slot 分爲匿名 slot 和具名 slot </script> </body> </html> 複製代碼
{
provide:{ //=>對象或者返回對象的函數均可以(屬性值若是是data中的數據,則必須使用函數的方法進行處理)
name:'zhufeng',
year:10
},
...
}
複製代碼
{
inject:['name'],
methods:{
func(){
let name=this.name;
}
}
}
複製代碼