一、插件的基本使用
1.1 初识插件
Vue.use()做了什么事情?
Vue.use的作用是注册一个Vue插件(注册组件), Vue.use必须在new Vue之前使用
什么时候需要定义插件?
当某一个组件或者功能经常需要被使用到时, 我们就可以将这个组件或者功能定义成一个插件
例如: 网络加载指示器
4.插件通常用来为 Vue 添加全局功能
插件的功能范围没有严格的限制——一般有下面几种:
添加全局方法或者 property。如:vue-custom-element
添加全局资源:指令/过滤器/过渡等。如 vue-touch
通过全局混入来添加一些组件选项。如 vue-router
添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router
1.2 插件开发流程
通过 vue create name 创建好vue项目后
在src目录下新建一个名为plugins的文件夹并在该文件夹里面新建一个loading的目录,在loading目录下新建一个名为loading.vue和index.js的文件
plugins/loading/loading.vue
<template>
<div class="container">
<div class="loading"></div>
<p class="title">正在加载...</p>
</div>
</template>
<script>
export default {
name: "Loading"
}
</script>
<style scoped>
.container{
width: 200px;
height: 200px;
border-radius: 20px;
background: rgba(0,0,0,.5);
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
.container .loading{
width: 100px;
height: 100px;
border-radius: 50%;
border: 5px solid #fff;
margin: 20px auto;
border-right-color: #4fc08d;
animation: loading 2s linear infinite;
}
.container .title {
text-align: center;
color: #fff;
}
@keyframes loading {
from{
transform: rotate(0deg);
}
to{
transform: rotate(360deg);
}
}
</style>
plugins/loading/index.js
import Vue from "vue"
import Loading from "./loading"
export default {
/*
* 如果要将一个组件封装成一个插件,那么必须提供一个install方法,必须在install方法中注册当前的这个组件
*/
install() {
Vue.component(Loading.name,Loading);
}
}
main.js
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
// import Loading from "./components/Loading";
import Loading from "./plugins/loading/index";
// 注册为全局组件
// import Loading from "./components/Loading";
// Vue.component(Loading.name,Loading)
//或通过use的方式,但是先要将组件先封装成一个插件后才能
Vue.use(Loading)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
App.vue
<template>
<div id="app">
<Loading></Loading>
</div>
</template>
<script>
// import Loading from "./components/Loading";
export default {
name: 'App',
components: {
// Loading
},
data:function(){
return{
}
},
methods:{
}
}
</script>
<style scoped>
</style>
将以上代码进行优化改造:
plugins/loading/loading.vue
<template>
<div class="container" v-show="isShow">
<div class="loading"></div>
<p class="title">{{title}}</p>
</div>
</template>
<script>
export default {
name: "Loading",
data(){
return {
title: '正在加载...',
isShow: false
}
},
}
</script>
<style scoped>
.container{
width: 200px;
height: 200px;
border-radius: 20px;
background: rgba(0,0,0,.5);
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
.container .loading{
width: 100px;
height: 100px;
border-radius: 50%;
border: 5px solid #fff;
margin: 20px auto;
border-right-color: #4fc08d;
animation: loading 2s linear infinite;
}
.container .title {
text-align: center;
color: #fff;
}
@keyframes loading {
from{
transform: rotate(0deg);
}
to{
transform: rotate(360deg);
}
}
</style>
plugins/loading/index.js
import Loading from "./loading"
export default {
/*
* 如果要将一个组件封装成一个插件,那么必须提供一个install方法,必须在install方法中注册当前的这个组件
*/
install(Vue,Options) {
//1.根据组件生成构造函数
let LoadingConstructor = Vue.extend(Loading)
//2.根据构造函数创建实例对象
let LoadingInstance = new LoadingConstructor();
//3.随便创建一个标签(元素)
let oDiv= document.createElement('div');
//4.将创建好的标签添加到页面上
document.body.appendChild(oDiv);
//5.将创建好的实例对象挂载到创建好的元素上
LoadingInstance.$mount(oDiv);
// console.log(Options);
// console.log(LoadingInstance.title);
//添加初始化值
setTimeout(function () {
if(Options&&Options.title!==null&&Options.title!==undefined){
LoadingInstance.title=Options.title;
}
},2000);
//添加全局方法
Vue.showLoading=function () {
LoadingInstance.isShow = true;
};
Vue.hiddenLoading=function () {
LoadingInstance.isShow = false;
}
//添加实例方法(局部)
Vue.prototype.$showLoading=function () {
LoadingInstance.isShow = true;
};
Vue.prototype.$hiddenLoading=function () {
LoadingInstance.isShow = false;
};
}
}
main.js
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import Loading from "./plugins/loading/index";
//或通过use的方式,但是先要将组件先封装成一个插件后才能
//只要调用use方法,就会去调用其对应的install方法
Vue.use(Loading,{
title: '加载完成'
})
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
App.vue
<template>
<div id="app">
<button @click="myFn1">显示</button>
<button @click="myFn2">隐藏</button>
</div>
</template>
<script>
// import Vue from 'vue'
export default {
name: 'App',
components: {
},
data:function(){
return{
}
},
methods:{
myFn1(){
// Vue.showLoading();//全局方法
this.$showLoading();
},
myFn2(){
// Vue.hiddenLoading();//全局方法
this.$hiddenLoading();
}
}
}
</script>
<style scoped>
</style>
二、插件示例
2.1 自定义 Toast 提示框
App.vue
<template>
<div id="app">
<button @click="toastHandle">提示框</button>
</div>
</template>
<script>
export default {
name: 'App',
components: {
},
methods: {
toastHandle() {
this.$toast("toast提示框",{
duration:10000,
defaultType:"warning"
});
},
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
main.js
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import Toast from "./plugins/toast"
import "./plugins/toast/toast.css"
Vue.use(Toast);
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
plugins/toast/toast.css
.vue-toast{
position: fixed;
color: #fff;
width: 50%;
height: 150px;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
background:rgba(0, 0, 0, 0.6);
border-radius: 10px;
top: 50%;
left: 50%;
margin-left: -25%;
margin-top: -25%;
z-index:999;
}
.toast-success{
color: #fff;
}
.toast-danger{
color: #ff0000;
}
.toast-warning{
color: #ff0;
}
plugins/toast/index.js
var Toast = {}
Toast.install = function(Vue) {
let opt = {
duration: 3000,
defaultType: "success"
}
Vue.prototype.$toast = (tips, type) => {
if (type.duration) {
opt.duration = type.duration
}
if (type.defaultType) {
opt.defaultType = type.defaultType
}
let toastTpl = new Vue({
render() {
return (
<div class = {
['vue-toast', 'toast-' + opt.defaultType] } > { tips } </div>
)
}
})
let tpl = toastTpl.$mount().$el; // 创建实例,挂载到文档中
document.body.appendChild(tpl);
setTimeout(function() {
document.body.removeChild(tpl)
}, opt.duration)
}
["success", "danger", "warning"].forEach(type => {
Vue.prototype.$toast[type] = (tips) => {
return Vue.prototype.$toast(tips, type)
}
})
}
export default Toast
下面是之前多的一个项目里面用到的插件,结合自定义指令
import Tree from './src/tree.vue';
/* istanbul ignore next */
Tree.install = function(Vue) {
Vue.component(Tree.name, Tree);
};
export default Tree;
highlight.js 代码高亮指令
import Hljs from 'highlight.js';
import 'highlight.js/styles/tomorrow-night.css'; // 代码高亮风格,选择更多风格需导入 node_modules/hightlight.js/styles/ 目录下其它css文件
let Highlight = {};
// 自定义插件
Highlight.install = function (Vue) {
// 自定义指令 v-highlight
Vue.directive('highlight', {
// 被绑定元素插入父节点时调用
inserted: function(el) {
let blocks = el.querySelectorAll('pre code');
for (let i = 0; i < blocks.length; i++) {
Hljs.highlightBlock(blocks[i]);
}
},
// 指令所在组件的 VNode 及其子 VNode 全部更新后调用
componentUpdated: function(el) {
let blocks = el.querySelectorAll('pre code');
for (let i = 0; i < blocks.length; i++) {
Hljs.highlightBlock(blocks[i]);
}
}
})
};
export default Highlight;