Vue Vue.extend()的使用
Vue.extend 属于 Vue 的全局 API,在实际业务开发中我们很少使用,因为相比常用的 Vue.component 写法使用 extend 步骤要更加繁琐一些。但是在一些独立组件开发场景中,Vue.extend + $mount 这对组合是我们需要去关注的。
应用场景
在 vue 项目中,初始化的根实例后,所有页面基本上都是通过 router 来管理,组件也是通过 import 来进行局部注册,所以组件的创建不需要去关注,相比 extend 要更省心一点点。但是这样做会有几个缺点:
组件模板都是事先定义好的,如果我要从接口动态渲染组件怎么办?所有内容都是在 #app 下渲染,注册组件都是在当前位置渲染。如果我要实现一个类似于 window.alert() 提示组件要求像调用 JS 函数一样调用它,该怎么办?
这时候,Vue.extend + vm.$mount 组合就派上用场了。
简单实用
基础用法
Vue.extend( options )
参数:{Object} options 用法:使用基础 Vue 构造器,创建一个[子类]。参数是一个包含组件选项的对象; data 选项是特例,需要注意: 在 Vue.extend() 中它必须是函数;<div id="mount-point"></div> // 创建构造器 var Profile = Vue.extend({ template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>', data: function () { return { firstName: 'Walter', lastName: 'White', alias: 'Heisenberg' } } }) // 创建 Profile 实例,并挂载到一个元素上。 new Profile().$mount('#mount-point') // 结果如下: <p>Walter White aka Heisenberg</p>
可以看到,extend 创建的是 Vue 构造器,而不是我们平时常写的组件实例,所以不可以通过 new Vue({ components: testExtend }) 来直接使用,需要通过 new Profile().$mount(’#mount-point’) 来挂载到指定的元素上。
第二种写法
可以在创建实例的时候传入一个元素,生成的组件将会挂载到这个元素上,跟 $mount 差不多。
// 1. 定义一个vue模版 let tem ={ template:'{{firstName}} {{lastName}} aka {{alias}}', data:function(){ return{ firstName:'Walter', lastName:'White', alias:'Heisenberg' } } // 2. 调用 const TemConstructor = Vue.extend(tem) const intance = new TemConstructor({el:"#app"}) // 生成一个实例,并且挂载在 #app 上
使用Vue.extend()编写vue插件
今天,我们使用Vue.extend()编程式的写法来编写一个vue插件,本质是将插件实例挂载到Vue的原型上。然后,就像element-ui的toast组件那样,使用this.$toast()实例方法去调用插件。
Vue.extend()
使用Vue这个基础构造器,构造出一个[子类],其实就是个构造函数,通过new运算符生成vue实例。具体见官方文档Vue-extend。
如何编程式使用组件呢
比如,我们要实现个弹窗功能。通过编程式导航,我们就不用在模板中写了,可以使用js直接编写唤出弹窗。首先,我们正常的编写弹窗组件。如下:
<template> ? <div class="gulu-toast" :class="toastClasses"> ? ? <div class="toast" ref="toast"> ? ? ? <div class="message"> ? ? ? ? <slot v-if="!enableHtml"></slot> ? ? ? ? <div v-else v-html="$slots.default[0]"></div> ? ? ? </div> ? ? ? <div class="line" ref="line"></div> ? ? ? <span class="close" v-if="closeButton" @click="onClickClose"> ? ? ? ? {{closeButton.text}} ? ? ? </span> ? ? </div> ? </div> </template>
<script> ? //构造组件的选项 ? export default { ? ? name: 'Toast', ? ? props: { ? ? ? autoClose: { ? ? ? ? type: [Boolean, Number], ? ? ? ? default: 5, ? ? ? ? validator (value) { ? ? ? ? ? return value === false || typeof value === 'number'; ? ? ? ? } ? ? ? }, ? ? ? closeButton: { ? ? ? ? type: Object, ? ? ? ? default () { ? ? ? ? ? return { ? ? ? ? ? ? text: '关闭', callback: undefined ? ? ? ? ? } ? ? ? ? } ? ? ? }, ? ? ? enableHtml: { ? ? ? ? type: Boolean, ? ? ? ? default: false ? ? ? }, ? ? ? position: { ? ? ? ? type: String, ? ? ? ? default: 'top', ? ? ? ? validator (value) { ? ? ? ? ? return ['top', 'bottom', 'middle'].indexOf(value) >= 0 ? ? ? ? } ? ? ? } ? ? }, ? ? mounted () { ? ? ? // 这里是为了防止不断点击,出现多个弹窗 ? ? ? const toast = document.getElementsByClassName('gulu-toast')[0] ? ? ? toast && document.body.removeChild(toast) ? ? ? this.updateStyles() ? ? ? this.execAutoClose() ? ? }, ? ? computed: { ? ? ? toastClasses () { ? ? ? ? return { ? ? ? ? ? [`position-${this.position}`]: true ? ? ? ? } ? ? ? } ? ? }, ? ? methods: { ? ? ? updateStyles () { ? ? ? ? this.$nextTick(() => { ? ? ? ? ? this.$refs.line.style.height = ? ? ? ? ? ? `${this.$refs.toast.getBoundingClientRect().height}px` ? ? ? ? }) ? ? ? }, ? ? ? execAutoClose () { ? ? ? ? if (this.autoClose) { ? ? ? ? ? setTimeout(() => { ? ? ? ? ? ? this.close() ? ? ? ? ? }, this.autoClose * 1000) ? ? ? ? } ? ? ? }, ? ? ? close () { ? ? ? ? this.$el.remove() ? ? ? ? this.$emit('close') ? ? ? ? this.$destroy() ? ? ? }, ? ? ? onClickClose () { ? ? ? ? this.close() ? ? ? ? if (this.closeButton && typeof this.closeButton.callback === 'function') { ? ? ? ? ? this.closeButton.callback(this)//this === toast实例 ? ? ? ? } ? ? ? } ? ? } ? } </script>
接下来,就是Vue.extend()出场了。
import Toast from './src/toast.vue'; Toast.install = function (Vue) { ?? ?// 其实就是全局挂载使用 ? ? Vue.prototype.$toast = function (text, props) { ? ? ? ? const ToastMain = Vue.extend(Toast) ? ? ? ? const instance = new ToastMain({ ? ? ? ? ? ? propsData: props // 这里必须是propsData ? ? ? ? }) ? ? ? ? instance.$slots.default = [text] // 插槽内容 ? ? ? ? // instance.$mount().$el 该段代码意义为: ? ? ? ? // 文档之外渲染,并且获取该实例的根DOM元素,将其插入到body元素中。 ? ? ? ? document.body.appendChild(instance.$mount().$el)? ? ? } } export default Toast
我们在main.js入口文件中,使用Vue.use()安装后,就可以在任何地方使用了~~。
具体使用
this.$toast("关闭吗?", { ? ? ? ? closeButton: { ? ? ? ? ? text: "关闭", ? ? ? ? ? callback: () => { ? ? ? ? ? ? console.log('已经关闭了'); ? ? ? ? ? }, ? ? ? ? }, ? ? ? ? autoClose: 12, ? ? ? ? position: 'bottom' ? ? ? });
小结:
首先,Vue.extend 获得是一个构造函数,可以通过实例化生成一个 Vue 实例。
实例化时可以向这个实例传入参数,但是需要注意的是 props 的值需要通过 propsData 属性来传递。
还可以通过$slots来自定义插槽内容。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
查看更多关于Vue中Vue.extend()的使用及解析的详细内容...