插件介绍
插件通常会为 Vue 添加全局功能。插件的范围没有限制——一般有下面几种:
Vue.js 的插件应当有一个公开方法 install
。这个方法的第一个参数是 Vue
构造器,第二个参数是一个可选的选项对象:
- MyPlugin.install = function (Vue, options) {
- // 1. 添加全局方法或属性
- Vue.myGlobalMethod = function () {
- // 逻辑...
- }
- // 2. 添加全局资源
- Vue.directive('my-directive', {
- bind (el, binding, vnode, oldVnode) {
- // 逻辑...
- }
- ...
- })
- // 3. 注入组件
- Vue.mixin({
- created: function () {
- // 逻辑...
- }
- ...
- })
- // 4. 添加实例方法
- Vue.prototype.$myMethod = function (methodOptions) {
- // 逻辑...
- }
- }
使用方式很简单,通过全局方法Vue.use()来使用插件。
下面开发一个简单的在控制台打印消息插件,新建一个toast.js:
- var Toast = {};
- Toast.install = function (Vue, options) {
- Vue.prototype.$msg = 'Hello World';
- }
- export default Toast;
在main.js中引入该toast.js并使用vue.use()安装该toast插件:
- import Vue from 'vue';
- import Toast from './toast.js';
- Vue.use(Toast);
然后我们在任意vue页面就可以调用:
- export default {
- mounted(){
- console.log(this.$msg); // Hello World
- }
- }
开发vue-toast插件
该插件实现的效果:
- 1.提示内容可以显示在不同的位置(顶部、底部、中间),调用方式this.$toast.top('填写的提示内容')、this.$toast.center('填写的提示内容')、this.$toast.bottom('填写的提示内容');
- 2.通过this.$toast('填写的提示内容')调用该插件,默认展示在底部;
- 3.toast有默认的展示持续时间,也可配置toast展示的持续时间。
toast.js实现代码如下:
- let Toast = {};
- Toast.install = function(Vue,options) {
- let opts = {
- type: 'bottom', // 显示位置
- duration: 2500 // 持续时间
- }
- for(let prop in options) {
- if(options.hasOwnProperty(prop)) {
- opts[prop] = options[prop];
- }
- }
-
- Vue.prototype.$toast = (tips,type) => {
- if(type) {
- opts.type = type;
- }
- if(document.getElementsByClassName('vue-toast').length) {
- return false;
- }
- let ToastEl = Vue.extend({
- template: `<div class="vue-toast vue-toast__${opts.type}">${tips}</div>`
- })
- let toastElement = new ToastEl().$mount().$el;
- document.body.append(toastElement);
- setTimeout(() => {
- document.body.removeChild(toastElement);
- },opts.duration);
- }
-
- ['top','center','bottom'].forEach((type) => {
- Vue.prototype.$toast[type] = (tips) => {
- return Vue.prototype.$toast(tips,type)
- }
- })
- }
- export default Toast;
优化vue-toast
调用方式更通用,如下所示:
- this.toast = this.$toast({
- message: '这是一段信息',
- position: 'top',
- duration: 0
- });
可以手动关闭弹框
实现方式就是封装成一个构造函数,整体代码如下:
- function Toast() {
- this.toastTimer = false; // toastTimer:toast定时器
- this.toastVM = null; // toastVM:存储toast VM
- this.install = function(Vue,options) {
- let opts = {
- message: '', // 文本内容
- position: 'bottom', // 显示位置
- duration: 2500, // 展示时长(ms),值为 0 时,toast 不会消失
- className: '' // 自定义类名
- }
- /** toast提示方法
- * @params {Object|String} config 配置,如果为字符串=message
- * */
- Vue.prototype.$toast = (config) => {
- let option = {};
- let self = this;
- Object.assign(option,opts,options);
- if(typeof config === 'object') {
- Object.assign(option,config)
- } else { // 如果是字符串,传递的是message文本内容
- option.message = config;
- }
- if(this.toastTimer) { // 如果toast还在,则取消上次消失时间
- clearTimeout(this.toastTimer);
- this.toastVM.show = false;
- }
- if(!this.toastVM) {
- let ToastEl = Vue.extend({
- data() {
- return {
- show: false,
- message: option.message,
- className: option.className
- }
- },
- methods: {
- // 关闭toast
- close() {
- self.toastVM.show = false;
- }
- },
- render(createElement) {
- if(!this.show) {
- return false;
- }
- return createElement(
- 'div',
- {
- class: ['lx-toast',`lx-toast-${option.position}`,this.className],
- show: this.show,
- domProps: {
- innerHTML: this.message
- }
- },
- )
- }
- })
- this.toastVM = new ToastEl();
- document.body.append(this.toastVM.$mount().$el);
- }
- this.toastVM.show = true;
- this.toastVM.message = option.message;
- this.toastVM.className = option.className;
- this.toastVM.position = option.position;
- if(option.duration != 0) {// 为0的时候一直显示
- this.toastTimer = setTimeout(() => {
- this.toastVM.show = this.toastTimer = false;
- },option.duration)
- }
- return this.toastVM;
- }
- }
- }
- export default new Toast();
使用方式:
- <template>
- <div class="test">
- <button @click="open">开启弹框</button>
- <button @click="close">关闭弹框</button>
- </div>
- </template>
-
- <script>
- export default {
- data () {
- return {
- toast: null
- }
- },
- methods: {
- open() {
- this.toast = this.$toast({
- message: '这是一段信息',
- position: 'top',
- duration: 0
- });
- },
- close() {
- this.toast.close();
- }
- }
- }
- </script>
添加loading方法
完整代码:
- function Toast() {
- this.toastTimer = false; // toastTimer:toast定时器
- this.toastVM = null; // toastVM:存储toast VM
- this.showLoad = false; // 存储loading显示状态
- this.loadNode = null; // 存储loading节点元素
- this.install = function(Vue,options) {
- let opts = {
- message: '', // 文本内容
- position: 'bottom', // 显示位置
- duration: 2500, // 展示时长(ms),值为 0 时,toast 不会消失
- className: '' // 自定义类名
- }
- /** toast提示方法
- * @params {Object|String} config 配置,如果为字符串=message
- * */
- Vue.prototype.$toast = (config) => {
- let option = {};
- let self = this;
- Object.assign(option,opts,options);
- if(typeof config === 'object') {
- Object.assign(option,config)
- } else { // 如果是字符串,传递的是message文本内容
- option.message = config;
- }
- if(this.toastTimer) { // 如果toast还在,则取消上次消失时间
- clearTimeout(this.toastTimer);
- this.toastVM.show = false;
- }
- if(!this.toastVM) {
- let ToastEl = Vue.extend({
- data() {
- return {
- show: false,
- message: option.message,
- className: option.className
- }
- },
- methods: {
- // 关闭toast
- close() {
- self.toastVM.show = false;
- }
- },
- render(createElement) {
- if(!this.show) {
- return false;
- }
- return createElement(
- 'div',
- {
- class: ['lx-toast',`lx-toast-${option.position}`,this.className],
- show: this.show,
- domProps: {
- innerHTML: this.message
- }
- },
- )
- }
- })
- this.toastVM = new ToastEl();
- document.body.append(this.toastVM.$mount().$el);
- }
- this.toastVM.show = true;
- this.toastVM.message = option.message;
- this.toastVM.className = option.className;
- this.toastVM.position = option.position;
- if(option.duration != 0) {// 为0的时候一直显示
- this.toastTimer = setTimeout(() => {
- this.toastVM.show = this.toastTimer = false;
- },option.duration)
- }
- return this.toastVM;
- }
- /** $loading加载
- * @params {Object|String} config 配置,如果为字符串=message
- * */
- Vue.prototype.$loading = (config) => {
- let option = {};
- let self = this;
- if(typeof config === 'object') {
- Object.assign(option,config)
- } else { // 传递的字符串
- option.message = config;
- }
- if(option.type == 'close') {
- if(this.loadNode) {
- this.loadNode.show = this.showLoad = false;
- }
- } else {
- if(this.showLoad && this.loadNode) {
- this.loadNode.message = option.message;
- return false;
- }
- const loadEl = Vue.extend({
- data() {
- return {
- show: false,
- message: option.message
- }
- },
- methods: {
- close() {
- self.loadNode.show = self.showLoad = false;
- }
- },
- render(h) {
- if(!this.show) {
- return false;
- }
- return h('div',{
- class: 'lx-load-mark',
- show: this.show
- },[
- h('div',{
- class: 'lx-load-box'
- },[
- h('div',{
- class: this.message ? 'lx-loading':'lx-loading-nocontent'
- },Array.apply(null,{length: 12}).map((value,index) => {
- return h('div',{
- class: ['loading_leaf',`loading_leaf_${index}`]
- })
- })),
- h('div',{
- class: 'lx-load-content',
- domProps: {
- innerHTML: this.message
- }
- })
- ])
- ])
- }
- })
- this.loadNode = new loadEl();
- document.body.appendChild(this.loadNode.$mount().$el);
- this.loadNode.show = this.showLoad = true;
- }
- return this.loadNode;
- }
- ['open','close'].forEach(type => {
- Vue.prototype.$loading[type] = (message) => {
- return Vue.prototype.$loading({type,message})
- }
- })
- }
- }
- export default new Toast();
完整的调用方式:
- <template>
- <div class="test">
- <button @click="open">开启弹框</button>
- <button @click="close">关闭弹框</button>
- </div>
- </template>
-
- <script>
- export default {
- data () {
- return {
- toast: null
- }
- },
- mounted() {
- let loading = this.$loading({
- message: '这是loading文字'
- })
- setTimeout(() => { // 5s 后关闭弹框
- loading.close();
- },5000);
- },
- methods: {
- open() {
- this.toast = this.$toast({
- message: '这是一段信息',
- position: 'top',
- duration: 0
- });
- },
- close() {
- this.toast.close();
- }
- }
- }
- </script>
toast.css代码:
- .lx-toast {
- position: fixed;
- bottom: 100px;
- left: 50%;
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
- max-width: 80%;
- height: 40px;
- line-height: 20px;
- padding: 10px 20px;
- transform: translateX(-50%);
- -webkit-transform: translateX(-50%);
- text-align: center;
- z-index: 9999;
- font-size: 14px;
- color: #fff;
- border-radius: 5px;
- background: rgba(0, 0, 0, 0.7);
- animation: show-toast .5s;
- -webkit-animation: show-toast .5s;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .lx-toast.lx-word-wrap {
- width: 80%;
- white-space: inherit;
- height: auto;
- }
- .lx-toast.lx-toast-top {
- top: 50px;
- bottom: inherit;
- }
- .lx-toast.lx-toast-center {
- top: 50%;
- margin-top: -20px;
- bottom: inherit;
- }
- @-webkit-keyframes show-toast {
- from {
- opacity: 0;
- }
- to {
- opacity: 1;
- }
- }
- @keyframes show-toast {
- from {
- opacity: 0;
- }
- to {
- opacity: 1;
- }
- }
- .lx-load-mark {
- position: fixed;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- z-index: 9999;
- }
- .lx-load-box {
- position: fixed;
- z-index: 3;
- width: 7.6em;
- min-height: 7.6em;
- top: 180px;
- left: 50%;
- margin-left: -3.8em;
- background: rgba(0, 0, 0, 0.7);
- text-align: center;
- border-radius: 5px;
- color: #FFFFFF;
- }
- .lx-load-content {
- margin-top: 64%;
- font-size: 14px;
- }
- .lx-loading, .lx-loading-nocontent {
- position: absolute;
- width: 0px;
- left: 50%;
- top: 38%;
- }
- .lx-loading-nocontent {
- top: 50%;
- }
- .loading_leaf {
- position: absolute;
- top: -1px;
- opacity: 0.25;
- }
- .loading_leaf:before {
- content: " ";
- position: absolute;
- width: 9.14px;
- height: 3.08px;
- background: #d1d1d5;
- -webkit-box-shadow: rgba(0, 0, 0, 0.0980392) 0px 0px 1px;
- box-shadow: rgba(0, 0, 0, 0.0980392) 0px 0px 1px;
- border-radius: 1px;
- -webkit-transform-origin: left 50% 0px;
- transform-origin: left 50% 0px;
- }
- .loading_leaf_0 {
- -webkit-animation: opacity-0 1.25s linear infinite;
- animation: opacity-0 1.25s linear infinite;
- }
- .loading_leaf_0:before {
- -webkit-transform: rotate(0deg) translate(7.92px, 0px);
- transform: rotate(0deg) translate(7.92px, 0px);
- }
- .loading_leaf_1 {
- -webkit-animation: opacity-1 1.25s linear infinite;
- animation: opacity-1 1.25s linear infinite;
- }
- .loading_leaf_1:before {
- -webkit-transform: rotate(30deg) translate(7.92px, 0px);
- transform: rotate(30deg) translate(7.92px, 0px);
- }
- .loading_leaf_2 {
- -webkit-animation: opacity-2 1.25s linear infinite;
- animation: opacity-2 1.25s linear infinite;
- }
- .loading_leaf_2:before {
- -webkit-transform: rotate(60deg) translate(7.92px, 0px);
- transform: rotate(60deg) translate(7.92px, 0px);
- }
- .loading_leaf_3 {
- -webkit-animation: opacity-3 1.25s linear infinite;
- animation: opacity-3 1.25s linear infinite;
- }
- .loading_leaf_3:before {
- -webkit-transform: rotate(90deg) translate(7.92px, 0px);
- transform: rotate(90deg) translate(7.92px, 0px);
- }
- .loading_leaf_4 {
- -webkit-animation: opacity-4 1.25s linear infinite;
- animation: opacity-4 1.25s linear infinite;
- }
- .loading_leaf_4:before {
- -webkit-transform: rotate(120deg) translate(7.92px, 0px);
- transform: rotate(120deg) translate(7.92px, 0px);
- }
- .loading_leaf_5 {
- -webkit-animation: opacity-5 1.25s linear infinite;
- animation: opacity-5 1.25s linear infinite;
- }
- .loading_leaf_5:before {
- -webkit-transform: rotate(150deg) translate(7.92px, 0px);
- transform: rotate(150deg) translate(7.92px, 0px);
- }
- .loading_leaf_6 {
- -webkit-animation: opacity-6 1.25s linear infinite;
- animation: opacity-6 1.25s linear infinite;
- }
- .loading_leaf_6:before {
- -webkit-transform: rotate(180deg) translate(7.92px, 0px);
- transform: rotate(180deg) translate(7.92px, 0px);
- }
- .loading_leaf_7 {
- -webkit-animation: opacity-7 1.25s linear infinite;
- animation: opacity-7 1.25s linear infinite;
- }
- .loading_leaf_7:before {
- -webkit-transform: rotate(210deg) translate(7.92px, 0px);
- transform: rotate(210deg) translate(7.92px, 0px);
- }
- .loading_leaf_8 {
- -webkit-animation: opacity-8 1.25s linear infinite;
- animation: opacity-8 1.25s linear infinite;
- }
- .loading_leaf_8:before {
- -webkit-transform: rotate(240deg) translate(7.92px, 0px);
- transform: rotate(240deg) translate(7.92px, 0px);
- }
- .loading_leaf_9 {
- -webkit-animation: opacity-9 1.25s linear infinite;
- animation: opacity-9 1.25s linear infinite;
- }
- .loading_leaf_9:before {
- -webkit-transform: rotate(270deg) translate(7.92px, 0px);
- transform: rotate(270deg) translate(7.92px, 0px);
- }
- .loading_leaf_10 {
- -webkit-animation: opacity-10 1.25s linear infinite;
- animation: opacity-10 1.25s linear infinite;
- }
- .loading_leaf_10:before {
- -webkit-transform: rotate(300deg) translate(7.92px, 0px);
- transform: rotate(300deg) translate(7.92px, 0px);
- }
- .loading_leaf_11 {
- -webkit-animation: opacity-11 1.25s linear infinite;
- animation: opacity-11 1.25s linear infinite;
- }
- .loading_leaf_11:before {
- -webkit-transform: rotate(330deg) translate(7.92px, 0px);
- transform: rotate(330deg) translate(7.92px, 0px);
- }
- @-webkit-keyframes opacity-0 {
- 0% {
- opacity: 0.25;
- }
- 0.01% {
- opacity: 0.25;
- }
- 0.02% {
- opacity: 1;
- }
- 60.01% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.25;
- }
- }
- @keyframes opacity-0 {
- 0% {
- opacity: 0.25;
- }
- 0.01% {
- opacity: 0.25;
- }
- 0.02% {
- opacity: 1;
- }
- 60.01% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.25;
- }
- }
- @-webkit-keyframes opacity-1 {
- 0% {
- opacity: 0.25;
- }
- 8.34333% {
- opacity: 0.25;
- }
- 8.35333% {
- opacity: 1;
- }
- 68.3433% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.25;
- }
- }
- @keyframes opacity-1 {
- 0% {
- opacity: 0.25;
- }
- 8.34333% {
- opacity: 0.25;
- }
- 8.35333% {
- opacity: 1;
- }
- 68.3433% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.25;
- }
- }
- @-webkit-keyframes opacity-2 {
- 0% {
- opacity: 0.25;
- }
- 16.6767% {
- opacity: 0.25;
- }
- 16.6867% {
- opacity: 1;
- }
- 76.6767% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.25;
- }
- }
- @keyframes opacity-2 {
- 0% {
- opacity: 0.25;
- }
- 16.6767% {
- opacity: 0.25;
- }
- 16.6867% {
- opacity: 1;
- }
- 76.6767% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.25;
- }
- }
- @-webkit-keyframes opacity-3 {
- 0% {
- opacity: 0.25;
- }
- 25.01% {
- opacity: 0.25;
- }
- 25.02% {
- opacity: 1;
- }
- 85.01% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.25;
- }
- }
- @keyframes opacity-3 {
- 0% {
- opacity: 0.25;
- }
- 25.01% {
- opacity: 0.25;
- }
- 25.02% {
- opacity: 1;
- }
- 85.01% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.25;
- }
- }
- @-webkit-keyframes opacity-4 {
- 0% {
- opacity: 0.25;
- }
- 33.3433% {
- opacity: 0.25;
- }
- 33.3533% {
- opacity: 1;
- }
- 93.3433% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.25;
- }
- }
- @keyframes opacity-4 {
- 0% {
- opacity: 0.25;
- }
- 33.3433% {
- opacity: 0.25;
- }
- 33.3533% {
- opacity: 1;
- }
- 93.3433% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.25;
- }
- }
- @-webkit-keyframes opacity-5 {
- 0% {
- opacity: 0.270958333333333;
- }
- 41.6767% {
- opacity: 0.25;
- }
- 41.6867% {
- opacity: 1;
- }
- 1.67667% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.270958333333333;
- }
- }
- @keyframes opacity-5 {
- 0% {
- opacity: 0.270958333333333;
- }
- 41.6767% {
- opacity: 0.25;
- }
- 41.6867% {
- opacity: 1;
- }
- 1.67667% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.270958333333333;
- }
- }
- @-webkit-keyframes opacity-6 {
- 0% {
- opacity: 0.375125;
- }
- 50.01% {
- opacity: 0.25;
- }
- 50.02% {
- opacity: 1;
- }
- 10.01% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.375125;
- }
- }
- @keyframes opacity-6 {
- 0% {
- opacity: 0.375125;
- }
- 50.01% {
- opacity: 0.25;
- }
- 50.02% {
- opacity: 1;
- }
- 10.01% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.375125;
- }
- }
- @-webkit-keyframes opacity-7 {
- 0% {
- opacity: 0.479291666666667;
- }
- 58.3433% {
- opacity: 0.25;
- }
- 58.3533% {
- opacity: 1;
- }
- 18.3433% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.479291666666667;
- }
- }
- @keyframes opacity-7 {
- 0% {
- opacity: 0.479291666666667;
- }
- 58.3433% {
- opacity: 0.25;
- }
- 58.3533% {
- opacity: 1;
- }
- 18.3433% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.479291666666667;
- }
- }
- @-webkit-keyframes opacity-8 {
- 0% {
- opacity: 0.583458333333333;
- }
- 66.6767% {
- opacity: 0.25;
- }
- 66.6867% {
- opacity: 1;
- }
- 26.6767% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.583458333333333;
- }
- }
- @keyframes opacity-8 {
- 0% {
- opacity: 0.583458333333333;
- }
- 66.6767% {
- opacity: 0.25;
- }
- 66.6867% {
- opacity: 1;
- }
- 26.6767% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.583458333333333;
- }
- }
- @-webkit-keyframes opacity-9 {
- 0% {
- opacity: 0.687625;
- }
- 75.01% {
- opacity: 0.25;
- }
- 75.02% {
- opacity: 1;
- }
- 35.01% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.687625;
- }
- }
- @keyframes opacity-9 {
- 0% {
- opacity: 0.687625;
- }
- 75.01% {
- opacity: 0.25;
- }
- 75.02% {
- opacity: 1;
- }
- 35.01% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.687625;
- }
- }
- @-webkit-keyframes opacity-10 {
- 0% {
- opacity: 0.791791666666667;
- }
- 83.3433% {
- opacity: 0.25;
- }
- 83.3533% {
- opacity: 1;
- }
- 43.3433% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.791791666666667;
- }
- }
- @keyframes opacity-10 {
- 0% {
- opacity: 0.791791666666667;
- }
- 83.3433% {
- opacity: 0.25;
- }
- 83.3533% {
- opacity: 1;
- }
- 43.3433% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.791791666666667;
- }
- }
- @-webkit-keyframes opacity-11 {
- 0% {
- opacity: 0.895958333333333;
- }
- 91.6767% {
- opacity: 0.25;
- }
- 91.6867% {
- opacity: 1;
- }
- 51.6767% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.895958333333333;
- }
- }
- @keyframes opacity-11 {
- 0% {
- opacity: 0.895958333333333;
- }
- 91.6767% {
- opacity: 0.25;
- }
- 91.6867% {
- opacity: 1;
- }
- 51.6767% {
- opacity: 0.25;
- }
- 100% {
- opacity: 0.895958333333333;
- }
- }
参考