1、動態(tài)添加class或style
有時候希望根據(jù)某個狀態(tài)值來決定是否添加某個類,可以這樣:
// 數(shù)組語法
<div :class="['a',value==true?'b':'']"> //類a總是存在间唉,當value為真時類b存在
// 對象語法
<div :class="{'a':true,'b':value}"> //類a,b都由value控制
<div :style="{background:'url('+value.url+')'}"> //對于style绞灼,最好用對象語法,屬性值取自當前vue實例
2呈野、綁定事件函數(shù)
有兩種方式:
// 方式1
<div @click='handle'></div> //handle函數(shù)的this指向當前vue實例低矮,并且會將event對象傳入handle作第一個參數(shù),通潮幻埃可用event.target獲取被點擊的DOM元素
// 方式2
<div @click='handle("param1",$event)'></div> //handle函數(shù)的this指向當前實例军掂,也可將$event傳入handle,作用同上姆打,一般用來獲取被點擊的DOM元素
3良姆、關于箭頭函數(shù)
vue的一些配置項肠虽,如mounted,beforeRouteEnter,beforeRouteLeave等幔戏,本身是一個函數(shù),若使用箭頭函數(shù)語法税课,則其內的this對象不是當前vue實例闲延。因此這三個配置項不要用箭頭函數(shù),其它的配置項韩玩,如methods,computed,watch等接受對象作為配置的垒玲,其內的函數(shù)最好用箭頭函數(shù),另外setTimeout(fn,time)中的fn最好也用箭頭函數(shù)找颓。
4合愈、數(shù)據(jù)傳遞
1、父子組件(prop down,event up)
- 一般而言击狮,父組件通過prop傳遞屬性給子組件佛析,子組件事先需定義props屬性,如果沒有定義props彪蓬,那這個傳遞過來的值會自動添加到子組件的根元素上寸莫;
- 子組件中一般通過觸發(fā)某種自定義事件向父元素通信,因此一般在父元素中使用子組件的地方監(jiān)聽該事件名档冬,該事件名是自定義的膘茎,因此要與子組件的一致。
<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
}
}
})
- 如果要在父元素中使用子組件的地方監(jiān)聽原生事件酷誓,可用@click.native
- 普通html標簽上用@click是原生事件披坏,自定義組件中用@click是自定義事件
2、非父子組件
有時候盐数,非父子關系的兩個組件之間也需要通信棒拂。在簡單的場景下,可以使用一個空的 Vue 實例作為事件總線:
var bus = new Vue()
// 觸發(fā)組件 A 中的事件
bus.$emit('id-selected', 1)
/ 在組件 B 創(chuàng)建的鉤子中監(jiān)聽事件
bus.$on('id-selected', function (id) {
// ...
}.bind(this))//綁定作用域
5娘扩、不能觸發(fā)視圖更新的操作
- 數(shù)組
// 無法觸發(fā)
vm.items[indexOfItem] = newValue
vm.items.length = newLength
// 可以觸發(fā)
Vue.set(example1.items, indexOfItem, newValue)
example1.items.splice(newLength)
- 對象
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 現(xiàn)在是響應式的
vm.b = 2
// `vm.b` 不是響應式的
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
Vue.set(vm.userProfile, 'age', 27) //響應式
3着茸、watch對象變化:
'messages': { // messages是一個數(shù)組壮锻,監(jiān)聽數(shù)組或對象的變化
handler: function(newValue, old) {
if (newValue.length == 0) {
setTimeout(() => {
history.back();
}, 1000)
}
},
deep: true
}
6、關于beforeRouteEnter和beforeRouteLeave
- beforeRouteEnter(to,from,next) 無法訪問當前vue實例涮阔,一般用于從localStorage中讀取數(shù)據(jù)恢復頁面猜绣,比如從頁面a到b,在從b回到a敬特,若a有數(shù)據(jù)變化(ajax拉取)就更新頁面掰邢,否則不更新;或者還原當前滾動條位置
- beforeRouteLeave(to,from,next) 可訪問當前vue實例伟阔,一般用于頁面離開時將某些狀態(tài)保存在localStorage中辣之,例如當前滾動條位置
- 二者都必須顯示調用next函數(shù)
7、keep-alive和router-view混合使用
// 這是目前用的比較多的方式
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
...
routes: [
{ path: '/', redirect: '/index', component: Index, meta: { keepAlive: true }},
{
path: '/common',
component: TestParent,
children: [
{ path: '/test2', component: Test2, meta: { keepAlive: true } }
]
}
....
// 表示index和test2都使用keep-alive
若有三個頁面A->B->C皱炉,希望A->B時B拉新數(shù)據(jù)怀估;C返回B時B不拉新數(shù)據(jù),且保存B到C之前的位置,該如何做?
1帅掘、給B設置keepAlive:true;
2康铭、在B的beforeRouteEnter中做獲取數(shù)據(jù)的操作,該鉤子的三個參數(shù)可以判斷B的上一個頁面赌髓,從而決定是否拉數(shù)據(jù)从藤;
在B的beforeRouteLeave里用localStorage記錄位置,并清除和頁面展現(xiàn)相關的數(shù)據(jù)狀態(tài)锁蠕;
3夷野、在接口回調里最好用EventCenter這種觀察者模式來觸發(fā)數(shù)據(jù)獲取成功的事件
4、在B的mounted鉤子里接受數(shù)據(jù)獲取成功的事件匿沛,就可以拿到數(shù)據(jù)
5扫责、在B的activated鉤子里取localStorage里的位置
8、router-link常用方式
<!-- 命名的路由 -->
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
<!-- 帶查詢參數(shù)逃呼,下面的結果為 /register?plan=private -->
<router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link>
//對應js
this.$route.params.userId
this.$route.query.plan
9鳖孤、過度動畫
-
單元素過渡
transition包一個含有v-if或v-show指令的元素就行
動畫過程 - 多元素過渡
transition下只能有一個根元素,所以多元素時必須用v-if抡笼,v-else來保證只有一個苏揣,此外,多個相同標簽時推姻,最好給每個標簽設置key - 多組件過渡
用動態(tài)組件即可 - 列表過渡
需用transition-group組件包裹平匈,被包裹元素必須設置key,其他和單元素一樣
10、數(shù)據(jù)拉取
- 數(shù)據(jù)獲取操作最早可以放在每個組件的beforeRouteEnter里增炭,然后利用觀察者模式把數(shù)據(jù)傳到beforeMount鉤子函數(shù)里做邏輯操作
beforeRouteEnter(to, from, next) {
let feed_id = to.params.id;
if (from.name != 'CommentDetail' && feed_id) {
getArticleDetail({
feed_id: feed_id
}).then(res => EventCenter.$emit('renderArticle', res));
getComment({
feed_id: feed_id
}).then(res => EventCenter.$emit('renderComment', res));
}
next();
}
beforeMount(){
// 1忍燥、渲染文章詳情
EventCenter.$on('renderArticle', res => {
});
// 2、渲染文章評論
EventCenter.$on('renderComment', res => {
})
}
11隙姿、插件 or 組件
對于全局使用頻率較高的最好寫成插件梅垄,而不是組件。例如loading,toast之類,若寫成組件输玷,則需要在每個父組件中引入該組件队丝,比較麻煩,寫成插件就可以直接調用
import $ from 'n-zepto';
import Vue from 'vue';
export default {
install() {
var timer = null;
Vue.prototype.$alerTip = function(text, delay, options) {
var defaultCssObject = {
position: 'fixed',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: 10000,
minWidth: '1.5rem',
margin: '0 auto',
left: 'calc((100% - 1.5rem) / 2)',
bottom: '1.4rem',
borderRadius: '.1rem',
height: '.5rem',
lineHeight: '.5rem',
background: '#000',
opacity: 0.85,
color: 'white',
};
var cssObject = options || defaultCssObject;
var temp = `<div class="v-toast">${text}</div>`;
var $div = $(temp);
$div.css(cssObject);
$('body').append($div);
clearTimeout(timer);
timer = setTimeout(() => {
$('.v-toast').remove();
timer = null;
}, delay);
}
}
}
12欲鹏、vue父子組件生命周期執(zhí)行順序問題
父子組件鉤子執(zhí)行順序:
father created
father before mounted
son created
son before mount
son mounted
father mounted
所以机久,你在父組件 beforeMounted 中已初始化的值一定可以通過props下發(fā)到子組件
13、vue-router切換頁面滾動條位置問題
注意:scrollBehavior只有在history.pushState可用時才有效赔嚎,而該方法僅兼容到IE10(移動端可放心使用)
const router = new VueRouter({
routes,
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
if (from.meta.keepAlive) { // 通過meta屬性精細控制
from.meta.savedPosition = document.body.scrollTop;
}
return { x: 0, y: to.meta.savedPosition || 0 }
}
}
})
14膘盖、vue庫的引入問題
vue提供眾多版本庫文件,在使用*.vue單文件組件的開發(fā)模式時尽狠,只需引入vue.runtime.min.js即可衔憨,該庫體積最小,不過要注意初始化vue實例時袄膏,不能用template選項,而應該換為render掺冠,其他組件中的template會被vue-loader轉化為類似h=>h(Component)這種形式沉馆,本質上是將模板編譯的時機從運行時轉移到了編譯時(只有初始化時不能用template選項,因為vue-loader 和 vue 都無法識別)
new Vue({
el: '#app',
router,
render: h => h(App)
})
// webpack對應修改:
alias: {
'vue$': 'vue/dist/vue.runtime.min.js'
}
15德崭、三種路由鉤子執(zhí)行順序問題,
全局:beforeEach斥黑,beforeResolve,afterEach
組件:beforeRouteEnter眉厨,beforeRouteUpdate锌奴,beforeRouteLeave
路由:beforeEnter
調用要離開路由的組件守衛(wèi)beforeRouteLeave
調用全局前置守衛(wèi):beforeEach
在重用的組件里調用 beforeRouteUpdate
調用路由獨享守衛(wèi) beforeEnter。
解析異步路由組件憾股。
在將要進入的路由組件中調用beforeRouteEnter
調用全局解析守衛(wèi) beforeResolve
導航被確認鹿蜀。
調用全局后置鉤子的 afterEach 鉤子。