一、元件
1.props屬性
1)props屬性
元件可以嵌套使用,叫做父子元件。
那麼父元件經常要給子元件傳遞資料這叫做父子元件通信。
父子元件的關系可以總結為 props 向下傳遞,事件向上傳遞。
父元件通過 props 給子元件下發資料,子元件通過事件給父元件發送消息。
<div id="app"> <!-- 使用子元件 --> <!-- 通過綁定屬性,将父元件的資料設定到子元件标簽中 --> <!-- msg2 代表的是一個自定義屬性名,可任意 msg 代表的是父元件中data屬性中的msg資料 --> <child :msg2="msg" :b="greetTxt"></child> </div> </body> <script type="text/javascript"> /* 定義子元件 */ Vue.component('child',{ /* 子元件中想用父元件傳遞的資料,需要通過props屬性聲明 */ props:["msg2",'b'], template:"<h3>Hello -- {{msg2}} --- {{b}}</h3>" }); /* 父元件 */ new Vue({ el:"#app", data:{ msg:"來自父元件的消息", greetTxt:"你好啊~Child" } });
2)props校驗
子元件在接收父元件傳入資料時, 可以進行props校驗,來確定資料的格式和是否必傳。可以指定一下屬性:
1) type: 指定資料類型 String Number Object …注意不能使用字元串數組,隻能是對象大寫形式
2) required: 指定是否必輸
3) default: 給預設值或者自定義函數傳回預設值
4) validator: 自定義函數校驗
兩種形式:
數組(不支援資料校驗)
props:[‘參數1’,‘參數2’…]
對象(支援資料校驗)
props:{
參數1:
參數2:
}
<div id="app"> <child :a="msg" :b="greetTxt" :d="num" ></child> </div> </body> <script type="text/javascript"> /* 定義子元件 */ Vue.component('child',{ /* props校驗 */ props:{ // 要求資料是數值型 // a:String, // 可以是數值型 和 字元串類型 b:[Number, String], // 必須設定屬性 /* c:{ required:true }, */ // 設定預設值;如果資料未被傳遞,則顯示預設結果 c:{ type:Number, default:100 }, // 數組/對象的預設值應當由一個工廠函數傳回 e:{ default:function(){ return 1; } }, // 自定義驗證函數 d:{ validator:function(value){ return value > 1; } }, // 自定義驗證函數 a:{ validator:function(value){ return value.length > 10; } } }, template:"<h3>Hello -- {{a}} -- {{b}} -- {{c}} -- {{e}} -- {{d}}</h3>" }); /* 父元件 */ new Vue({ el:"#app", data:{ msg:"來自父元件的消息", greetTxt:"你好啊~Child", num:10 } }); </script>
2.非props屬性
引用子元件時,非定義的props屬性,自動合并到子元件上**,class和style也會自動合并。**<div id="app"> <child style="font-size: 20px;" class="active" ></child> </div> </body> <script type="text/javascript"> /* 定義子元件 */ Vue.component('child',{ template:"<div style='color:red' class='bg'>Hello</div>" }); /* 父元件 */ new Vue({ el:"#app", }); </script>
3.自定義事件
自定義事件
父元件給子元件傳值使用props屬性, 那麼需要子元件更新父元件時,要使用自定義事件 o n 和 on和 on和emit:
o n 監 聽 : ∗ ∗ 不 能 監 聽 駝 峰 标 示 的 自 定 義 事 件 , 使 用 全 部 小 寫 ( a b c ) 或 者 − ( a − b − c ) ∗ ∗ on監聽:** 不能監聽駝峰标示的自定義事件, 使用全部小寫(abc)或者-(a-b-c) ** on監聽:∗∗不能監聽駝峰标示的自定義事件,使用全部小寫(abc)或者−(a−b−c)∗∗emit主動觸發: $emit(事件名,傳入參數)
實作步驟:
1.定義父元件
定義父元件中的資料和方法
2.定義子元件
定義子元件的模闆和方法
3.在使用子元件的标簽時,綁定自定義事件
<child @update-count=“changeCount” >
說明:
update-count 代表的是 自定義事件
changeCount 代表的是自定義事件被觸發時,調用的函數
4.在子元件的方法中,手動觸發自定義事件
$emit(事件名,傳遞的參數);
主動挂載
自定義事件不僅可以綁定在子元件,也可以直接挂載到父元件,使用 o n 綁 定 和 on綁定和 on綁定和emit觸發。
<div id="app"> 數量:{{count}} <hr > <child @update-count="changeCount" ></child> </div> <hr > <div id="root"> 數量:{{count}} </div> </body> <script type="text/javascript"> /* 定義子元件 */ Vue.component('child',{ template:"<button @click='update'>子元件Child</button>", methods:{ update:function(){ console.log("子元件的方法..."); // 觸發自定義事件 this.$emit("update-count","Hello"); } } }); /* 父元件 */ new Vue({ el:"#app", data:{ count:0 }, methods:{ changeCount:function(a){ console.log("父元件的方法..."); console.log("子元件中傳遞的資料:" + a); // 更新data屬性中的資料 this.count++; } } }); var root = new Vue({ el:"#root", data:{ count:0 } }); // 主動挂載 root.$on("update-count",function(){ console.log("主動挂載..."); // 更新父元件的資料 this.count++; }); // 手動觸發 root.$emit("update-count","HAHAH"); </script>
二、插槽分發
1.slot插槽
父子元件使用時,有時需要将父元素的模闆跟子元素模闆進行混合,這時就要用到slot插槽進行内容分發,簡單了解就是在子模闆中先占個位置等待父元件調用時進行模闆插入。
在子元件模闆中使用**标簽定義插槽位置**,标簽中可以填寫内容,當父元件不傳入内容時顯示此内容。
<div id="app"> <child> <h3>我是父元件</h3> <h3>我是父元件2</h3> </child> </div> <hr > <!-- 元件模闆 --> <template id="child-template"> <div> <slot><div>我是預設内容,父元件不傳入時我顯示</div></slot> <div>我是子元件</div> <div>Hello</div> <!-- 定義slot插槽進行占位 --> <!-- <slot>我是預設内容,父元件不傳入時我顯示</slot> --> <slot><div>我是預設内容,父元件不傳入時我顯示</div></slot> </div> </template> </body> <script type="text/javascript"> /* 定義子元件 */ Vue.component('child',{ template:"#child-template", }); /* 父元件 */ new Vue({ el:"#app", data:{ count:0 } }); </script>
2.具名插槽
具名插槽slot, 就是給插槽起個名字。
在子元件定時可以定定義多個插槽,同時通過name屬性指定一個名字
如:,父元件引用時使用< slot=‘header’>進行插槽選擇。
<div id="app"> <child> <h3 slot="zhangsan">我是張三</h3> <h3 slot="lisi">我是李四</h3> </child> </div> <hr > <!-- 元件模闆 --> <template id="child-template"> <div> <slot name="zhangsan"></slot> <div>我是子元件</div> <div>Hello</div> <slot name="lisi"></slot> </div> </template> </body> <script type="text/javascript"> /* 定義子元件 */ Vue.component('child',{ template:"#child-template", }); /* 父元件 */ new Vue({ el:"#app", data:{ count:0 } }); </script>
3.slot-scope
作用域插槽slot-scope,父元件通過插槽混入父元件的内容, 子元件也可以通過slot作用域向插槽slot内部傳入資料
使用方式:,父元件通過進行引用。
<div id="app"> <child> <!-- 使用template标簽将插槽對應的資料包裹起來,并設定slot-scope的屬性值,屬性值是一個變量名,自定義 --> <!-- <template slot-scope="props"> <h3 >我是張三 -- {{props.msg}}</h3> </template> --> <!-- 在2.5+之後,可以不局限于<template>, 任何元素都可以,同時可以使用解構指派的方式進行資料解析。 --> <!-- <h3 slot-scope="props">我是張三 -- {{props.msg}}</h3> --> <!-- 解構指派 --> <h3 slot-scope="{msg,txt}">我是張三 -- {{msg}}-- {{txt}}</h3> </child> </div> <hr > <!-- 元件模闆 --> <template id="child-template"> <div> <div>我是子元件</div> <div>Hello</div> <!-- 定義插槽時,傳遞資料 --> <slot msg="你好啊張三" txt="哈哈"></slot> </div> </template> </body> <script type="text/javascript"> /* 定義子元件 */ Vue.component('child',{ template:"#child-template", }); /* 父元件 */ new Vue({ el:"#app", data:{ count:0 } }); </script>
三、動态元件
1.動态元件
使用标簽的is屬性,動态綁定多個元件到一個挂載點**,通過改變is綁定值,切換元件。**實作步驟: 1. 定義父元件,設定data資料 2. 定義多個子元件 3. 定義導航(a标簽),并為導航綁定點選事件,修改data屬性中資料的值 4. 使用is屬性綁定父元件的資料 <component :is="page"></component> page 代表的是父元件中data屬性定義的資料 <div id="app"> / <a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" @click.prevent="page='index'">首頁</a> / <a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" @click.prevent="page='news'">新聞頁</a> / <a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" @click.prevent="page='login'">登入頁</a> <hr > <component :is="page"></component> </div> </body> <script type="text/javascript"> Vue.component('index', { template:'<h5>首頁</h5>' }); Vue.component('news', { template:'<h5>新聞頁</h5>' }); Vue.component('login', { template:'<h5>登陸頁</h5>' }); /* 父元件 */ new Vue({ el:"#app", data:{ page:"login" } }); </script>
2.keep-alive
如果把切換出去的元件保留在記憶體中,可以保留它的狀态或避免重新渲染。為此可以添加一個 keep-alive 指令。
用生命周期中的mounted(挂載)鈎子函數進行元件渲染監聽,當元件第一次被渲染後就儲存在記憶體中,下次切換不會被重新渲染。
<div id="app"> / <a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" @click.prevent="page='index'">首頁</a> / <a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" @click.prevent="page='news'">新聞頁</a> / <a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" @click.prevent="page='login'">登入頁</a> <hr > <!-- 把切換出去的元件保留在記憶體中 --> <keep-alive> <component :is="page"></component> </keep-alive> </div> </body> <script type="text/javascript"> Vue.component('index', { template:'<h5>首頁</h5>', mounted: function () { console.log('挂載...首頁'); } }); Vue.component('news', { template:'<h5>新聞頁</h5>', mounted: function () { console.log('挂載...新聞頁'); } }); Vue.component('login', { template:'<h5>登陸頁</h5>', mounted: function () { console.log('挂載...登入頁'); } }); /* 父元件 */ new Vue({ el:"#app", data:{ page:"login" } }); </script>
3.refs屬性
使用ref 給每個元件起一個固定的名字,友善後續直接引用操作,在父元件中使用$refs通路子元件。<div id="app"> <child ref="ref1"></child> <hr> <child ref="ref2"></child> </div> </body> <script type="text/javascript"> Vue.component('child', { template:'<button @click="count++">{{count}}</button>', data:function(){ return {count:0}; } }); /* 父元件 */ var app = new Vue({ el:"#app", }); </script>
四、資料處理
1.watch屬性
在Vue元件中,使用watch屬性來監聽資料的變化,同時可以指定監聽那個屬性。
watch:{**
監聽的資料:function(newValue,oldValue){
}
}**
<div id="app"> {{uname}} -- {{upwd}} <hr > <p> firstName: <input type="text" v-model="firstName"> </p> <p> lastName: <input type="text" :value="lastName" @input="changeLastName"> </p> <h4>{{fullName}}</h4> </div> </body> <script type="text/javascript"> var app = new Vue({ el:"#app", data:{ uname:"zhangsan", upwd:"123456", firstName:"Hello", lastName:"Kitty", fullName:"Hello Kitty" }, // watch屬性 監聽資料變化,可以得知資料變化前的值與變化後的結果 watch:{ uname:function(v1,v2){ console.log(v1+","+v2); }, upwd:function(newValue,oldValue){ console.log("改變後的值:" + newValue + ",改變後的值:" + oldValue); }, // 監聽值的變化 firstName:function(newValue,oldVlue){ this.fullName = newValue + " " + this.lastName; }, lastName:function(newValue,oldVlue){ this.fullName = this.firstName + " " + newValue; } }, methods:{ changeLastName:function(e){ // 給數指派 this.lastName = e.target.value } } }); </script>
2.$watch
除了在元件内部使用watch也可以使用内部指令 w a t c h ∗ ∗ 進 行 屬 性 監 聽 。 ∗ ∗ watch**進行屬性監聽。 ** watch∗∗進行屬性監聽。∗∗watch第一個參數是需要監聽的屬性,第二個是回調函數用法和watch一樣。
需要取消監聽隻需拿到監聽對象的引用,這個引用是傳回一個函數對象,執行該對象就可以取消監聽。
同時監聽多個屬性,可以不指定屬性
<div id="app"> {{uname}} </div> </body> <script type="text/javascript"> var app = new Vue({ el:"#app", data:{ uname:"zhangsan", upwd:'123' }, }); // 使用$watch監聽指定資料 /* var unwacth = app.$watch("uname",function(v1,v2){ console.log(v1+","+v2) }); */ // 取消監聽 (傳回一個函數對象,執行該對象就可以取消監聽) // unwacth(); // 監聽所有資料 app.$watch(function(){ return this.uname +"-" + this.upwd; },function(newValue, oldValue) { console.log('newValue:【'+newValue+'】 oldValue:【'+oldValue+'】'); }); </script>
3.computed屬性
computed計算屬性用于定義比較複雜的屬性計算
注:如果是computed屬性計算得到的結果,使用時不需要加括号,與定義在data中的屬性使用方法一緻
computed和methods差別:
計算屬性使用computed定義, 方法使用methods定義
計算屬性使用時不加括号執行符
計算屬性是基于它們的依賴進行緩存的,計算屬性隻有在它的相關依賴發生改變時才會重新求值。否則傳回之前計算好的值,性能更高!
<div id="app"> <p> firstName: <input type="text" v-model="firstName"> </p> <p> lastName: <input type="text" v-model="lastName"> </p> <!-- 如果是computed屬性計算得到的結果,使用時不需要加括号,與定義在data中的屬性使用方法一緻 --> <h4>{{fullName2}}</h4> <!-- 如果是methods中定義的方法,使用時需要添加括号調用該方法 --> <h4>{{fullName()}}</h4> </div> </body> <script type="text/javascript"> var app = new Vue({ el:"#app", data:{ firstName:"Hello", lastName:"Kitty" }, // 計算資料 computed:{ fullName2:function(){ return this.firstName + " " + this.lastName; } }, methods:{ fullName:function(){ return this.firstName + " " + this.lastName; } } }); </script>
4.getter和setter
<div id="app"> <p> fullName: <input type="text" v-model="fullName" /> </p> <h4>firstName: {{firstName}}</h4> <h4>lastName: {{lastName}}</h4> </div> </body> <script type="text/javascript"> var app = new Vue({ el:"#app", data:{ firstName:"Hello", lastName:"Kitty" }, // 計算資料 computed:{ fullName:{ // get 取值 get:function(){ return this.firstName + " " + this.lastName; }, // set 指派 set:function(value){ console.log(value); var news = value.split(" "); this.firstName = news[0]; this.lastName = news[1]; } } } }); </script>
五、生命周期
1.生命周期
常用的生命周期鈎子函數有:
1) created: 執行個體建立完成後被立即調用
2) mounted: 執行個體挂載完成後被立即調用
3) beforeUpdate: 執行個體需要渲染之前調用
4) updated: 執行個體更新後調用
5) destroyed: Vue 執行個體銷毀後調用
<div id="app"> {{uname}} </div> </body> <script type="text/javascript"> var app = new Vue({ el:"#app", data:{ uname:"admin" }, created: function () { console.log('執行個體建立...'); }, mounted:function () { console.log('執行個體挂載...'); }, beforeUpdate:function () { console.log('執行個體将要更新...'); }, updated:function () { console.log('執行個體已更新...'); }, destroyed:function(){ console.log('執行個體解除安裝...'); } }); // 銷毀執行個體 // app.$destroy(); </script>
2.鈎子函數
- el: 指令所綁定的元素,可以用來直接操作 DOM 。
- binding: 一個對象,包含以下屬性:
- name: 指令名,不包括
字首。
v-
- value: 指令的綁定值, 例如:
, value 的值是
v-my-directive="1 + 1"
。
2
- oldValue: 指令綁定的前一個值,僅在
和
update
鈎子中可用。無論值是否改變都可用。
componentUpdated
- expression: 綁定值的表達式或變量名。 例如
, expression 的值是
v-my-directive="1 + 1"
。
"1 + 1"
- arg: 傳給指令的參數。例如
, arg 的值是
v-my-directive:foo
。
"foo"
- modifiers: 一個包含修飾符的對象。 例如:
, 修飾符對象 modifiers 的值是
v-my-directive.foo.bar
。
{ foo: true, bar: true }
- vnode: Vue 編譯生成的虛拟節點。
- oldVnode: 上一個虛拟節點,僅在
和
update
鈎子中可用。
componentUpdated
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Vue</title> <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script> </head> <body> <div id="app" v-runoob:hello.a.b="message"> </div> <script> Vue.directive('runoob', { bind: function (el, binding, vnode) { var s = JSON.stringify el.innerHTML = 'name: ' + s(binding.name) + '<br>' + 'value: ' + s(binding.value) + '<br>' + 'expression: ' + s(binding.expression) + '<br>' + 'argument: ' + s(binding.arg) + '<br>' + 'modifiers: ' + s(binding.modifiers) + '<br>' + 'vnode keys: ' + Object.keys(vnode).join(', ') } }) new Vue({ el: '#app', data: { message: '哈士奇' } }) </script> </body> </html>
六、自定義指令
1.自定義指令
除了預設設定的核心指令 (v-model 和 v-show),Vue 也允許注冊自定義指令。
兩種定義方式:全局指令和局部指令
1.定義指令
全局指令
Vue.directive(“指令名”,{
//inserted 鈎子函數,當綁定元素插入到DOM調用
inserted:function(el){
// el 代表的是目前綁定指令的元素對象
}
});
局部指定
注:使用directive定義,第一個參數為指令名,使用時加上v-字首才能生效。inserted屬性指當綁定元素插入到DOM時調用。
使用指令
v-指令名
<div id="app"> <input type="text" v-focus v-aa > <input type="text" v-demo:ab.a.b="1+1"> </div> </body> <script type="text/javascript"> /* 定義全局指令 */ Vue.directive("focus",{ //當綁定元素插入到DOM調用 inserted:function(el){ // el 代表的是目前綁定指令的元素對象 el.focus(); // 聚焦 } }); Vue.directive('demo',{ bind: function (el,binding) { console.log(el); console.log(binding); } }); var app = new Vue({ el:"#app", data:{ uname:"admin" }, /* 局部指令 */ directives:{ aa:function(el){ console.log(el); el.value="Hello" } } }); // 銷毀執行個體 // app.$destroy(); </script>
2.實作圖檔懶加載
谷歌圖檔的加載做得非常優雅,在圖檔未完成加載前,用随機的背景色占位,圖檔加載完成後才直接渲染出來,用自定義指令可以非常友善的實作這個功能。<div id="app"> <div class="item" v-for="item in imgs" v-img="item.url"></div> </div> </body> <script type="text/javascript"> /* 定義全局自定義指令v-img */ Vue.directive("img",{ bind:function(el,binding){ console.log(el); console.log(binding); //生成随機顔色 var color=parseInt(Math.random()*0xFFFFFF).toString(16); //設定目前元素的背景,提前進行占位等待圖檔加載 el.style.background="#"+color; //setTimeout模拟圖檔加載的延時情況 setTimeout(function() { //得到圖檔的路徑 var url=binding.value; //得到圖檔對象 var img=new Image(); //設定img對象的人src屬性 img.src=url; //将img對象設定到div(el對象)中 el.appendChild(img); },Math.random()*100+500);//随機延時 } }); var app=new Vue({ el:"#app", data:{ //定義模拟資料 imgs:[ {url:'img/1.jpg'}, {url:'img/2.jpg'}, {url:'img/3.jpg'}, {url:'img/4.jpg'} ] } }); </script>
3.過濾器
Vue允許自定義過濾器,可被用作一些常見的文本格式化。
過濾器可以用在兩個地方:mustache 插值和 v-bind 表達式 (後者從 2.1.0+ 開始支援)。
過濾器應該被添加在 JavaScript 表達式的尾部,由“管道”符訓示:
{{資料 | 過濾器}}
多個過濾器可以串聯
{{資料 | 過濾器 | 過濾器2}}
定義過濾器
全局過濾器
Vue.filter(“uppercase”,function(value){
return value.toUpperCase();
});
局部過濾器
filters:{
length:function(value){
return value.length;
}
}
<div id="app"> <!-- 使用過濾器 --> {{msg}} --{{msg | uppercase}}--{{msg | length}}<br> {{msg | uppercase | test}}<br> {{msg | test01("-->","<--")}} </div> </body> <script type="text/javascript"> /* 定義全局過濾器 */ Vue.filter("uppercase",function(value){ return value.toUpperCase(); }); var app=new Vue({ el:"#app", data:{ msg:"Hello" }, /* 定義局部過濾器 */ filters:{ length:function(value){ return value.length; }, test:function(value){ return value+":"+value.length; }, test01:function(value,begin,end){ return begin + value + end; } } }); </script>