在平常開發中,可能只須要一兩個插件就能夠完成對系統開發須要。若是引入整個組件庫,最後打包項目體積比較大。例如
element-ui
中的message
提示組件等。下面會在vuejs
官網提供的插件建議,根據四種方法開發不一樣的vuejs
插件javascript
插件一般用來爲 Vue 添加全局功能。插件的功能範圍沒有嚴格的限制——通常有下面幾種:css
Vue.prototype
上實現。element-ui
),提供本身的 API,同時提供上面提到的一個或多個功能。如vue-routerinitUse
安裝插件函數在vuejs
源碼src/core/global-api/use.js
中能夠閱讀到vuejs
插件須要export
一個install
函數。vue
使用indexOf
檢測插件是否已註冊,防止插件的重複註冊。html
import { toArray } from '../util/index'
export function initUse (Vue: GlobalAPI) {
Vue.use = function (plugin: Function | Object) {
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
// additional parameters
const args = toArray(arguments, 1)
args.unshift(this)
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
plugin.apply(null, args)
}
installedPlugins.push(plugin)
return this
}
}
複製代碼
directive
方式開發插件一個指令定義對象能夠提供以下幾種鉤子函數(都爲可選):vue
bind
:只調用一次,指令第一次綁定到元素時調用。在這裏能夠進行一次性初始化設置inserted
:被綁定元素插入父節點時調用(僅保證父節點存在,但不必定已被插入文檔中)。update
:所在組件的VNode
更新時調用,可是可能發生在其子VNode
更新以前。指令值可能發生了變化,也可能沒有發生變華。componentUpdated
:指令所在組件的VNode
及子VNode
所有更新後調用unbind
:只調用一次,指令與元素解綁時調用指令鉤子函數會被傳入如下參數:java
el
:指令所綁定的元素,能夠用來直接操做DOM
binding
:一個對象,包含如下屬性
name
:指令名,不包含v-
前綴value
:指令的綁定值,例如:v-my-direactive= "1+1"
中表達式值爲2
oldValue
:指令綁定的前一個值,僅在 update
和componentUpdated
鉤子中可用。不管值是否改變均可用。expression
:字符串形式的指令表達式。例如 v-my-directive="1 + 1"
中,表達式爲 "1 + 1"
。arg
:傳給指令的參數,可選。例如 v-my-directive:foo
中,參數爲 foo
。modifiers
:一個包含修飾符的對象。例如:v-my-directive.foo.bar
中,修飾符對象爲 { foo: true, bar: true }
上面說明文檔是在vuejs
官方文檔教程中摘抄的,能夠經過這裏閱讀而更多react
v-time
插件vuejs
插件須要提供一個install
函數向外暴露。在src/directives/time
下的index.js
中一共開發了三個不一樣關於time
的指令v-time
、v-clock
、v-down
github
import Time from "./time.js";
export default {
install(Vue, options = {}) {}
};
複製代碼
v-time
顯示當前時間指令v-time
獲取一個傳入的時間戳值binding.value
,而後返回一個符合格式的time
值vue-router
import Time from "./time.js";
export default {
install(Vue, options = {}) {
Vue.directive("time", {
bind(el, binding) {
el.innerHTML = el.innerHTML ? el.innerHTML : el.textContent;
el.innerHTML = Time.getFormatTime(binding.value);
}
});
}
};
複製代碼
v-clock
時鐘指令 v-clock
每隔一秒獲取一次當前時間實現時鐘的效果。import Time from "./time.js";
export default {
install(Vue, options = {}) {
Vue.directive("clock", {
bind(el, binding) {
el.timeout = setInterval(function() {
const value = Date.now();
el.innerText = Time.getFormatTime(value);
}, 1000);
},
unbind() {
clearInterval(el.timeout);
delete el.timeout;
}
});
}
};
複製代碼
v-down
給定時間倒計時指令v-down
傳入將來的一個時間戳,計算倒計時間。express
import Time from "./time.js";
export default {
install(Vue, options = {}) {
Vue.directive("down", {
bind(el, binding) {
const value = binding.value;
el.__handle__ = setInterval(() => {
if (Time.getDownTime(value).clear) {
clearInterval(el.__handle__);
el.innerText = Time.getDownTime(value).time;
return;
}
el.innerText = Time.getDownTime(value);
}, 1000);
},
unbind() {
clearInterval(el.__timeout__);
delete el.__timeout__;
}
});
}
};
複製代碼
getFormatTime
是YYYY-MM-DD hh:mm:ss
時間格式的函數,computeTime
是計算傳入時間與當前時間差值得格式時間。
export default {
getFormatTime(value) {
if (isNaN(value)) {
console.error("the value is not a number");
return;
}
const date = new Date(value);
const year = date.getFullYear();
const month = this.format(date.getMonth() + 1);
const day = this.format(date.getDate());
const hours = this.format(date.getHours());
const minutes = this.format(date.getMinutes());
const seconds = this.format(date.getSeconds());
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
},
format(value) {
return value > 9 ? value : "0" + value;
},
getDownTime(value) {
const date = new Date(value);
const now = Date.now();
const count = (date - now) / 1000;
if (count <= 0) {
return {
clear: true,
time: "00天00時00分00秒"
};
}
return this.computeTime(count);
},
computeTime(value) {
const day = this.format(Math.floor(value / 86400));
const hours = this.format(Math.floor((value % 86400) / 3600));
const minutes = this.format(Math.floor(((value % 86400) % 3600) / 60));
const seconds = this.format(Math.floor(((value % 86400) % 3600) % 60));
return `${day}天${hours}時${minutes}分${seconds}秒`;
}
};
複製代碼
//在入口文件main.js
import time from 'vill-directive'
Vue.use(time);
//其餘組件
<template>
<div class="demo">
<h4>v-time 指令</h4>
<span v-time="now"></span>
<h4>v-clock 指令</h4>
<span v-clock></span>
<h4>v-down 指令</h4>
<span v-down="time"></span>
</div>
</template>
<script>
export default {
name: "Demo",
data() {
return {
time: "2019-03-20 13:16:00"
};
},
computed: {
now() {
return Date.now();
}
}
};
</script>
<style scoped></style>
複製代碼
prototype
方式開發插件經過prototype
方式開發插件,是在vue
的原型上添加屬性或者方法。例如:
// 添加實例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 邏輯...
}
複製代碼
message
提示插件prototype
在src/lib/vill-message
中的index.js
中,定義了vuejs
的install
函數,主要是把方法和屬性添加到vue
的原型上。
import Message from './main.js';
export default {
install(Vue,options={}){
Vue.prototype.$message = Message;
}
};
複製代碼
DOM
元素並進行掛載Vue.extend
使用基礎 Vue 構造器,建立一個「子類」。options
是能夠傳入的參數配置。而後對數據進行手動掛載$mount
,最後加入document
文檔中。
import Vue from "vue";
import MessageTpl from "./message.vue";
const NoticeConstructor = Vue.extend(MessageTpl);
let nId = 1;
const Message = options => {
if(JSON.stringify(options) == undefined)
return false
let id = "notice-" + nId++;
options = options || {};
if (typeof options === "string") {
options = {
message: options
};
}
const NoticeInstance = new NoticeConstructor({
data: options
});
NoticeInstance.id = id;
NoticeInstance.vm = NoticeInstance.$mount();
NoticeInstance.vm.visible = true;
NoticeInstance.dom = NoticeInstance.vm.$el;
document.body.appendChild(NoticeInstance.dom);
return NoticeInstance.vm;
};
["success", "warning", "info", "error"].forEach(type => {
Message[type] = options => {
if (typeof options === "string") {
options = {
message: options
};
}
options.type = type;
return Message(options);
};
});
export default Message;
複製代碼
message.vue
模板message
是傳入的參數值,是提示的內容值;Icon
是一個圖標組件。
<template>
<transition name="vill-message-fade">
<div v-if="visible" :class="wrapClasses">
<Icon :iconType="type"></Icon>
<span :class="[prefixCls+'-content']">
{{message}}
</span>
</div>
</transition>
</template>
<script>
const prefixCls = "vill-message";
import Icon from "../vill_icon/index.js";
export default {
name: "vill-message",
data() {
return {
visible: false,
type: "info",
message: "",
duration: 1500,
prefixCls: prefixCls
};
},
components: {
Icon: Icon
},
computed: {
wrapClasses() {
return [`${prefixCls}`, `${prefixCls}-${this.type}`];
}
},
methods: {
setTimer() {
setTimeout(() => {
this.close(); // 3000ms以後調用關閉方法
}, this.duration);
},
close() {
this.visible = false;
setTimeout(() => {
this.$destroy(true);
this.$el.parentNode.removeChild(this.$el); // 從DOM裏將這個組件移除
}, 500);
}
},
mounted() {
this.setTimer(); // 掛載的時候就開始計時,3000ms後消失
}
};
</script>
複製代碼
Icon
圖標組件採起的render
函數進行渲染,根據傳入的參數success
、error
、warning
、info
,直接渲染同名SVG
圖標(有點取巧),這樣避免v-if
和v-else
的多個條件判斷的作法。
<script>
const prefixCls = "vill-icon";
export default {
name: "vill-icon",
data() {
return {
prefixCls: prefixCls
};
},
props: {
iconType: {
type: String,
default: "info"
}
},
render: function(h) {
return h(
"i",
{
attrs: {
class: `${this.prefixCls}`
}
},
[
h("img", {
attrs: {
src: require(`./assets/${this.iconType}.svg`),
class: "icon"
}
})
]
);
}
};
</script>
<style scoped lang="scss">
.vill-icon {
display: inline-block;
width: 20px;
height: 20px;
color: #fff;
overflow: hidden;
border-radius: 50%;
margin: 0 15px;
& .icon {
display: inline-block;
width: 100%;
height: 100%;
}
}
</style>
複製代碼
//在main入口
import message from 'vill-message'
Vue.use(message);
//在其餘vue文件
this.$message({
duration:2000,
type:'success',
message:'hello vill-message'
});
this.$message({
duration:2000,
type:'error',
message:'hello vill-message'
});
this.$message.success("hello vill-message");
this.$message.error("hello vill-message");
this.$message.warning("hello vill-message");
this.$message.info("hello vill-message");
複製代碼
Mixin
開發插件"混入 (mixin) 提供了一種很是靈活的方式,來分發 Vue 組件中的可複用功能。一個混入對象能夠包含任意組件選項。當組件使用混入對象時,全部混入對象的選項將被「混合」進入該組件自己的選項。"
mixin
使用比較簡單,能夠定義經常使用method
或者生命週期函數在Minxin
中,而後混入各組件之中。
// 定義一個混入對象
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
// 定義一個使用混入對象的組件
var Component = Vue.extend({
mixins: [myMixin]
})
var component = new Component() // => "hello from mixin!"
複製代碼
Vue
全局方法或者屬性方式添加vue
全局方法和屬性開發vue
插件跟prototype
比較相似,差異只是在把屬性或者方法綁定在prototype
改爲直接綁定在vue
實例上。以下所示:
Vue.$myMethod = function (methodOptions) {
// 邏輯...
}
複製代碼
其餘message.vue
組件模板徹底和prototype
原型上同樣。
若是以爲喜歡能夠給個贊~
vill-directive地址:github.com/Harhao/vill…
vill-message地址:github.com/Harhao/vill…