Vue.mixin
混入 (mixin) 提供了一種非常靈活的方式缘挑,來(lái)分發(fā) Vue 組件中的可復(fù)用功能。一個(gè)混入對(duì)象可以包含任意組件選項(xiàng)蝌数。當(dāng)組件使用混入對(duì)象時(shí)哩盲,所有混入對(duì)象的選項(xiàng)將被“混合”進(jìn)入該組件本身的選項(xiàng)。
- 定義一個(gè) mixin.js
export default mixin {
data() {
return {
name: 'mixin'
}
},
created() {
console.log('mixin...', this.name);
},
mounted() {},
methods: { //日期轉(zhuǎn)換
formatDate (dateTime, fmt = 'YYYY年MM月DD日 HH:mm:ss') {
if (!dateTime) {
return ''
}
moment.locale('zh-CN')
dateTime = moment(dateTime).format(fmt)
return dateTime
}
}
}
- 在vue文件中使用mixin
import '@/mixin'; // 引入mixin文件
export default {
mixins: [mixin], //用法
data() {
return {
userName: "adimin",
time: this.formatDate(new Date()) //這個(gè)vue文件的數(shù)據(jù)源data里面的time就是引用混入進(jìn)來(lái)的方法
}
}
}
- 或者在全局中使用在main.js中滓侍,所有頁(yè)面都能使用了
import mixin from './mixin'
Vue.mixin(mixin)
合并選項(xiàng)
當(dāng)組件和混入對(duì)象含有同名選項(xiàng)時(shí)密浑,這些選項(xiàng)將以恰當(dāng)?shù)姆绞竭M(jìn)行“合并”。
data對(duì)象在內(nèi)部會(huì)進(jìn)行遞歸合并粗井,并在發(fā)生沖突時(shí)以組件數(shù)據(jù)優(yōu)先尔破。
同名鉤子函數(shù)將合并為一個(gè)數(shù)組街图,因此都將被調(diào)用±凉梗混入對(duì)象的鉤子將在組件自身鉤子之前調(diào)用餐济。
值為對(duì)象的選項(xiàng),例如 methods胆剧、components 和 directives絮姆,將被合并為同一個(gè)對(duì)象。兩個(gè)對(duì)象鍵名沖突時(shí)秩霍,取組件對(duì)象的鍵值對(duì)篙悯。
Vue.extend
Vue.extend 屬于 Vue 的全局 API。它使用基礎(chǔ) Vue 構(gòu)造器铃绒,創(chuàng)建一個(gè)“子類(lèi)”鸽照。參數(shù)是一個(gè)包含組件選項(xiàng)的對(duì)象。如下:
<div id="app"></div>
var Profile = Vue.extend({
template: '<p>{{firstName}} {{lastName}}</p>',
data: function () {
return {
firstName: 'Walter',
lastName: 'White'
}
}
})
- 創(chuàng)建 Profile 實(shí)例颠悬,并掛載到一個(gè)元素上矮燎。
new Profile().$mount('#app')
應(yīng)用實(shí)例
我們常用 Vue.extend 封裝一些全局插件,比如 toast赔癌, diolog 等诞外。
下面以封裝一個(gè) toast 組件為例。
1.編寫(xiě)組件
根據(jù)傳入的 type 確定彈窗的類(lèi)型(成功提示灾票,失敗提示峡谊,警告,加載刊苍,純文字)
設(shè)置彈窗消失的時(shí)間
<template>
<div>
<transition name="fade">
<div class="little-tip" v-show="showTip">
<img src="/success.png" alt="" width="36" v-if="type=='success'" />
<img src="/fail.png" alt="" width="36" v-if="type=='fail'" />
<img src="/warning.png" alt="" width="36" v-if="type=='warning'" />
<img src="/loading.png" alt="" width="36" v-if="type=='loading'" class="loading" />
<span>{{msg}}</span>
</div>
</transition>
</div>
</template>
<script>
export default {
data() {
return {
showTip: true,
msg: '',
type: ''
}
},
mounted() {
setTimeout(() => {
this.showTip = false
}, 1500)
}
}
</script>
<style lang="less" scoped>
/* 樣式略 */
</style>
2.利用 Vue.extend 構(gòu)造器把 toast 組件掛載到 vue 實(shí)例下
import Vue from 'vue'
import Main from './toast.vue'
let Toast = Vue.extend(Main)
let instance
const toast = function(options) {
options = options || {}
instance = new Toast({
data: options
})
instance.vm = instance.$mount()
document.body.appendChild(instance.vm.$el)
return instance.vm
}
export default toast
3.在 main.js 引入 toast 組價(jià)并掛載在 vue 原型上
import Vue from 'vue'
import toast from './components/toast'
Vue.prototype.$toast = toast
4.在項(xiàng)目中調(diào)用
this.$toast({ msg: '手機(jī)號(hào)碼不能為空' })
this.$toast({
msg: '成功提示',
type: 'success'
})
- Vue.extend 和 Vue.component 的區(qū)別
component是需要先進(jìn)行組件注冊(cè)后靖苇,然后在 template 中使用注冊(cè)的標(biāo)簽名來(lái)實(shí)現(xiàn)組件的使用。Vue.extend 則是編程式的寫(xiě)法班缰。
控制component的顯示與否贤壁,需要在父組件中傳入一個(gè)狀態(tài)來(lái)控制或者在組件外部用 v-if/v-show 來(lái)實(shí)現(xiàn)控制,而 Vue.extend 的顯示與否是手動(dòng)的去做組件的掛載和銷(xiāo)毀埠忘。
Vue.directive
注冊(cè)或獲取全局指令脾拆。指令定義函數(shù)提供了幾個(gè)鉤子函數(shù)(可選):
bind: 只調(diào)用一次,指令第一次綁定到元素時(shí)調(diào)用莹妒,可以定義一個(gè)在綁定時(shí)執(zhí)行一次的初始化動(dòng)作名船。
inserted: 被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用(父節(jié)點(diǎn)存在即可調(diào)用,不必存在于 document 中)旨怠。
update: 被綁定元素所在的模板更新時(shí)調(diào)用渠驼,而不論綁定值是否變化。通過(guò)比較更新前后的綁定值鉴腻。
componentUpdated: 被綁定元素所在模板完成一次更新周期時(shí)調(diào)用迷扇。
unbind: 只調(diào)用一次百揭, 指令與元素解綁時(shí)調(diào)用。
應(yīng)用實(shí)例
下面封裝一個(gè)復(fù)制粘貼文本的例子蜓席。
1.編寫(xiě)指令 copy.js
const vCopy = {
bind (el, { value }) {
el.$value = value // 用一個(gè)全局屬性來(lái)存?zhèn)鬟M(jìn)來(lái)的值
el.handler = () => {
if (!el.$value) {
alert('無(wú)復(fù)制內(nèi)容')
return
}
// 動(dòng)態(tài)創(chuàng)建 textarea 標(biāo)簽
const textarea = document.createElement('textarea')
// 將該 textarea 設(shè)為 readonly 防止 iOS 下自動(dòng)喚起鍵盤(pán)器一,同時(shí)將 textarea 移出可視區(qū)域
textarea.readOnly = 'readonly'
textarea.style.position = 'absolute'
textarea.style.left = '-9999px'
// 將要 copy 的值賦給 textarea 標(biāo)簽的 value 屬性
textarea.value = el.$value
// 將 textarea 插入到 body 中
document.body.appendChild(textarea)
// 選中值并復(fù)制
textarea.select()
// textarea.setSelectionRange(0, textarea.value.length);
const result = document.execCommand('Copy')
if (result) {
alert('復(fù)制成功')
}
document.body.removeChild(textarea)
}
// 綁定點(diǎn)擊事件,就是所謂的一鍵 copy 啦
el.addEventListener('click', el.handler)
},
// 當(dāng)傳進(jìn)來(lái)的值更新的時(shí)候觸發(fā)
componentUpdated (el, { value }) {
el.$value = value
},
// 指令與元素解綁的時(shí)候厨内,移除事件綁定
unbind (el) {
el.removeEventListener('click', el.handler)
}
}
export default vCopy
2.注冊(cè)指令
import copy from './copy'
// 自定義指令
const directives = {
copy
}
// 這種寫(xiě)法可以批量注冊(cè)指令
export default {
install (Vue) {
Object.keys(directives).forEach((key) => {
Vue.directive(key, directives[key])
})
}
}
3.在 main.js 引入并 use
import Vue from 'vue'
import Directives from './JS/directives'
Vue.use(Directives)
這樣就可以在項(xiàng)目直接用 vCopy 指令了祈秕。