vue插件开发及填坑

801 阅读2分钟

随着各种项目的需求增多,vue技术栈的使用率越发的多了,伴随而来的遇到的坑也越发的多了,有的使用因为版本问题、有些是因为编码/编译原因、有些是因为自己不认真...总之,各种坑随处可见。但是采坑未必是坏事,反而可以帮助我们更快成长。

vue插件(或者公共组件)的开发,其实大家一直在用,写法也不尽相同。之前开发中,基本写法是写一个组件,各种属性通过props引入,然后在需要的地方单独引入组件。这种方法虽然可行,但是如果很多页面都需要同一个插件,比如loading、toast等,引入多次就很不方便了,这是我们可以用另外两种方法开发插件,把插件install到vue上。

先简单看下整体目录:


整体目录是vue-cli生成的,结构一目了然,重点说下两个文件夹

commons里是一些公共组件,个别地方引用;

plugins里是多处使用的插件,这里准备了两个文件toast和loading,用两种方法开发。

方法一:

toast文件夹下分别建toast.vue、toast.js(此处注意,后面的坑就在这里)

//toast.vue
<template>
    <transition name="fade">
        <div class="toast" v-show="isShow">
            <i>{{title}}</i>
            <span>{{message}}</span>
        </div>
    </transition>
</template>

<script>
    export default {
        name: 'Toast', 
        data(){
            return {
                isShow: false,
                title: '',
                message: ''
            }
        }
    }
</script>

//样式略

组件就是通常的写法,没什么可说的,然后是注册插件js

//toast.js
import Toast from './toast'
let alertToast = {}
alertToast.install = function(Vue){
    let alerts = Vue.extend(Toast)
    let alertToastC = new alerts()
    alertToastC.$mount(document.createElement('div'))
    document.body.appendChild(alertToastC.$el)

    Vue.prototype.$alertToast = function(title, message, delay=2000){
        alertToastC.title = title
        alertToastC.message = message
        alertToastC.isShow = true
        setTimeout(function(){
            alertToastC.isShow = false
        }, delay)
    }
}

export default alertToast

然后将插件引入到全局,并通过vue.use()引用,在需要使用的地方直接调用this.$alertToast()就可以了。

//main.js
import Vue from 'vue'
import alertToast from './plugins/toast/toast'

Vue.use(alertToast)

//hello.vue
<template>
    <div>
        <button type='button' @click="showToast">click</button>
    </div>
</template>

<script>
export default{
    methods: {
        showToast(){
            this.$alertToast()
        }
    }
}
</script>

点击按钮见证奇迹吧,然而奇迹真的发生了!!!点击按钮没有什么效果(或者挂载插件用别的方式的话,控制台会报错: [Vue warn]: Failed to mount component: template or render function not defined.  )。

这个问题困扰了很久,网上的相关方法也都没有什么效果,查看代码也看不出有什么逻辑错误,后经过大佬指点,发现了一个自己挖的坑:在定义toast的组件和js文件的时候,取了相同的名字(此处即使大小写不一样也会被认作是同样的改名字),而在toast.js里引入toast.vue的时候,由于习惯和webpack的配置,写法进行了简化 import Toast from './toast',此时程序会默认引入toast.js而不是toast.vue文件,解决办法也很简单,只需要加上后缀即可import Toast from './toast.vue'。

经过修改,问题解决,插件可以正常使用。

方法二:

这个方法和最开始说的方法很相似,只不过在引入的时候我们不是每次使用单独引入,而是install到vue上,在使用的时候直接使用组件即可,不需要每次都单独引入一次,简单代码如下:

//loading.vue
<template>
    <transition name="fade">
        <div class="loadings" v-show="isLoading">
            loading......
        </div>
    </transition>
</template>

<script>
export default {
    name: 'Loadings',
    props: {
        isLoading: {
            type: Boolean, 
            default: false 
        }
    }
}
</script>//loading.js
import Loadings from './Loadings.vue'
const loads = {}
loads.install = function(Vue){
    Vue.component('loads', Loadings)
}
export default loads//main.js
import Vue from 'vue'
import alertToast from './plugins/toast/toast'import loads from './plugins/loading/loading'

Vue.use(alertToast)
Vue.use(loads)
//hello.vue<template>
    <div>
        <button type='button' @click="showToast">click</button>
        <button type='button' @click="showLoading" :isLoading='isLoading'>clickLoad</button>
    </div>
</template><script>
export default{
    data(){
        return {
            isLoading: false
        }
    },
    methods: {
        showToast(){
            this.$alertToast(‘success', '请求成功')
        },
        showLoading(){
            this.isLoading = true
            setTimeout(()=>{
                this.isLoading = false
            }, 3000)
        }
    }
}
</script>

可见两种方法本质是差不多的,只不过在使用方法上有所区别,实际使用中可以根据情况不同分别使用不同的定义方法,方便后期的维护和功能扩展。