美文网首页
2021-06-26 Vue自定义插件

2021-06-26 Vue自定义插件

作者: 走花鹿 | 来源:发表于2021-06-26 13:15 被阅读0次

    实现一个message组件,类似于element ui的消息提示功能。
    功能:跳出提示语,几秒后自动隐藏。
    目的:巩固和总结Vue自定义插件的方法。



    先写一个用import导入插件的模式

    开始

    第一步

    // Messgae.vue
    // 初始化模板和数据
    <template>
     <div>
       <div v-for="m in message" :key="m.id">{{m.message}}</div>
     </div>
    </template>
    <script>
    export default {
     name: 'ELMessage',
     data() {
       return {
         message: [] // {id, message, duration}
       }
     }
    }
    </script>
    
    // message.js
    export const Message = {
      info (options) {
        console.log(options);
      }
    }
    
    // App.vue
    <template>
      <div id="app">
        <button @click="showMessage">全局message</button>
      </div>
    </template>
    <script>
    // import 导入js
    import { Message } from './component/message'
    let id = 0
    export default {
      name: 'App',
      data() {
        return {}
      },
      created() {
        
      },
      methods: {
        showMessage() {
          Message.info({ message: `这是消息提示${++id}`, duration: 2000})
        }
      },
    }
    </script>
    
    输出

    第二步

    // message.vue
    <template>
      <div>
        <div v-for="m in message" :key="m.id">{{m.message}}</div>
      </div>
    </template>
    <script>
    export default {
      name: 'ELMessage',
      data() {
        return {
          message: [] // {id, message, duration}
        }
      },
      mounted() {
        this.id = 0
      },
      methods: {
        add(options) {
          const layer = {
            ...options,
            id: ++this.id
          }
          this.message.push(layer)
    
          setTimeout(() => {
            this.remove(layer)
          }, layer.duration)
        },
        remove(layer) {
          this.message = this.message.filter( m => m.id !== layer.id)
        }
      },
    }
    </script>
    
    // message.js
    import Vue from 'vue'
    import MessageComponent from './Message.vue'
    
    const getInstance = () => {
      const vm = new Vue({
        render: h => h(MessageComponent)
      }).$mount() // $mount() 将虚拟DOM转换为真实DOM
    
      //vm.$el 获取Vue实例关联的DOM元素;
      document.body.appendChild(vm.$el)
      // 当前messageComponent组件
      return vm.$children[0]
    }
    
    export const Message = {
      info (options) {
        console.log(options);
        getInstance().add(options)
      }
    }
    
    // App.vue
    <template>
      <div id="app">
        <button @click="showMessage">全局message</button>
      </div>
    </template>
    <script>
    // import 导入js
    import { Message } from './component/message'
    let id = 0
    export default {
      name: 'App',
      data() {
        return {}
      },
      created() {
        
      },
      methods: {
        showMessage() {
          Message.info({ message: `这是消息提示${++id}`, duration: 2000})
        }
      },
    }
    </script>
    
    输出效果:前面的消息提示1,2,3过一段时间会消失

    发现问题

    在第二步中存在一个问题,如下图:


    渲染出了多个vm实例

    解决

    单例模式

    import Vue from 'vue'
    import MessageComponent from './Message.vue'
    
    // 单例模式
    let vm = null
    
    const getInstance = () => {
      if (!vm) {
        vm = new Vue({
          render: h => h(MessageComponent)
        }).$mount()
        document.body.appendChild(vm.$el)
      }
      // const vm = new Vue({
      //   render: h => h(MessageComponent)
      // }).$mount() // $mount() 将虚拟DOM转换为真实DOM
    
      //vm.$el 获取Vue实例关联的DOM元素;
      // document.body.appendChild(vm.$el)
      // 当前messageComponent组件
      return vm.$children[0]
    }
    
    export const Message = {
      info (options) {
        console.log(options);
        getInstance().add(options)
      }
    }
    
    现在只会生成一个实例

    这里写的是全局可以引用自定义插件的模式
    主要是main.js不同,前面重复的文件就不写了
    主要是把插件的方法挂载到Vue.prototype原型对象上

    开始

    // message.js
    import Vue from 'vue'
    import MessageComponent from './Message.vue'
    
    // 单例模式
    let vm = null
    
    const getInstance = () => {
      if (!vm) {
        vm = new Vue({
          render: h => h(MessageComponent)
        }).$mount()
        document.body.appendChild(vm.$el)
      }
      // const vm = new Vue({
      //   render: h => h(MessageComponent)
      // }).$mount() // $mount() 将虚拟DOM转换为真实DOM
    
      //vm.$el 获取Vue实例关联的DOM元素;
      // document.body.appendChild(vm.$el)
      // 当前messageComponent组件
      return vm.$children[0]
    }
    
    export const Message = {
      info (options) {
        console.log(options)
        getInstance().add(options)
      }
    }
    
    // Vue.use(插件)会执行这个install方法
    export default {
      install(Vue, options) {
        console.log(options)
        Vue.prototype.$message = {
          info: Message.info
        }
      }
    }
    
    // main.js
    import Vue from 'vue'
    import App from './App.vue'
    
    import Message from './component/message'
    
    // {size: 'small'}作为参数传递
    Vue.use(Message, {
      size: 'small'
    })
    
    // 阻止启动生产消息,常用作指令。浏览器不会打印相关信息
    Vue.config.productionTip = false
    
    new Vue({
      render: h => h(App),
    }).$mount('#app')
    

    这样就可以在任意页面使用this.$message.info来调用这个插件了

    试一下

    加一个按钮,执行ShowMessage2方法

    <template>
      <div id="app">
        <button @click="showMessage">全局message</button>
        <button @click="showMessage2">全局原型message</button>
      </div>
    </template>
    <script>
    // import 导入js
    import { Message } from './component/message'
    let id = 0
    export default {
      name: 'App',
      data() {
        return {}
      },
      created() {
        
      },
      methods: {
        showMessage() {
          Message.info({ message: `这是消息提示${++id}`, duration: 2000})
        },
        showMessage2() {
          this.$message.info({message: `这是全局原型消息提示${++id}`, duration: 2000})
        }
      },
    }
    </script>
    

    效果:

    全局原型调用方法的效果

    完~

    相关文章

      网友评论

          本文标题:2021-06-26 Vue自定义插件

          本文链接:https://www.haomeiwen.com/subject/istzyltx.html