2021-06-26 Vue自定义插件

2021-06-26  本文已影响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>

效果:

全局原型调用方法的效果

完~

上一篇下一篇

猜你喜欢

热点阅读