1.vue常用對象
var vm = new Vue({
// 數(shù)據(jù)
data: "聲明需要響應(yīng)式綁定的數(shù)據(jù)對象",
props: "接收來自父組件的數(shù)據(jù)",
propsData: "創(chuàng)建實例時手動傳遞props塘砸,方便測試props",
computed: "計算屬性",
methods: "定義可以通過vm對象訪問的方法",
watch: "Vue實例化時會調(diào)用$watch()方法遍歷watch對象的每個屬性",
// DOM
el: "將頁面上已存在的DOM元素作為Vue實例的掛載目標(biāo)",
template: "可以替換掛載元素的字符串模板",
render: "渲染函數(shù)寸莫,字符串模板的替代方案",
renderError: "僅用于開發(fā)環(huán)境开仰,在render()出現(xiàn)錯誤時脐往,提供另外的渲染輸出",
// 生命周期鉤子
beforeCreate: "發(fā)生在Vue實例初始化之后蕊肥,data observer和event/watcher事件被配置之前",
created: "發(fā)生在Vue實例初始化以及data observer和event/watcher事件被配置之后",
beforeMount: "掛載開始之前被調(diào)用谒获,此時render()首次被調(diào)用",
mounted: "el被新建的vm.$el替換,并掛載到實例上之后調(diào)用",
beforeUpdate: "數(shù)據(jù)更新時調(diào)用壁却,發(fā)生在虛擬DOM重新渲染和打補丁之前",
updated: "數(shù)據(jù)更改導(dǎo)致虛擬DOM重新渲染和打補丁之后被調(diào)用",
activated: "keep-alive組件激活時調(diào)用",
deactivated: "keep-alive組件停用時調(diào)用",
beforeDestroy: "實例銷毀之前調(diào)用批狱,Vue實例依然可用",
destroyed: "Vue實例銷毀后調(diào)用,事件監(jiān)聽和子實例全部被移除展东,釋放系統(tǒng)資源",
// 資源
directives: "包含Vue實例可用指令的哈希表",
filters: "包含Vue實例可用過濾器的哈希表",
components: "包含Vue實例可用組件的哈希表",
// 組合
parent: "指定當(dāng)前實例的父實例赔硫,子實例用this.$parent訪問父實例,父實例通過$children數(shù)組訪問子實例",
mixins: "將屬性混入Vue實例對象盐肃,并在Vue自身實例對象的屬性被調(diào)用之前得到執(zhí)行",
extends: "用于聲明繼承另一個組件爪膊,從而無需使用Vue.extend,便于擴展單文件組件",
provide&inject: "2個屬性需要一起使用砸王,用來向所有子組件注入依賴推盛,類似于React的Context",
// 其它
name: "允許組件遞歸調(diào)用自身,便于調(diào)試時顯示更加友好的警告信息",
delimiters: "改變模板字符串的風(fēng)格谦铃,默認(rèn)為{{}}",
functional: "讓組件無狀態(tài)(沒有data)和無實例(沒有this上下文)",
model: "允許自定義組件使用v-model時定制prop和event",
inheritAttrs: "默認(rèn)情況下耘成,父作用域的非props屬性綁定會應(yīng)用在子組件的根元素上。當(dāng)編寫嵌套有其它組件或元素的組件時驹闰,可以將該屬性設(shè)置為false關(guān)閉這些默認(rèn)行為",
comments: "設(shè)為true時會保留并且渲染模板中的HTML注釋"
});
2. Vue中watch的用法
(1)監(jiān)聽
??????????route使用場景:當(dāng)兩個路由指向同一個組件是瘪菌,修改路由視圖并未更新,第二個組件的created未執(zhí)行嘹朗,這時需要監(jiān)聽route使用場景:當(dāng)兩個路由指向同一個組件時师妙,修改路由視圖并未更新,第二個組件的created未執(zhí)行屹培,這時需要監(jiān)聽route使用場景:當(dāng)兩個路由指向同一個組件是默穴,修改路由視圖并未更新,第二個組件的created未執(zhí)行惫谤,這時需要監(jiān)聽route
created () {
console.log(this.getStatus(this.$route.path))
},
methods: {
getStatus (urlStr) {
var urlStrArr = urlStr.split('/')
return urlStrArr[urlStrArr.length - 1]
}
},
watch: {
'$route' (to, from) {
console.log(this.getStatus(this.$route.path))
}
}
(2) watch默認(rèn)在數(shù)據(jù)第一次修改時開始監(jiān)聽壁顶,對對象的內(nèi)部的屬性監(jiān)聽不到珠洗,只能監(jiān)聽對象的引用溜歪。
使用場景:1.組件要求第一次修改之前就開始監(jiān)聽 2. 深度去監(jiān)聽對象的屬性。
data() {
return {
fullName: '',
firstName: '',
lastName: '',
obj: {
name: 'huoalong'
}
}
},
watch: {
firstName: {
handler(newName, oldName) {
this.fullName = newName + this.lastName;
},
immediate: true //在第一次修改之前開始監(jiān)聽许蓖,
deep: true, //深度監(jiān)聽對象內(nèi)部的屬性
}
}
deep的意思就是深入觀察蝴猪,監(jiān)聽器會一層層的往下遍歷调衰,給對象的所有屬性都加上這個監(jiān)聽器,但是這樣性能開銷就會非常大了自阱,任何修改obj里面任何一個屬性都會觸發(fā)這個監(jiān)聽器里的 handler,如果我們明確要觀察哪個屬性時可以這樣做
watch: {
‘obj.name’: {
handler(newName, oldName) {
this.fullName = newName + this.lastName;
},
immediate: true //在第一次修改之前開始監(jiān)聽
}
}
(3) 通過組件的屬性props設(shè)置一個動態(tài)變化的值時需要用到watch
場景:父子組件通過props傳動態(tài)值時嚎莉,需要在子組件data里面重新定義一個變量對象來盛放props,然后用watch監(jiān)聽沛豌。
父組件
<el-dialog title="消息列表" :visible.sync="dialogTableVisible" size="tiny">
<MessageList :tabs="tabs"></MessageList>
</el-dialog>
子組件
props: {
tabs: {
type: String,
}
},
data() {
return {
//tabs: '課程報名申請',
activeName2: 'first',
tab: {
tabs: this.tabs,
}
};
},
watch: {
tabs: function(value) {
this.tab['tabs'] = value;
}
},
3. 在鉤子函數(shù)里面用$refs定位DOM時遇到的坑
在mounted函數(shù)里面用$refs定位dom一般會得到undefined的情況趋箩,mounted階段,DOM結(jié)構(gòu)準(zhǔn)備就緒加派,但是這里的準(zhǔn)備就緒需要特別說明一下:
DOM結(jié)構(gòu)已經(jīng)出來了叫确,但是如果在DOM結(jié)構(gòu)中的某個DOM節(jié)點使用了v-if、v-show或者v-for(即根據(jù)獲得的后臺數(shù)據(jù)來動態(tài)操作DOM芍锦,即響應(yīng)式)竹勉,那么這些DOM是不會再mounted階段找到的。
此時的mounted階段娄琉,一般是用于發(fā)起后端請求次乓,拿回數(shù)據(jù),配合路由鉤子做一些事情孽水,簡單來說就是在mounted鉤子中加載數(shù)據(jù)而已票腰,加載回來的數(shù)據(jù)是不會再這個階段更新的DOM中的
所以如果在mounted鉤子中使用$refs,如果ref是定位在有v-if女气、v-for丧慈、v-show中的DOM節(jié)點,返回來的只能是undefined主卫,因為在mounted階段他們根本不存在L幽!
經(jīng)過檢驗簇搅,上面端文字是錯誤的完域,$refs定位不到的主要原因是因為v-if、v-for瘩将、v-show這些語句如果依賴父組件傳來的參數(shù)的話吟税,該該參數(shù)是在mounted()階段子還沒獲取得到~~~~!W讼帧3σ恰!
如果想要真正地在DOM加載完成后拿到數(shù)據(jù)备典,就需要調(diào)用VUE的全局api : this.$nextTick(() => {})
如果說mounted階段是加載階段异旧,那么updated階段則是完成了數(shù)據(jù)更新到DOM的階段(對加載回來的數(shù)據(jù)進行處理),此時提佣,ref吮蛹、數(shù)據(jù)等等全部都掛載到DOM結(jié)構(gòu)上去荤崇,在update階段使用this.$refs.xxx,就100%能找到該DOM節(jié)點潮针。
updated與mounted不同的是术荤,在每一次的DOM結(jié)構(gòu)更新,vue都會調(diào)用一次updated(){}鉤子函數(shù)每篷!而mounted僅僅只執(zhí)行一次而已
簡單來說瓣戚,只要在調(diào)試的時候,能看到元素的存在焦读,在updated階段都可以使用this.$refs.xxx找到對應(yīng)的DOM節(jié)點带兜!
4. 組件之間傳遞參數(shù)的五種方法
(1)路由query 使用場景:根據(jù)url地址來傳參
{
path: '/workTaskEdit/:id',
name: 'workTaskEdit',
components: '',
},
<router-link :to="{path:'/workTaskEdit',query{id:id}}">
vm.$router.push({name:'workTaskEdit', query:{id:id}})
(2)props 使用場景:父子組件傳參
//子組件
props: [ 'a' ] 或者 props: {a:{type: 'Array'}}
//父組件
<component :a= 'data'> </component>
(3)vue Bus 使用場景:簡單的非父子組件傳參
aa組件和bb組件為非父子組件,假設(shè) bb 組件里面有個按鈕吨灭,點擊按鈕刚照,把 123 傳遞給 aa 組件
在根組件定義Bus,用一個空的Vue實例作為中央事件總線喧兄,注冊到根組件无畔,避免局部作用域的影響。
// 根組件(this.$root)
new Vue({
el: '#app',
router,
render: h => h(App),
data: {
// 空的實例放到根組件下吠冤,所有的子組件都能調(diào)用
Bus: new Vue()
}
})
bb 組件內(nèi)調(diào)用事件觸發(fā)
<button @click="submit">提交<button>
methods: {
submit() {
// 事件名字自定義浑彰,用不同的名字區(qū)別事件
this.$root.Bus.$emit('eventName', 123)
}
}
aa 組件內(nèi)調(diào)用事件接收↓
// 當(dāng)前實例創(chuàng)建完成就監(jiān)聽這個事件
created(){
this.$root.Bus.$on('eventName', value => {
this.print(value)
})
},
methods: {
print(value) {
console.log(value)
}
},
// 在組件銷毀時別忘了解除事件綁定
beforeDestroy() {
this.$root.Bus.$off('eventName')
},
補充: 利用Bus可以在Vue外部調(diào)用methods里面的方法:
在父組件中的methods的方法中定義一個方法,在方法里用$emit接收公共組件里的方法拯辙,注意父組件要用一個變量保存郭变,var vm = new Vue({})
var vm = new Vue({
el: '#example',
data: {
msg: 'Hello Directive',
data: {}
},
methods: {
getCardNum: function (data, on) {
eventHub.$emit('translate', data);
}
}
});
在事件當(dāng)前的組件中,在created中涯保,用$on向公共的組件eventHub傳遞诉濒,translate是自定義的,getCardNum(data)是要在外部調(diào)用的方法;
eventHub.$on('translate', function (data) {
that.getCardNum(data);
});
最后就可以在vue組件外部夕春,或者文件外部調(diào)用getCardNum(data)這個函數(shù)未荒,比如在html中就可以 onclick = vm.getCardNum() 這樣來調(diào)用;vm是父組件
(4)vuex 使用場景:復(fù)雜的非父子組件傳參及志,各個組件共享數(shù)據(jù)
(5) 復(fù)雜的項目中一般用vuex 參考 https://vuex.vuejs.org/zh-cn/api.html
5. 組件和route使用$router.params.xx耦合度太高片排,可嘗試使用props解耦
//通過 props 解耦
const User = {
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true },
// 對于包含命名視圖的路由,你必須分別為每個命名視圖添加 `props` 選項:
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
})
//這樣你便可以在任何地方使用該組件速侈,使得該組件更易于重用和測試率寡。
補充: 切記router.push的時候不要path和params一起用,params會失效倚搬,建議用query冶共,如果非要用params,可以使用組件的name。而且一定要注意取數(shù)據(jù)的時候是route比默,不是router幻捏,千萬不要被坑 了盆犁,打印出來可以發(fā)現(xiàn)route是本路由的信息命咐,而router是全局的router信息
6. 導(dǎo)航守衛(wèi)
完整的導(dǎo)航解析流程
導(dǎo)航被觸發(fā)。
在失活的組件里調(diào)用離開守衛(wèi)谐岁。
調(diào)用全局的 beforeEach 守衛(wèi)醋奠。
在重用的組件里調(diào)用 beforeRouteUpdate 守衛(wèi) (2.2+)。
在路由配置里調(diào)用 beforeEnter伊佃。
解析異步路由組件窜司。
在被激活的組件里調(diào)用 beforeRouteEnter。
調(diào)用全局的 beforeResolve 守衛(wèi) (2.5+)航揉。
導(dǎo)航被確認(rèn)塞祈。
調(diào)用全局的 afterEach 鉤子。
觸發(fā) DOM 更新帅涂。
用創(chuàng)建好的實例調(diào)用 beforeRouteEnter 守衛(wèi)中傳給 next 的回調(diào)函數(shù)议薪。
(1)組件內(nèi)的守衛(wèi)
beforeRouteEnter 不能訪問this,但是在next里面有一個vm參數(shù) 可以訪問組件實例 場景:在渲染該組件的對應(yīng)路由被 confirm 前調(diào)用
beforeRouteUpdate 有this,不支持回調(diào) 在當(dāng)前路由改變媳友,但是該組件被復(fù)用時調(diào)用
beforeRouteLeave 有this斯议,不支持回調(diào) 場景:這個離開守衛(wèi)通常用來禁止用戶在還未保存修改前突然離開
(2)路由獨享的守衛(wèi)
routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ]
7. mixins使用注意事項和高級用法,繼承extends醇锚,二者類似
對比: mixins接受對象數(shù)組(多繼承)哼御,extends接受對象或函數(shù)(單繼承)
合并策略:
(1)值為對象的選項,如 methods, components 和 directives 將合并到同一個對象內(nèi)焊唬。如果鍵沖突則組件的選項優(yōu)先恋昼。
(2)同名鉤子函數(shù)被并入一個數(shù)組,因而都會被調(diào)用赶促。另外焰雕,混合的鉤子將在組件自己的鉤子之前調(diào)用
繼承鉤子函數(shù)
const extend = {
created () {
console.log('extends created')
}
}
const mixin1 = {
created () {
console.log('mixin1 created')
}
}
const mixin2 = {
created () {
console.log('mixin2 created')
}
}
export default {
extends: extend,
mixins: [mixin1, mixin2],
name: 'app',
created () {
console.log('created')
}
}
控制臺輸出
extends created
mixin1 created
mixin2 created
created
結(jié)論: 優(yōu)先調(diào)用mixins和extends繼承的父類,extends觸發(fā)的優(yōu)先級更高芳杏,相對于是隊列
push(extend, mixin1, minxin2, 本身的鉤子函數(shù))
mixins
調(diào)用方式: mixins: [mixin1, mixin2]
是對父組件的擴充矩屁,包括methods、components爵赵、directive等吝秕。。空幻。
觸發(fā)鉤子函數(shù)時烁峭,先調(diào)用mixins的函數(shù),再調(diào)用父組件的函數(shù)。
雖然也能在創(chuàng)建mixin時添加data约郁、template屬性缩挑,但當(dāng)父組件也擁有此屬性時以父為準(zhǔn),從這一點也能看出制作者的用心(擴充)鬓梅。
data供置、methods內(nèi)函數(shù)、components和directives等鍵值對格式的對象均以父組件/實例為準(zhǔn)
extends
調(diào)用方式: extends: CompA
同樣是對父組件的擴充绽快,與mixins類似芥丧,但優(yōu)先級均次于父組件
extend
擴展組件的構(gòu)造器
當(dāng)我們調(diào)用vue.component('a', {...})時自動調(diào)用
值得注意的是extend內(nèi)的data為一個函數(shù)
8. model指令高級
場景: 默認(rèn)情況下v-model把value用作prop且把input作為event事件,而一些輸入類型比如單選框和復(fù)選框可能想使用value另做它用坊罢,這時需要修改prop來達到不同的目的续担。
ue.component('my-checkbox',{
model: {
prop: 'checked',
event: 'change',
},
props: {
value: String,
check: {
type: 'Number',
default: 0,
}
}
})
9. is的使用
場景 :運用在動態(tài)組件,且基于dom內(nèi)模版的限制下工作
value: 已注冊的組件名稱或者一個組件的選項對象
結(jié)合keep-alive組件使用效果更好 創(chuàng)建一次組件緩存活孩,避免重復(fù)渲染
keep-alive>
<component :is='currentTab'></component>
</keep-alive>
//變通
<table>
<tr :is='my-component'></tr>
</table>
10.利用Object.freeze()提升性能
場景: 對于純展示的大數(shù)據(jù)
eg: data: { list: Object.freeze([.........]) }
11.插槽的使用
內(nèi)容分發(fā)API <slot>
具名插槽:
父組件
<templete slot="header">
<h1>.....</h1>
</templete>
或者
<h1 slot='header'>...</h1>
子組件
<header>
<slot name='header'></slot>
</header>
默認(rèn)插槽
<slot>默認(rèn)值</slot>
作用域插槽傳值
父組件
<templete slot-scope='{todo}'>
{{ todo.text }}
</templete>
子組件
<slot :todo="todo">
{{ todo.text }}
</slot>
12.Vue對變動的數(shù)組和對象檢測時,需要注意的地方
數(shù)組:以下兩個變動的數(shù)組不能檢測到
1)利用索引直接設(shè)置一個項時物遇,vm.items[indexOf] = newItem;
(2) 修改數(shù)組的長度, vm.items.length = newLength;
解決辦法:
(1) Vue.set(items,index,newValue)
Vue.items.splice(items,1,newValue)
this.$set(items,index,newValue)
(2) items.splice(newLength)
對象:對象添加屬性和刪除屬性時,vue不能檢測到
解決辦法:
Vue.set(object,newKey,newValue)
this.$set(object,newKey,newValue)
Object.assign({},object,{屬性列表})