最近在學(xué)習(xí)Vue花椭,下面是學(xué)習(xí)過(guò)程中總結(jié)了一些基本的知識(shí)點(diǎn)
Vue
一. 基本知識(shí)
1. 實(shí)例化
var app = new Vue({
el: '#app', //綁定到元素上
data: {
message:'hello world'
},
filters:{
filterName1:function(){},
filterName2:function(){}
},
methods:{
methodName1:function(){},
methodName2:function(){}
},
//生命周期鉤子
created:function(){
//未掛載到dom之前觸發(fā)
}油额,
mounted:function(){
//掛載到dom后觸發(fā)
}柬批,
beforeDestroy:function(){
}
})
2. 過(guò)濾器
{{ data中的變量名 | filter中的過(guò)濾器名 }}
3. 指令和事件
v-text:解析文本,和{{ }}作用一樣
v-html:解析html
v-bind:動(dòng)態(tài)更新HTML元素上的屬性
v-on:綁定事件監(jiān)聽(tīng)器
v-bind語(yǔ)法糖:冒號(hào) :
v-on語(yǔ)法糖:@
-
v-bind的作用细睡,以及v-bind的變量語(yǔ)法兼贸,數(shù)組語(yǔ)法,對(duì)象語(yǔ)法:
- v-bind通常用來(lái)綁定屬性的寓落,格式是v-bind:屬性名 = "值",簡(jiǎn)寫(xiě):屬性名 = "值"
- 變量語(yǔ)法:v-bind:class = "變量"荞下,變量形式 ,這里的變量的值伶选,通常是在css定義好的類名;
- 數(shù)組語(yǔ)法:v-bind:class= "[變量1锄弱,變量2]" 考蕾,數(shù)組形式,其實(shí)跟上面差不多会宪,只不過(guò)可以同時(shí)綁定多個(gè)class名;
- 對(duì)象語(yǔ)法:v-bind:class = {classname1:boolean蚯窥,classname2:boolean}掸鹅,對(duì)象形式,這里的classname1(2)其實(shí)就是樣式表中的類名拦赠,這里的boolean通常是一個(gè)變量巍沙,也可以是常量、計(jì)算屬性等荷鼠,這種方法也是綁定class最常用的方式句携。
4. VUE內(nèi)置指令
-
v-cloak : 解決頁(yè)面沒(méi)加載完的時(shí)候出現(xiàn)類似{{ msg }}等變量名的現(xiàn)象,一般和display:none一起使用
<style> [v-cloak]:{ display-none; } </style> ------------------------- <p v-cloak> {{ msg }} </p>
-
v-once:只在頁(yè)面中渲染一次允乐,改變變量的值也不會(huì)重新渲染
<p v-once> {{ msg }} </p>
-
條件指令:v-if
v-if : 后面接的是等號(hào)矮嫉,等號(hào)后面的內(nèi)容必須是布爾值,布爾值為true則渲染牍疏,否則不渲染
v-else
v-else-if
-
例:
<p v-if = '6>3'>{{ apple }}</p> <p v-else-if = '9<6'> {{ banana}} </p> <p v-else> {{ orange }} </p>
v-if的弊端:Vue在渲染元素時(shí)蠢笋,出于效率考慮,會(huì)盡可能的復(fù)用已有的元素而非重新渲染鳞陨,因
此會(huì)出現(xiàn)烏龍解決方法:加key昨寞,唯一,提供key值可以來(lái)決定是否復(fù)用該元素
-
v-show:只改變display屬性
-
v-if和v-show的區(qū)別:
v-if:實(shí)時(shí)渲染:頁(yè)面顯示就渲染厦滤,不顯示就移除
v-show:元素始終存在于頁(yè)面中援岩,只是改變了display屬性
-
-
v-for:
-
遍歷多個(gè)對(duì)象:data 里面是一個(gè)數(shù)組
<div id='app'> <ul> <!-- intm in items --> <li v-for="fruit in fruits">{{ fruit.name }}</li> </ul> <ul> <!-- 帶索引的寫(xiě)法 --> <li v-for="(fruit,index) in fruits">第{{ index }}個(gè) {{ fruit.name }}</li> </ul> </div> <script> var app = new Vue({ el: '#app', data: { //這里是一個(gè)數(shù)組 fruits: [ {name: 'apple'}, {name: 'banana'}, {name: 'orange'} ] } }) </script>
-
-
遍歷一個(gè)對(duì)象的多個(gè)屬性
<div id='app'> <span v-for='value in fruits'>{{ value }}</span> <!-- 帶v-k-i的寫(xiě)法:value key index (外開(kāi)) --> <p v-for="(value,key,index) in fruits2"> value:{{value}}<br> key:{{key}}<br> index:{{index}} </p> </div> <script> var app = new Vue({ el: '#app', data: { //這里是一個(gè)對(duì)象 fruits: { fruit1: 'apple', fruit2: 'banana', fruit3: 'orange' } } }) </script>
v-model表單
5. 計(jì)算屬性
-
基礎(chǔ)例子
<div id="example"> <p>Original message: "{{ message }}"</p> <p>Computed reversed message: "{{ reversedMessage }}"</p> </div> var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { // 計(jì)算屬性的 getter reversedMessage: function () { // `this` 指向 vm 實(shí)例 return this.message.split('').reverse().join('') } } })
-
計(jì)算屬性的 setter
計(jì)算屬性默認(rèn)只有 getter ,不過(guò)在需要時(shí)你也可以提供一個(gè) setter :
在賦值的時(shí)候會(huì)觸發(fā)set函數(shù)掏导,把新賦的值以參數(shù)的形式傳遞進(jìn)去
// ... computed: { fullName: { // getter get: function () { return this.firstName + ' ' + this.lastName }, // setter set: function (newValue) { var names = newValue.split(' ') this.firstName = names[0] this.lastName = names[names.length - 1] } } } // ...
現(xiàn)在再運(yùn)行
vm.fullName = 'John Doe'
時(shí)享怀,setter 會(huì)被調(diào)用,vm.firstName
和vm.lastName
也會(huì)相應(yīng)地被更新碘菜。
6. 數(shù)組更新凹蜈、過(guò)濾與排序
改變數(shù)組的一系列方法:
- push() 在末尾添加元素
- pop() 將數(shù)組的最后一個(gè)元素移除
- shift() 刪除數(shù)組的第一個(gè)元素
- unshift():在數(shù)組的第一個(gè)元素位置添加一個(gè)元素
- splice() :可以添加或者刪除函數(shù)—返回刪除的元素
三個(gè)參數(shù):- 第一個(gè)參數(shù) 表示開(kāi)始操作的位置
- 第二個(gè)參數(shù)表示:要操作的長(zhǎng)度
- 第三個(gè)為可選參數(shù):
? sort():排序
? reverse()
兩個(gè)數(shù)組變動(dòng)vue檢測(cè)不到:
- 改變數(shù)組的指定項(xiàng)
- 改變數(shù)組長(zhǎng)度
過(guò)濾:filter
解決方法:
改變指定項(xiàng): Vue.set(app.arr,1,”car”)?
app.arr.splice(1): 改變數(shù)組長(zhǎng)度
二. 組件
組件 (Component) 是 Vue.js 最強(qiáng)大的功能之一限寞。組件可以擴(kuò)展 HTML 元素,封裝可重用的代碼仰坦。在較高層面上履植,組件是自定義元素,Vue.js 的編譯器為它添加特殊功能悄晃。在有些情況下玫霎,組件也可以表現(xiàn)為用 is 特性進(jìn)行了擴(kuò)展的原生 HTML 元素。所有的 Vue 組件同時(shí)也都是 Vue 的實(shí)例妈橄,所以可接受相同的選項(xiàng)對(duì)象 (除了一些根級(jí)特有的選項(xiàng)) 并提供相同的生命周期鉤子落萎。
1. 組件用法
-
全局注冊(cè)
Vue.component('component-name',{ template: '<div>組件內(nèi)容</div>' }) //優(yōu)點(diǎn):所有Vue實(shí)例都可以使用 //缺點(diǎn):權(quán)限太大逮栅,容錯(cuò)率低
-
局部注冊(cè)
var app = new Vue({ el: '#app', data:{}, components: { 'component-name': { template: '<div>組件內(nèi)容</div>' } } })
-
注意事項(xiàng):
組件名用橫桿命名法,不能用駝峰命名法
template中的內(nèi)容必須被一個(gè)DOM元素包起來(lái)
在組件的定義中,除了template疚沐,還可以有data、methods侣滩、computed選項(xiàng)
-
data必須是一個(gè)方法
data: function(){ return { message: 'hello world' } }
2. props父級(jí)向子級(jí)傳遞數(shù)據(jù)
在組件中使用props從父組件接收參數(shù)摊册,props中定義的屬性,在組件送可以直接使用
props來(lái)自父級(jí)篙贸,而data中return的數(shù)據(jù)是自己組件本身的數(shù)據(jù)投队,兩種數(shù)據(jù)的作用域都是組件本身,可以在template爵川、methods敷鸦、computed中直接使用
props的值有兩種,一種是字符串?dāng)?shù)組寝贡,一種是對(duì)象
-
可以使用v-bind動(dòng)態(tài)綁定父組件來(lái)的內(nèi)容
<div id="app"> ---用v-bind傳遞數(shù)據(jù)(需要回車(chē))-------------------------<br> <input type="text" v-model.lazy="parentMsg"> <bind-component v-bind:msg='parentMsg'></bind-component> </div> var app = new Vue({ el: '#app', data: { count: 0, parentMsg: '這是來(lái)自父級(jí)的數(shù)據(jù)' }, components: { 'bind-component': { props:['msg'], template: '<div>{{ msg }}</div>' } } })
3. 單項(xiàng)數(shù)據(jù)流
props傳遞數(shù)據(jù)是單向的扒披,父級(jí)數(shù)據(jù)的變化會(huì)傳遞給子級(jí),反之就行不通了
單向數(shù)據(jù)流可以避免子組件無(wú)意中修改父組件狀態(tài)
-
應(yīng)用情景:
-
第一種:父組件傳遞初始值進(jìn)來(lái)兔甘,子組件將它作為初始值保存起來(lái)谎碍,在自己的作用域
下可以隨意使用和修改。<div id="app"> <my-component msg="來(lái)自父級(jí)的數(shù)據(jù)"></my-component> </div> ---javascript--------------------- <script> var app = new Vue({ el: '#app', data: {}, components: { 'my-component': { props: ['msg'], template: '<p>{{ newMsg }}<p>', data: function () { return { //在data中保存下來(lái) newMsg: this.msg } } } } }) </script>
-
第二種:需要被轉(zhuǎn)變的原始值傳入洞焙,通過(guò)props獲取蟆淀,通過(guò)計(jì)算屬性進(jìn)行轉(zhuǎn)換
<div id="app"> <input type="number" v-model="width"> <computed-component :wth='width'></computed-component> </div> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script> var app = new Vue({ el: '#app', data: {width:10}, components: { 'computed-component': { props: ['wth'], template:'<div :style="style"></div>', //用計(jì)算屬性轉(zhuǎn)換傳入的值 computed: { style: function(){ return { width: this.wth + 'px', height: '100px', background: 'red' } } } } } }) </script>
-
4. 組件命名注意事項(xiàng)
- 在html中, myMessage 和 mymessage 是一致的,因此在組件中的html
中使用必須使用kebab-case(短橫線)命名方式。在html中不允許使用駝
峰T璺恕H廴巍!Q淝椤R商Α! - 在組件中, 父組件給子組件傳遞數(shù)據(jù)必須用短橫線甸鸟。在template中惦费,必
須使用駝峰命名方式兵迅,若為短橫線的命名方式。則會(huì)直接保錯(cuò)薪贫。 - 在組件的data中,用this.XXX引用時(shí),只能是駝峰命名方式恍箭。若為短橫線
的命名方式,則會(huì)報(bào)錯(cuò)瞧省。
5. 數(shù)據(jù)類型驗(yàn)證
-
驗(yàn)證的 type 類型可以是:
- String
- Number
- Boolean
- Object
- Array
- Function
Vue.component ( ‘ my-compopent ’扯夭, { props : { //必須是數(shù)字類型 propA : Number , //必須是字符串或數(shù)字類型 propB : [String , Number] , //布爾值,如果沒(méi)有定義鞍匾,默認(rèn)值就是 true propC: { type : Boolean , default : true }, //數(shù)字交洗,而且是必傳 propD: { type: Number , required : true }, //如果是數(shù)組或?qū)ο螅J(rèn)值必須是一個(gè)函數(shù)來(lái)返回 propE: { type : Array, default : function () { return [] ; } }, //自定義一個(gè)驗(yàn)證函數(shù) propF: { validator : function (value) { return value > 10; } } } });
三. 組件通信
1. 自定義事件
用于:子組件給父級(jí)傳遞數(shù)據(jù)
子組件用$emit ( '父組件中事件名' , 要傳遞的數(shù)據(jù) ) 來(lái)觸發(fā)事件 橡淑,父組件用@'父組件中事件名'='觸發(fā)的函數(shù)'來(lái) 監(jiān)昕子組件的事件构拳,觸發(fā)的函數(shù)的參數(shù)即為子組件傳遞來(lái)的數(shù)據(jù)
第一步:自定義事件
第二步:在子組件中用$emit觸發(fā)事件,第一個(gè)參數(shù)是事件名梳码,后邊的參數(shù)是要傳遞的數(shù)據(jù)
第三步:在自定義事件中用一個(gè)參數(shù)來(lái)接受
<div id="app">
您的余額是:{{ acount }}<br>
<my-component :acount="acount" @change-acount='handleAcount'></my-component>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
acount: 2000
},
methods:{
handleAcount:function(value){
this.acount = value
}
},
components: {
'my-component': {
props:['acount'],
template: `<div>
<button @click="addAcount">+1000</button>
<button @click="reduceAcount">-1000</button>
</div>`,
data: function(){
return {
count: this.acount
}
},
methods:{
addAcount: function(){
this.count += 1000
//注意這里$emit的參數(shù)
this.$emit('change-acount',this.count)
},
reduceAcount: function(){
this.count -= 1000
this.$emit('change-acount',this.count)
}
}
}
}
})
2. 在組件中使用v-model
在組件中使用v--model 其實(shí)是一個(gè)語(yǔ)法糖隐圾,這背后其實(shí)做了兩個(gè)操作
- v--bind 綁定一個(gè) value 屬性
- v--on 指令給當(dāng)前元素綁定 input 事件
$emit('input',value)的代碼,這行代碼實(shí)際上會(huì)觸發(fā)一個(gè) input事件, ‘input’后的參數(shù)就是傳遞給v--model綁定
的屬性的值
<div id="app">
您的余額是:{{ acount }}<br>
<!-- <my-component :acount="acount" @change-acount='handleAcount'></my-component> -->
<!-- 下面使用v-model -->
<my-component :acount="acount" v-model='acount'></my-component>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
acount: 2000
},
components: {
'my-component': {
props:['acount'],
template: `<div>
<button @click="addAcount">+1000</button>
<button @click="reduceAcount">-1000</button>
</div>`,
data: function(){
return {
count: this.acount
}
},
methods:{
addAcount: function(){
this.count += 1000
// 這里觸發(fā)的是input事件
this.$emit('input',this.count)
},
reduceAcount: function(){
this.count -= 1000
this.$emit('input',this.count)
}
}
}
}
})
</script>
3. 非父組件之間的通信---bus中介
用于兩個(gè)組件之間的通信,(非父子關(guān)系)掰茶,可以在根組件中用一個(gè)空的Vue對(duì)象作為中介,一個(gè)組件中監(jiān)聽(tīng)該中介的自定義事件蜜笤,另一個(gè)組件中觸發(fā)該自定義事件并傳遞數(shù)據(jù)
<div id="app">
<acomponent></acomponent>
<bcomponent></bcomponent>
</div>
<script>
Vue.component('acomponent', {
template: '<button @click="handle">點(diǎn)擊向B組件傳遞數(shù)據(jù)</button>',
data: function () {
return {
msg: '我是來(lái)自A組件的數(shù)據(jù)'
}
},
methods: {
handle: function () {
// 觸發(fā)根組件的bus中的method1事件
this.$root.bus.$emit('method1', this.msg)
}
}
})
Vue.component('bcomponent', {
template: '<div>{{ msg }}</div>',
data: function () {
return {
msg: '這是B組件'
}
},
created: function () {
// 對(duì)根組件bus監(jiān)聽(tīng)method1事件
this.$root.bus.$on('method1', (value)=> {
this.msg = value
})
}
})
var app = new Vue({
el: '#app',
data: {
bus: new Vue()
}
})
</script>
4. 父鏈和子鏈
父鏈:this.$parent
子鏈:this.$refs.索引
提供了為子組件提供索引的方法濒蒋,用特殊的屬性ref為其增加一個(gè)索引
<div id="app">
<button @click='clickA'>A子組件</button>
<button @click='clickB'>B子組件</button>
<son-a ref='a'></son-a>
<son-b ref='b'></son-b>
</div>
<script>
var app = new Vue({
el: '#app',
data: { msg: '來(lái)自父組件的msg' },
methods: {
clickA: function(){
alert(this.$refs.a.name)
},
clickB: function(){
alert(this.$refs.b.name)
}
},
components: {
'son-a': {
template: '<div>這是子組件:{{ msg }}</div>',
data: function () {
return {
msg: this.$parent.msg,
name: 'son-a'
}
}
},
'son-b': {
template: '<div><div>',
data: function () {
return {
name: 'son-b'
}
}
}
}
})
</script>
四. 插槽slot標(biāo)簽
1. 單個(gè)插槽
用于混合父組件的內(nèi)容與子組件的模板
在子組件中加入<slot></slot>標(biāo)簽,當(dāng)父組件中沒(méi)有傳入內(nèi)容時(shí)把兔,默認(rèn)顯示slot標(biāo)簽中的內(nèi)容沪伙,反之,則將傳入內(nèi)容替換掉原來(lái)slot標(biāo)簽中的內(nèi)容
<div id="app">
<my-component>
<p>{{ msg }}</p>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('my-component', {
template: `<div>
<slot>
如果父元素沒(méi)傳內(nèi)容進(jìn)來(lái)县好,就默認(rèn)顯示我吧围橡!
</slot>
</div>`
})
var app = new Vue({
el: '#app',
data: {msg:'父元素的內(nèi)容'}
})
</script>
2. 具名插槽
把父組件要傳入的標(biāo)簽命名slot='名稱',在子組件的slot標(biāo)簽中添加name屬性
<div id="app">
<my-component>
<div slot='header'>標(biāo)題</div>
<div slot='container'>正文</div>
<div slot='footer'>底部</div>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('my-component', {
template: `<div>
<slot name='header'>
如果父元素沒(méi)傳內(nèi)容進(jìn)來(lái)缕贡,就默認(rèn)顯示我吧翁授!
</slot>
</div>`
})
var app = new Vue({
el: '#app',
data: {msg:'父元素的內(nèi)容'}
})
</script>
3. 作用域插槽
從子組件中獲取數(shù)據(jù):在父組件中添加<template></template>標(biāo)簽,slot屬性的值與子元素<slot>標(biāo)簽的name屬性一樣晾咪,用slot-scope屬性獲取傳來(lái)的數(shù)據(jù)(除了name)
<div id="app">
<my-component>
<!-- 這里的prop是變量名收擦,隨便取一個(gè)名字都可以
slot的值要跟子組件的name相同
template標(biāo)簽不會(huì)被渲染
template標(biāo)簽用其他例如<p>、<span>等都可以 -->
<template slot-scope='prop' slot='abc'>
<!-- 可以獲取除了name以外傳來(lái)的內(nèi)容 -->
{{ prop.text }}
</template>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('my-component', {
template: `<div>
<slot name='abc' text='子組件中傳來(lái)的內(nèi)容'>
如果父元素沒(méi)傳內(nèi)容進(jìn)來(lái)谍倦,就默認(rèn)顯示我吧塞赂!
</slot>
</div>`
})
var app = new Vue({
el: '#app',
data: {msg:'父元素的內(nèi)容'}
})
</script>
4. 訪問(wèn)slot
通過(guò)this.$slots.name訪問(wèn)
Vue.component('my-component2', {
template: `<div>
<slot name='header'>
如果父元素沒(méi)傳內(nèi)容進(jìn)來(lái),就默認(rèn)顯示我吧昼蛀!
</slot>
<slot name = 'footer'></slot>
</div>`,
mounted:function(){
var header = this.$slots.header
var footer = this.$slots.footer
console.log(header[0].elm.innerText)
console.log(footer[0].elm.innerText)
}
})
五. 動(dòng)態(tài)組件
VUE給我們提供 了一個(gè)元素叫component
作用是: 用來(lái)動(dòng)態(tài)的掛載不同的組件
實(shí)現(xiàn):使用is特性來(lái)進(jìn)行實(shí)現(xiàn)的
<div id="app">
<!-- 綁定is屬性 -->
<component :is='thisView'></component>
<button @click="handleView('A')">頁(yè)面一</button>
<button @click="handleView('B')">頁(yè)面二</button>
<button @click="handleView('C')">頁(yè)面三</button>
<button @click="handleView('D')">頁(yè)面四</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#app',
data: {
thisView: 'compA'
},
methods:{
'handleView':function(value){
this.thisView = 'comp' + value
}
},
components:{
'compA':{template:'<div>頁(yè)面一</div>'},
'compB':{template:'<div>頁(yè)面二</div>'},
'compC':{template:'<div>頁(yè)面三</div>'},
'compD':{template:'<div>頁(yè)面四</div>'}
}
})
</script>
六. 自定義指令
自定義指令的基本用法
和組件類似分全局注冊(cè)和局部注冊(cè)宴猾,區(qū)別就是把component換成了derective
-
鉤子函數(shù)
指令定義函數(shù)提供了幾個(gè)鉤子函數(shù)(可選):
- bind: 只調(diào)用一次圆存,指令第一次綁定到元素時(shí)調(diào)用,用這個(gè)鉤子函數(shù)可以定義一個(gè)在綁定時(shí) 執(zhí)行一次的初始化動(dòng)作仇哆。
- inserted: 被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用(父節(jié)點(diǎn)存在即可調(diào)用沦辙,不必存在于 document 中)。 update: 被綁定元素所在的模板更新時(shí)調(diào)用税产,而不論綁定值是否變化怕轿。通過(guò)比較更新前后的 綁定值,可以忽略不必要的模板更新(詳細(xì)的鉤子函數(shù)參數(shù)見(jiàn)下)辟拷。
- componentUpdated: 被綁定元素所在模板完成一次更新周期時(shí)調(diào)用撞羽。 unbind: 只調(diào)用一次, 指令與元素解綁時(shí)調(diào)用衫冻。
-
鉤子函數(shù)的參數(shù)有:
- el: 指令所綁定的元素诀紊,可以用來(lái)直接操作 DOM 。
- binding: 一個(gè)對(duì)象隅俘,包含以下屬性:
- name: 指令名邻奠,不包括 v- 前綴。
- value: 指令的綁定值为居, 例如: v-my-directive=”1 + 1”, value 的值是 2碌宴。
- oldValue: 指令綁定的前一個(gè)值,僅在 update 和 componentUpdated 鉤子中可用蒙畴。無(wú)論值是否改變都可用贰镣。
- expression: 綁定值的字符串形式。 例如 v-my-directive=”1 + 1” 膳凝, expression 的值是 “1 + 1”碑隆。
- arg: 傳給指令的參數(shù)。例如 v-my-directive:foo蹬音, arg 的值是 “foo”上煤。
- modifiers: 一個(gè)包含修飾符的對(duì)象。 例如: v-my-directive.foo.bar, 修飾符對(duì)象,,,modifiers 的值是 { foo: true, bar: true }著淆。
- vnode: Vue 編譯生成的虛擬節(jié)點(diǎn)劫狠。
- oldVnode: 上一個(gè)虛擬節(jié)點(diǎn),僅在 update 和 componentUpdated 鉤子中可用牧抽。 自定義的指令
七嘉熊、render函數(shù)
1. 基本用法
在自定義組件時(shí),template屬性內(nèi)容有時(shí)會(huì)很長(zhǎng)扬舒,而且阐肤,在切換組件內(nèi)的內(nèi)容時(shí),不顯示的內(nèi)容可能也會(huì)渲染一遍再隱藏,而在組件中用render函數(shù)可以解決這個(gè)問(wèn)題
render函數(shù)的參數(shù)必須是createElement孕惜,這是在源碼中已經(jīng)定義好的函數(shù)
render函數(shù)要記得把createElement函數(shù)執(zhí)行結(jié)果返回出去
<div id="app">
<comp :thisview='thisView'>
<slot slot='red'>red</slot>
<slot slot='blue'>blue</slot>
</comp>
<button @click='clickRed'>red</button>
<button @click='clickBlue'>blue</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('comp', {
props: ['thisview'],
//這里的參數(shù)必須是createElement愧薛,是源碼中已經(jīng)定義好的函數(shù)
render: function (createElement) {
return createElement('div', this.$slots[this.thisview])
},
data: function () {
return {
view: this.thisview
}
}
})
var app = new Vue({
el: '#app',
data: { thisView: 'red' },
methods: {
clickRed: function () {
this.thisView = 'red'
},
clickBlue: function () {
this.thisView = 'blue'
}
}
})
</script>
2. createElement函數(shù)的參數(shù)
render函數(shù)返回createElement函數(shù)的執(zhí)行結(jié)果
-
第一個(gè)參數(shù) :createElement函數(shù)的第一個(gè)參數(shù)必選,可以是String衫画、Object毫炉、Function
-
String:html標(biāo)簽,比如'div'削罩、'h1'等等
Vue.component('child',{ render:function(createElement){ return createElement('div') } })
-
-
Object:含有數(shù)據(jù)選項(xiàng)的對(duì)象,比如:
Vue.component('child',{ render:function(createElement){ return createElement({ template: '<div>文字內(nèi)容</div>' }) } })
-
Function:返回含有數(shù)據(jù)選項(xiàng)的對(duì)象,比如:
Vue.component('child',{ render:function(createElement){ var domFn = function(){ return { template: '<div>文字內(nèi)容</div>' } } return createElement(domFn()) } })
-
第二個(gè)參數(shù):數(shù)據(jù)對(duì)象(可選)——只能是Object
下面是一些常見(jiàn)的選項(xiàng):style瞄勾、class、attrs弥激、domProps等
Vue.component('child',{ render:function(createElement){ return createElement({ template: '<div>文字內(nèi)容</div>' },{ 'class': { //表示類名class进陡,true為有該類名,false則相反 //class在js中是關(guān)鍵字微服,最好用引號(hào)包起來(lái)趾疚,不加也沒(méi)事 foo: true, baz: false }, style: { color: 'red', //css中的橫桿命名在這里都要寫(xiě)成駝峰命名 fontSize: '20px' }, attrs: { //attributes,正常的HTML屬性,大部分可以寫(xiě)進(jìn)來(lái) id: 'red', src: '../XXX.jpg' }, domProps: { //用來(lái)寫(xiě)原生的DOM屬性 innerHTML: '<span style="color:red;">文字內(nèi)容</span>' } }) } })
-
第三個(gè)參數(shù):代表子節(jié)點(diǎn)以蕴,可選——可以是String 或 Array(Array常用)
因?yàn)榈诙€(gè)參數(shù)可選且必須為Object糙麦,所以,如果第二個(gè)參數(shù)為String或Array丛肮,那么意味著第二個(gè)參數(shù)為空赡磅,這個(gè)String或Array是第三個(gè)參數(shù),子節(jié)點(diǎn)
其實(shí)第三個(gè)參數(shù)存的就是VNODE虛擬節(jié)點(diǎn)
Vue.component('child',{ render: function(createElement){ return createElement({ template: '<div>內(nèi)容</div>' },{ class:{ red: true } },[ //這里的內(nèi)容時(shí)字符串宝与,不是對(duì)象仆邓,所以也是子節(jié)點(diǎn)(第三個(gè)參數(shù)) createElement('span','內(nèi)容'), createElement('span','內(nèi)容') ]) } })
3. this.$slots在render函數(shù)中的使用
插槽的用法
第三個(gè) 參數(shù)存的就是VNODE
createElement(‘header’,header), 返回的就是VNODE
var header = this.$slots.header? //這返回的內(nèi)容就是含有VNODE的數(shù)組
<div id="app">
<child>
<span slot='header'>我是標(biāo)題</span>
<span slot='main'>我是正文</span>
<span slot='main'>我是正文</span>
<span slot='footer'>我是結(jié)尾</span>
</child>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('child', {
render: function (createElement) {
var header = this.$slots.header
var main = this.$slots.main
var footer = this.$slots.footer
return createElement('div', {
'class': {
red: true
}
}, [
createElement('header', header),
createElement('main', main),
createElement('footer', footer)
])
}
})
var app = new Vue({
el: '#app',
data: {}
})
4. 在 render中使用props傳遞數(shù)據(jù)
5. 在render函數(shù)中使用v-model
<div id="app">
<my-component :inputvalue='inputvalue' @change='changevalue'></my-component><br>
<!-- 這里的v-model是語(yǔ)法糖,綁定input事件伴鳖,當(dāng)觸發(fā)input事件時(shí),把傳來(lái)的值付給inputvalue -->
<my-component :inputvalue='inputvalue' v-model='inputvalue'></my-component><br>
{{ inputvalue }}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#app',
data: {
inputvalue: '111'
},
methods: {
changevalue: function (value) {
this.inputvalue = value
}
},
components: {
'my-component': {
props: ['inputvalue'],
render: function (createElement) {
return createElement('input', {
attrs: {
value: this.inputvalue
},
on: {
input: (event) => {
this.$emit('change', event.target.value)
this.$emit('input', event.target.value)
}
}
})
}
}
}
})
</script>
6. 作用域插槽
向組件的插槽中傳遞數(shù)據(jù)
$scopedSlots.default
<div id="app">
<my-component>
<template scope='abc'>
{{ abc.text }}<br>
{{ abc.name }}
</template>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#app',
data: {},
components: {
'my-component': {
render: function (createElement) {
return createElement('div', this.$scopedSlots.default({
text: '我是子組件傳來(lái)的數(shù)據(jù)',
name: '陳秋鈿'
}))
}
}
}
})
</script>
7. 函數(shù)化組件
functional:true //表示當(dāng)前Vue實(shí)例無(wú)狀態(tài)徙硅、無(wú)實(shí)例
無(wú)實(shí)例:組件內(nèi)部沒(méi)有this榜聂,可以通過(guò)context上下文來(lái)解決,render函數(shù)的第一個(gè)參數(shù)是createElement嗓蘑,第二個(gè)參數(shù)是context须肆,這里this是window
context.parent
context.props
context.props.text ---- this.text
context.children ----- this.$slots.default
八. vue-cli腳手架
1. 安裝步驟
首先電腦上要安裝最新版的nodeJS.官網(wǎng)下載,安裝完之后安裝淘寶npm鏡像
npm install -g cnpm --registry=https://registry.npm.taobao.org
-
安裝五部走:
-
全局安裝vue-cli
npm install -g vue-cli
-
進(jìn)入目錄–初始化項(xiàng)目
vue init webpack my-project
-
進(jìn)入項(xiàng)目
cd my-project
-
安裝依賴
npm install
-
啟動(dòng)項(xiàng)目
npm run dev
-
-
部署項(xiàng)目:
npm run build
2. 目錄結(jié)構(gòu)
├── build // 項(xiàng)目構(gòu)建(webpack)相關(guān)代碼 記憶:(夠賤) 9個(gè)
│ ├── build.js // 生產(chǎn)環(huán)境構(gòu)建代碼
│ ├── check-versions.js // 檢查node&npm等版本
│ ├── dev-client.js // 熱加載相關(guān)
│ ├── dev-server.js // 構(gòu)建本地服務(wù)器
│ ├── utils.js // 構(gòu)建配置公用工具
│ ├── vue-loader.conf.js // vue加載器
│ ├── webpack.base.conf.js // webpack基礎(chǔ)環(huán)境配置 //entry程序的入口
│ ├── webpack.dev.conf.js // webpack開(kāi)發(fā)環(huán)境配置
│ └── webpack.prod.conf.js // webpack生產(chǎn)環(huán)境配置
二桩皿、
├── config// 項(xiàng)目開(kāi)發(fā)環(huán)境配置相關(guān)代碼 記憶: (環(huán)配) 3個(gè)
│ ├── dev.env.js // 開(kāi)發(fā)環(huán)境變量(看詞明意)
│ ├── index.js //項(xiàng)目一些配置變量
│ └── prod.env.js // 生產(chǎn)環(huán)境變量
三豌汇、
├──node_modules// 項(xiàng)目依賴的模塊 記憶: (依賴) *個(gè)
四、
├── src// 源碼目錄5
1
│ ├── assets// 資源目錄
│ │ └── logo.png
2
│ ├── components// vue公共組件
│ │ └── Hello.vue
3
│ ├──router// 前端路由
│ │ └── index.js// 路由配置文件
4
│ ├── App.vue// 頁(yè)面入口文件(根組件)
5
│ └── main.js// 程序入口文件(入口js文件)
五泄隔、
└── static// 靜態(tài)文件拒贱,比如一些圖片,json數(shù)據(jù)等
│ ├── .gitkeep
剩余、
├── .babelrc// ES6語(yǔ)法編譯配置
├── .editorconfig// 定義代碼格式
├── .gitignore// git上傳需要忽略的文件格式
├── index.html// 入口頁(yè)面
├── package.json// 項(xiàng)目基本信息
├── README.md// 項(xiàng)目說(shuō)明
3. 其他
以 .vue 結(jié)尾的是組件文件逻澳,組件文件中的樣式只對(duì)組件中的標(biāo)簽有用
九. 前端路由和vuex狀態(tài)管理
訪問(wèn)不同的路由闸天,加載不同的組件(輸入不同的網(wǎng)址,顯示不同的內(nèi)容)
watch: {
// 如果路由有變化斜做,會(huì)再次執(zhí)行該方法
$route: "getUserData"
}
1. vue--router路由基本加載
-
安裝
npm install --save vue-router
- 引用
import router from 'vue-router' Vue.use(router)
-
配置路由文件苞氮,并在vue實(shí)例中注入
var rt = new router({ routes:[{ //這里是routes,不是routers啊 path:'/',//指定要跳轉(zhuǎn)的路徑 component:HelloWorld//指定要跳轉(zhuǎn)的組件 }] }) new Vue({ el: '#app', router: rt, components: { App }, template: '' })
-
確定視圖加載的位置
<router-view></router-view>
2. 路由的跳轉(zhuǎn)
用router-link
<router-link to="/"></router-link>
<template>
<ul>
<li>
<router-link to="/helloworld">HELLO WORLD</router-link>
</li>
<li>
<router-link to="/helloearth">HELLO EARTH</router-link>
</li>
</ul>
</template>
3. 通過(guò)路由傳遞參數(shù)
- 在路由中加入name屬性
- 在path后面加 "/ : 要傳遞的參數(shù) "
- 在router-link標(biāo)簽中綁定to瓤逼,name 和 params結(jié)合使用笼吟,在組件中用 $route.params.XXX 獲取傳來(lái)的參數(shù)
<!-- list.vue -->
<template>
<ul>
<li>
<router-link :to="{name: 'helloworld',params:{worldmsg: '你好世界'}}">
HELLO WORLD
</router-link>
</li>
<li>
<router-link :to="{name:'helloearth',params:{earthmsg:'你好地球'}}">
HELLO EARTH
</router-link>
</li>
</ul>
</template>
<!-- HelloEarth.vue -->
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
<h3>{{ $route.params.earthmsg }}</h3>
</div>
</template>
<script>
export default {
name: 'HelloEarth',
data () {
return {
msg: 'HELLO EARTH'
}
}
}
</script>
// index.js(router)
export default new router({
routes: [{
name: 'helloworld',
path: '/helloworld/:worldmsg',
component: HelloWorld
},{
name: 'helloearth',
path: '/helloearth/:earthmsg',
component: HelloEarth
}]
})
4. Axios —— get請(qǐng)求
this.$http.get( 'url ', {params:{}})
axios 是一個(gè)基于Promise 用于瀏覽器和 nodejs 的 HTTP 客戶端,它本身具有以下特征:
- 從瀏覽器中創(chuàng)建 XMLHttpRequest
- 從 node.js 發(fā)出 http 請(qǐng)求
- 支持 Promise API
- 攔截請(qǐng)求和響應(yīng)
- 轉(zhuǎn)換請(qǐng)求和響應(yīng)數(shù)據(jù)
- 取消請(qǐng)求
- 自動(dòng)轉(zhuǎn)換JSON數(shù)據(jù)
- 客戶端支持防止 CSRF/XSRF
-
使用方法
-
安裝
npm install axios
-
引入加載
import axios from 'axios'
-
將axios掛載到全局Vue上(不用每個(gè)文件都引入加載)
Vue.prototype.$http = axios
這里的http.get()函數(shù)就能發(fā)送請(qǐng)求贷帮,(這里this是指當(dāng)前Vue實(shí)例)
-
發(fā)出get請(qǐng)求
axios基于promise,有.then()定硝、.catch()
在請(qǐng)求鏈接上加參數(shù)的兩種方法:
? 直接在鏈接后面加 ?page=1&limit=10
? 或者皿桑,get函數(shù)加第二個(gè)參數(shù) {params:{ page:1;limit:10}}
<template> <div> <button @click='getData'>點(diǎn)擊請(qǐng)求數(shù)據(jù)</button> <ul> <li v-for="item in items">{{item.title}}</li> </ul> </div> </template> <script> export default { name: "HelloWorld", data() { return { msg: "Welcome to Your Vue.js App", items: [] }; }, methods: { getData() { // this.$http.get('https://cnodejs.org/api/v1/topics?page=1&limit=10') this.$http .get("https://cnodejs.org/api/v1/topics", { params: { page: 1, limit: 10 } }) .then(res => { this.items = res.data.data; console.log(res.data.data); }) .catch(function(err) { console.log(err); }); } } }; </script>
-
5. Axios —— post請(qǐng)求
與get相似,把get換成post
-
POST傳遞數(shù)據(jù)有兩種格式:
form-data格式: ?page=1&limit=48
x-www-form-urlencoded格式: { page: 1,limit: 10 }
-
在axios中蔬啡,post請(qǐng)求接收的參數(shù)必須是form-data格式诲侮,可以使用qs插件把我們寫(xiě)的內(nèi)容轉(zhuǎn)換為formdata格式
qs插件—-qs.stringify
npm install qs
import qs from'qs'
postData() {
this.$http.post(url, qs.stringify({
params: {
page: 1,
limit: 10
}
}))
.then(res => {
this.items = res.data.data;
console.log(res.data.data);
})
.catch(function(err) {
console.log(err);
});
}
6.vuex的store用法
子組件和父組件之間的通信可以通過(guò)props以及$emit來(lái)完成,非父組件之間的通信需要通過(guò)他們之間的共同父組件來(lái)完成箱蟆,當(dāng)文件較多時(shí)沟绪,就會(huì)很亂很麻煩,所以就用到了Vuex的store
簡(jiǎn)而言之空猜,vuex可以用來(lái)管理狀態(tài)绽慈,共享數(shù)據(jù),在各個(gè)組件之間管理外部狀態(tài)
應(yīng)用場(chǎng)景:多個(gè)頁(yè)面間共享的登錄狀態(tài)
-
安裝vuex辈毯,引入并通過(guò)use方法使用它
npm i vuex
import Vuex from 'vuex'
Vue.use(Vuex)
-
創(chuàng)建狀態(tài)倉(cāng)庫(kù)
//這里的Store和state是不能改的坝疼! var store = new Vuex.Store({ //state 狀態(tài) state: { num: 100 } }) //在入口文件中引入store,跟引入router一樣 new Vue({ el: '#app', router, store, //就是這一句 components: { App }, template: '<App/>' })
-
在任意組件中谆沃,都可以通過(guò) this.$store.state.XXX 直接拿到共享的數(shù)據(jù)
computed:{ getNum:function(){ return this.$store.state.num } }
7. vuex的相關(guān)操作及核心用法
vuex狀態(tài)管理的流程
view———->actions———–>mutations—–>state————->view
方法1:在mutations選項(xiàng)中定義狀態(tài)改變事件钝凶,在組件中通過(guò)this.$store.commit('事件名')觸發(fā)轉(zhuǎn)臺(tái)的改變
-
方法2:actions,用來(lái)操作mutations的唁影,可有可無(wú)耕陷,但是actions可以進(jìn)行異步操作而mutations不能,
通過(guò)this.$store.dispatch('事件名')
注意:actions提交的是mutation,而不是直接變更狀態(tài)
actions可以包含異步操作,但是mutation只能包含同步操作
-
方法三:getters据沈,我覺(jué)得這個(gè)跟計(jì)算屬性有點(diǎn)像
var store = new Vuex.Store({ state: { num: 100 }, mutations:{ addNum(state){ state.num ++ }, reduceNum(state){ state.num -- } }, actions:{ //傳入的參數(shù)為上下文 ruduce(context){ context.commit('reduceNum') } }, getters:{ getCount(state){ return state.num > 0 ? state.num : 0 } } }) //在組件中 this.$store.commit('addNum') this.$store.dispatch('ruduce') this.$store.getters('getCount')
十. 過(guò)渡
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
new Vue({
el: '#demo',
data: {
show: true
}
})
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
在進(jìn)入/離開(kāi)的過(guò)渡中哟沫,會(huì)有 6 個(gè) class 切換。
-
v-enter
:定義進(jìn)入過(guò)渡的開(kāi)始狀態(tài)锌介。在元素被插入之前生效嗜诀,在元素被插入之后的下一幀移除猾警。 -
v-enter-active
:定義進(jìn)入過(guò)渡生效時(shí)的狀態(tài)。在整個(gè)進(jìn)入過(guò)渡的階段中應(yīng)用裹虫,在元素被插入之前生效肿嘲,在過(guò)渡/動(dòng)畫(huà)完成之后移除。這個(gè)類可以被用來(lái)定義進(jìn)入過(guò)渡的過(guò)程時(shí)間筑公,延遲和曲線函數(shù)雳窟。 -
v-enter-to
: 2.1.8版及以上 定義進(jìn)入過(guò)渡的結(jié)束狀態(tài)。在元素被插入之后下一幀生效 (與此同時(shí)v-enter
被移除)匣屡,在過(guò)渡/動(dòng)畫(huà)完成之后移除封救。 -
v-leave
: 定義離開(kāi)過(guò)渡的開(kāi)始狀態(tài)。在離開(kāi)過(guò)渡被觸發(fā)時(shí)立刻生效捣作,下一幀被移除誉结。 -
v-leave-active
:定義離開(kāi)過(guò)渡生效時(shí)的狀態(tài)。在整個(gè)離開(kāi)過(guò)渡的階段中應(yīng)用券躁,在離開(kāi)過(guò)渡被觸發(fā)時(shí)立刻生效惩坑,在過(guò)渡/動(dòng)畫(huà)完成之后移除。這個(gè)類可以被用來(lái)定義離開(kāi)過(guò)渡的過(guò)程時(shí)間也拜,延遲和曲線函數(shù)以舒。 -
v-leave-to
: 2.1.8版及以上 定義離開(kāi)過(guò)渡的結(jié)束狀態(tài)。在離開(kāi)過(guò)渡被觸發(fā)之后下一幀生效 (與此同時(shí)v-leave
被刪除)慢哈,在過(guò)渡/動(dòng)畫(huà)完成之后移除蔓钟。
?