简介
插件是为应用添加全局功能的一种强大而且简单的方式。以下是一些知名插件案例:
- 添加全局方法或者 property。如:vue-custom-element。
- 添加全局资源:指令/过滤器/过渡等。如 vue-touch。
- 通过全局混入来添加一些组件选项。如 vue-router。
- 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
- 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router。
制作
插件有一个公开方法install,所有的插件都需要使用install这个公开方。这个方法的第一个参数是Vue构造器,第二个参数是一个可选的选项对象。
// MyPlugin就是插件的名称
MyPlugin.install = function (Vue, options) {
// 通过 Vue.xxxx 添加全局方法或属性
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 通过 Vue.directive 来进行自定义指令
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 通过全局 mixin方法添加一些组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 添加实例方法,通过把它们绑定到 Vue.prototype 上实现
Vue.prototype.$myMethod = function (options) {
// 逻辑...
}
}
使用
在main.js中,需要导入插件 Xxx.js 并且通过全局方法 Vue.use() 来使用插件。例如:
//Speak.js
var Speak = {};
Speak.install = function (Vue, options) {
Vue.prototype.$words = "Hello, plugin!"
}
module.exports = Speak;
//main.js
import Vue from 'vue'
import Speak from './assets/js/speak.js' //导入插件
Vue.use(Speak) //使用插件
new Vue({
el: '#app',
})
// xxx.vue
export default {
created(){
alert(this.$words); // Hello plugin!
}
}
案例:toast插件
需求
点击按钮后触发一个toast提示,内容、位置要求可以自定义。
思路
可以在body中添加一个div来显示提示信息,然后定时清除。自定义功能通过绑定Vue.prototype时传入。
实现
首先制作了一个简单的弹出模板的js。
// plugin/toast.js
var Toast = {};
Toast.install = function(Vue, options) {
Vue.prototype.$toast = (tips) => {
// 1.指定模板
let toastTpl = Vue.extend({
template: '<div class="vue-toast">' + tips + '</div>',
});
// 2.创建实例挂载,dom保存到变量
let tpl = new toastTpl().$mount().$el;
// 3、把创建的dom添加到#app中
document.getElementById("app").appendChild(tpl);
// 4.延迟2.5秒后移除该dom
setTimeout(function() {
document.getElementById("app").removeChild(tpl);
}, 2500)
}
}
export default Toast;
//main.js
import Toast from './plugin/toast.js'
Vue.use(Toast)
// App.vue
<template>
<div id="app">
<button @click="jump()">弹出</button>
</div>
</template>
<script>
export default {
methods: {
jump() {
this.$toast("这是我自己的写的吐司");
}
}
}
</script>
运行发现:
解决方案1(不推荐):
在根目录下新建一个新的vue.config.js的文件,添加下面内容重启serve。由于runtime-only 比 runtime-compiler高效,所以不推荐此方案。
module.exports = {
runtimeCompiler: true
}
解决方案2:
把插件里的 template 用 render 方式展现。
// plugin/toast.js
import toastTemp from './toast.vue'
var Toast = {};
Toast.install = function(Vue, options) {
Vue.prototype.$toast = (tips, position) => {
let toastTpl = Vue.extend({
// 1、指定模板
render: h => h(toastTemp)
});
// 2、创建实例挂载,dom保存到变量
let tpl = new toastTpl().$mount().$el;
// 3、把创建的dom添加到#app中
document.getElementById("app").appendChild(tpl);
//4、 延迟2.5秒后移除该dom
setTimeout(function() {
document.getElementById("app").removeChild(tpl);
}, 2500)
}
}
export default Toast;
// plugin/toast.vue
<template>
<transition name="fade">
<div class="vue-toast" v-show="show">
{{tips}}
</div>
</transition>
</template>
<script>
export default {
props: ['tips'],
}
</script>
按照上面的办法已经可以正常添加dom了,但也仅仅是达到了“在页面添加dom,2.5秒后移除”的效果,没有加入位置、动画、样式等,接下来将其补全,完整代码如下。
插件相关:
// plugin/toast.js
import toastTemp from './toast.vue'
var Toast = {};
Toast.install = function(Vue, options) {
Vue.prototype.$toast = (tips, position) => {
let toastTpl = Vue.extend({
// 1、指定模板
render: h => h(toastTemp, {
//render的第二个参数用于传参
//传递属性
props: {
tips
},
//相当于v-bind:class
class: {
top: position == 'top',
center: position == 'center',
bottom: position == 'bottom'
}
})
});
// 2、创建实例挂载,dom保存到变量
let tpl = new toastTpl().$mount().$el;
// 3、把创建的dom添加到#app中
document.getElementById("app").appendChild(tpl);
//4、 延迟2.5秒后移除该dom
setTimeout(function() {
document.getElementById("app").removeChild(tpl);
}, 2500)
}
}
export default Toast;
// plugin/toast.vue
<template>
<transition name="fade">
<div class="vue-toast" v-show="show">
{{tips}}
</div>
</transition>
</template>
<script>
export default {
props: ['tips'],
data() {
return {
show: false
}
},
mounted() {
this.show = true;
setTimeout(() => {
this.show = false;
}, 2000);
}
}
</script>
<style>
.vue-toast {
position: absolute;
padding: 8px 10px;
background: #000;
opacity: 0.9;
color: #FFF;
border-radius: 8px;
}
.top {
top: 20px;
left: 50%;
transform: translateX(-50%);
}
.center {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.bottom {
bottom: 20px;
left: 50%;
transform: translateX(-50%);
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>
调用相关:
// main.js
import Toast from './plugin/toast.js'
Vue.use(Toast)
// App.vue
<template>
<div id="app">
<button @click="jump()">弹出</button>
</div>
</template>
<script>
export default {
methods: {
jump() {
this.$toast("这是我自己的写的吐司", 'bottom');
}
}
}
</script>
运行:
相关资料
Vue-render函数的三个参数
对Vue中 runtime-compiler 和 runtime-only 两种模式的理解