segmentfault 會及時更新,這個定期更新杏瞻。
記錄一些小技巧和踩過的坑
1. props 帶不帶冒號的區(qū)別
<child1 ref="child1" msg="{name:'bill'}"></child1>
<child1 ref="child1" :msg="{name:'bill'}"></child1>
首先冒號是v-bind的縮寫熬丧,不帶冒號后面是字符串曼振,帶了冒號就是數(shù)據(jù)綁定,引號里面的內(nèi)容是變量或者表達式,
組件內(nèi)不能修改props的值昔园,同時修改的值也不會同步到組件外層扁瓢,即調(diào)用組件方不知道組件內(nèi)部當前的狀態(tài)是什么
vue 組件props傳遞時,為什么有時候需要加冒號堕战,有時候不需要坤溃?
如何在Vue2中實現(xiàn)組件props雙向綁定
2. computed屬性,可以set嘱丢,但是設(shè)置的是data返回的數(shù)據(jù)薪介,不能設(shè)置自身。
如果計算屬性是對象的話越驻,可以設(shè)置他的屬性汁政。
3. 組件的生命周期函數(shù)是在template標簽里的數(shù)據(jù)發(fā)生變化時候觸發(fā)update
數(shù)據(jù)可能更新了,但是沒有綁定到dom上面的話缀旁,不會調(diào)用update鉤子函數(shù)记劈。
4. 給變data的第二季屬性的值,data不會更新并巍,導(dǎo)致組件不會更新
所以在這個時候應(yīng)該用Object.assign()重新生成新的對象目木。第一級屬性值更新的話,data是更新的懊渡!
5. 動態(tài)綁定style的話刽射,后面的樣式值不能加分號
style = {
color: "rgb(66, 180, 232)"
};
//下面渲染不出來
style = {
color: "rgb(66, 180, 232)";
};
6. filter 過濾器
vue2.0 的時候把過濾器移除了,現(xiàn)在2.10又加了上去距贷,
定義filter過濾器:
寫在實例Vue內(nèi)部的是局部過濾器柄冲,
new Vue({
filters:{
formatMoney: function (value){
return "$"+value.toFixed(2);
}
}
})
寫在外部的是全局過濾器
Vue.filter("money", function (vaule, type) {
return "¥" + vaule.toFixed(2) + type;
})
組件內(nèi)調(diào)用:
<span v-text="message | wrap 'before' 'after'"></span>//1.x的寫法,2直接wrap('before','after')調(diào)用
Vue.filter('wrap', function (value, begin, end) {
return begin + value + end
})
補充下:一個豎線 | 在js中是二進制運算
7. watch監(jiān)測對象或者數(shù)組忠蝗,不是替換對象或者數(shù)組现横,newVal和oldVal是同一個值。
注意:在變異(不是替換)對象或數(shù)組時,舊值將與新值相同戒祠,因為它們的引用指向同一個對象/數(shù)組骇两。Vue 不會保留變異之前值的副本。
8. 為組件綁定原生事件
有時候姜盈,你可能想在某個組件的根元素上監(jiān)聽一個原生事件低千。可以使用 .native 修飾 v-on 馏颂。例如:
<my-component v-on:click.native="doTheThing"></my-component>
9. 2.1.6computed在beforeMount前面執(zhí)行的示血,vue2.2.1剛好相反
10. v-for和v-if在同一個標簽使用的話,v-for的優(yōu)先級高于v-if
如果在同一標簽使用救拉,v-if就是用來過濾v-for里面的數(shù)據(jù)的难审,先走if的話用template套在外面
今天并列使用的時候遇到的巨坑:
<topic v-for="(topic,idx) in topics" :model="topic" :showIdx="false" :clickHandler="handleTopicClick" v-if="mode==0"/>
<school-topic v-for="t in topics" :model="t" :style="showStyle(t)" :clickHandler="handleTopicClick" v-else />
結(jié)果topics只有三條數(shù)據(jù),但是渲染出9條數(shù)據(jù)亿絮,官網(wǎng)說的很清楚:v-for with v-if
11.keep-alive
緩存組件在內(nèi)存中告喊,再次進入該頁面不會重新渲染,用于保存頁面的原始狀態(tài)
<template>
<div id="app">
<keep-alive include="SelectTopics">
<router-view></router-view>
</keep-alive>
</div>
</template>
即使設(shè)置了keep-alive
組件的beforeUpdate
和updated
鉤子函數(shù)還是會調(diào)用的派昧。
activated和unactivated鉤子是在keep-alive組件里面被調(diào)用的黔姜,不是第一次進入keep-alive組件的話,調(diào)用順序是:
beforeEach
->beforeRouteEnter
->activated
->beforeUpdate
->beforeRouteEnter
的next
函數(shù)
也可以在離開頁面的時候手動銷毀改組件:
beforeRouteLeave(to, from, next) {
if (to.path === "/examcentre") {
this.$destroy();
}
next();
}
//或者
deactivated: function () {
console.log(4)
this.$destroy();
},
有時候根據(jù)需求(比如該組件是復(fù)用的)需要在再次進入該頁面的時候重新從后臺獲取數(shù)據(jù)蒂萎,那么可以在activated
鉤子函數(shù)中請求數(shù)據(jù)來update頁面秆吵。
vue.js 能否設(shè)置某個組件不被keep-alive?
vue2.0 keep-alive最佳實踐
Vue如何做到前進刷新數(shù)據(jù),后退不刷新數(shù)據(jù)呢?
<keep-alive>組件緩存問題
Vue路由開啟keep-alive時的注意點
vue.js+vue-router+webpack keep-alive用法
瀏覽器的前進回退并不會走dom綁定的前進后退的事件
所以要想清除vuex state里面的數(shù)據(jù)的話,可以放在beforeRouteLeave
里面做處理岖是。
this.$store.commit("SET_PAPERATTRIBUTE", {});
彈窗組件
mint-ui 中的Toast MessageBox Indicator 調(diào)用的方式是Toast('提示信息');
或者在全局引入mint-ui然后再組件里this.$toast("提示信息")
,這種方式和我們普通的引入組件的方式都不同帮毁,通常我們是在模板里直接將組件放到模板里面,這就意味著父組件在render的時候豺撑,子組件也被render到了dom里面:
<template>
<div class="my-set-attr-wrap">
<set-attribute ref="setMyAttr" :style="setAttrStyle" :model="attributeModel" />
</div>
</template>
this.$toast("提示信息")
這種是在函數(shù)中調(diào)用烈疚,肯定也是要render到dom里面的,改咋辦呢聪轿?查看了mint-ui的實現(xiàn)方式:document.body.appendChild(instance.$el);
目錄:
TopicDetailPopup.vue文件就是普通的vue寫法爷肝,
index.js:
這里考慮到每次彈出層不能都去創(chuàng)建新的組件,我們只需要將組件內(nèi)的數(shù)據(jù)更新就可以了陆错,dom也不需要刪除灯抛,然后再創(chuàng)建,就用到了單例模式音瓷,這邊的instance是在父組件沒銷毀之前都是存在的对嚼,每次只是更新了組件的數(shù)據(jù),為啥沒被銷毀呢绳慎,這邊形成了一個閉包:
調(diào)用:
import TopicDetailPopup from '../topicDetailPopup/index.js'
TopicDetailPopup.open({
detail: res.data
});
但是這個地方出現(xiàn)個問題this.$store
現(xiàn)在為undefined
纵竖,應(yīng)該是因為這個組件是直接new實例化的漠烧,而不是通過根組件嵌套的,
main.js
new Vue({
router: router,
store,
render: h => h(App)
}).$mount("#app");
store注冊在根組件里面靡砌,而彈窗組件沒有和根組件關(guān)聯(lián)已脓,所以拿不到store。
要是能將彈窗組件插入其他組件問題就能解決了通殃,貌似現(xiàn)在API沒有提供這樣的接口度液,vue2動態(tài)添加組件的話可以用render函數(shù),可以我現(xiàn)在的彈窗組件是模板的形式画舌,也可以動態(tài)插入到父組件堕担,<component :is="componentId"></component>
且需要在components里面引用,這樣又回到了模板語法了骗炉。
彈窗的弊端:
vue-devtools 沒法檢測到組件照宝,也沒法檢測到vuex,對于webapp來說返回鍵沒法使用句葵,關(guān)閉不了當前的彈窗,造成上面的問題都是由于沒用使用router兢仰。
對于安卓手機返回鍵沒法使用可以采用曲線救國的方式乍丈,禁用返回鍵,js沒法直接操作安卓返回鍵把将,但是可以使用beforeRouteLeave
轻专,使得返回鍵沒有效果,
beforeRouteLeave(to, from, next) {
if (this.popupVisible) {//彈窗顯示的話察蹲,路由沒法跳轉(zhuǎn)
next(false);
} else {
next(true);
}
}
彈窗的好處:
在當前頁面直接彈出请垛,這樣可以保存當前頁面的數(shù)據(jù)和滾動條的位置,還有就是組件復(fù)用的話洽议,直接關(guān)閉彈窗宗收,不需要根據(jù)不同的頁面去回退或者前進到特定的頁面。
使用的是vue2.0亚兄,如何動態(tài)添加組件混稽。例如實現(xiàn)點擊A按鈕添加aTest組件,點擊B按鈕添加bTest組件审胚。
:model和v-model的區(qū)別
v-model通常用于input的雙向數(shù)據(jù)綁定<input v-model="parentMsg">
匈勋,也可以實現(xiàn)子組件到父組件數(shù)據(jù)的雙向數(shù)據(jù)綁定:
首先說說v-model的用法:
model.vue
<template>
<div>
父:
<input type="text"
v-model="msg">
<child v-model="msg"></child>
</div>
</template>
<script>
import child from './modelChild.vue'
export default {
name: "model",
props: {
},
components: {
child
},
data() {
return {
msg: "ppp"
}
},
methods: {
}
}
</script>
<style lang="less">
</style>
modelChild.vue
<template>
<div>
子:
<input type="text"
@input="handleInput"
class="text"
:value="value">
</div>
</template>
<script>
export default {
name: "modelChild",
props: ["value"],
methods: {
handleInput(e) {
this.$emit("input", e.target.value)
}
}
}
</script>
<style lang="less">
.text {
height: 20px;
width: 200px;
}
</style>
無論改變父組件還是子組件的輸入框,value和msg的值都會改變膳叨,兩個輸入框的值也就同時改變了洽洁。
:model和v-model的區(qū)別
:model是v-bind:model的縮寫,<child :model="msg"></child>
這種只是將父組件的數(shù)據(jù)傳遞到了子組件,并沒有實現(xiàn)子組件和父組件數(shù)據(jù)的雙向綁定菲嘴。當然引用類型除外饿自,子組件改變引用類型的數(shù)據(jù)的話碎浇,父組件也會改變的。
Vue.component注冊全局組件
查看vue-router源碼的時候發(fā)現(xiàn)install.js里面兩句:
Vue.component('router-view', View)
Vue.component('router-link', Link)
這兩句就是全局注冊了這兩個組件,
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
這三步后璃俗,在組件里直接使用<router-view></router-view>
而不用先import再使用奴璃。
在mint-ui里也是相同的做法:
src/index.js
const install = function(Vue) {
if (install.installed) return;
Vue.component(Header.name, Header);//注冊全局組件
Vue.component(Button.name, Button);
Vue.use(InfiniteScroll);//使用指令插件
Vue.use(Lazyload, {
loading: require('./assets/loading-spin.svg'),
try: 3
});//使用指令插件或lazy-component
Vue.$messagebox = Vue.prototype.$messagebox = MessageBox;
Vue.$toast = Vue.prototype.$toast = Toast;
Vue.$indicator = Vue.prototype.$indicator = Indicator;
};
后面的Vue.$toast = Vue.prototype.$toast = Toast;
使得我們可以在組件中直接調(diào)用this.$toast("提示信息")
組件上寫class
之前在寫react的時候是不可以這么做的,今天查看了popup.vue的時候發(fā)現(xiàn)vue是可以這么干的城豁,直接渲染到了組件的根元素上面苟穆。用在組件上
Boolean類型的props可以直接定義:
props: {
fixed: Boolean,
value: {}
}
數(shù)據(jù)更新頁面沒刷新
今天在concat兩個數(shù)組的時候發(fā)現(xiàn)數(shù)據(jù)更新了,頁面并沒有刷新唱星,debug看了下數(shù)據(jù)雳旅,concat的數(shù)據(jù)沒有g(shù)et set屬性訪問器,導(dǎo)致后來push的數(shù)據(jù)也沒有屬性訪問器间聊。之前沒有細看文檔攒盈。搜了下原來push是變異方法,concat不是哎榴。
解決辦法有二:
- 使用變異方法
- 使用vue component的$set函數(shù)
看一些小伙伴的回答是data的$set方法型豁,至少vue2是沒有的。具體可查看文檔列表渲染
我的解決辦法是:
Array.prototype.push.apply(arr, item);
render函數(shù)和模板語法只能二選一
今天在模板.vue文件里加入render函數(shù)發(fā)現(xiàn)并不會執(zhí)行render函數(shù)尚蝌,原來是vue-loader
會將template
轉(zhuǎn)成render函數(shù)迎变,所以只能二選一。.vue文件如何使用render函數(shù)渲染組件
控制input只能輸入數(shù)字
<input type="number">
在pc和手機端都可以實現(xiàn)只能輸入數(shù)字飘言,可是手機端彈出的軟鍵盤里面沒有完成或者搜索按鈕衣形,搜了下,現(xiàn)在的HTML5 number的情況下并沒有支持搜索按鈕姿鸿,type='text'是有的谆吴。所以曲線救國,控制表單只能輸入數(shù)字苛预。
起初的想法是先把在
<input type='text' @input="handleInput" :value="val"/>
handleInput(e){
this.val=e.target.value.replace(/[^\d]/g,'');
}
但是這種并不會實時刷新表單的數(shù)據(jù)句狼,下面就會起作用
e.target.value=e.target.value.replace(/[^\d]/g,'');
優(yōu)雅點的寫法,用自定義指令:
//<input type="text" v-number-only />
directives: {
numberOnly: {
bind: function(el) {
el.handler = function() {
el.value = el.value.replace(/\D+/, '')
}
el.addEventListener('input', el.handler)
},
unbind: function(el) {
el.removeEventListener('input', el.handler)
}
}
},
彈出層彈出文本框獲取焦點
由于彈出層是單例模式鲜锚,所以打開彈出層只會執(zhí)行一次mounted鉤子函數(shù),我去監(jiān)聽
visible(val) {
if (val) {
this.$refs.textbox.focus();//這樣并不能使文本框獲取焦點
} else {
this.detail = null;
this.$refs.textbox.value = "";
}
}
解決辦法也是使用自定義指令
focus: {
update(el) {
el.focus();
}
}
改變v-html解析后臺返回的HTML樣式
平時在寫組件里面的樣式加上scoped
苫拍,避免樣式的全局污染芜繁,而從后臺返回的HTML無效的,解決辦法就是在組件里再加一對style標簽绒极,將樣式寫到這里骏令。