vue2 自定义动态组件所遇到的问题


Posted in Javascript onJune 08, 2017

下面讲一下如何定义动态组件。

 Vue.extend

 思路就是拿到组件的构造函数,这样我们就可以new了。而Vue.extend可以做到:https://cn.vuejs.org/v2/api/#Vue-extend

// 创建构造器
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')

官方提供了这个示例,我们进行一下改造,做一个简单的消息提示框。

动态组件实现

创建一个vue文件。widgets/alert/src/main.vue

<template>
 <transition name="el-message-fade">
<div v-show="visible" class="my-msg">{{message}}</div>
 </transition>
</template>
<script >
 export default{
  data(){
   return{
    message:'',
    visible:true
   } 
  },
  methods:{
   close(){
    setTimeout(()=>{
      this.visible = false;
    },2000)
   },
  },
  mounted() {
  this.close();
  }
 }
</script>

这是我们组件的构成。如果是第一节中,我们可以把他放到components对象中就可以用了,但是这儿我们要通过构造函数去创建它。再创建一个widgets/alert/src/main.js

import Vue from 'vue';
let MyMsgConstructor = Vue.extend(require('./main.vue'));
let instance;
var MyMsg=function(msg){
 instance= new MyMsgConstructor({
  data:{
   message:msg
}})
//如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素。可以使用 vm.$mount() 手动地挂载一个未挂载的实例。
instance.$mount();
 document.body.appendChild(instance.$el)
 return instance;
}
export default MyMsg;
require('./main.vue')返回的是一个组件初始对象,对应Vue.extend( options )中的options,这个地方等价于下面的代码:
import alert from './main.vue'
let MyMsgConstructor = Vue.extend(alert);

而MyMsgConstructor如下。

 参考源码中的this._init,会对参数进行合并,再按照生命周期运行:

Vue.prototype._init = function (options) {
 ...// merge options
 if (options && options._isComponent) {
  // optimize internal component instantiation
  // since dynamic options merging is pretty slow, and none of the
  // internal component options needs special treatment.
  initInternalComponent(vm, options);
 } else {
  vm.$options = mergeOptions(
  resolveConstructorOptions(vm.constructor),
  options || {},
  vm
  );
 }
// expose real self
 vm._self = vm;
 initLifecycle(vm);
 initEvents(vm);
 initRender(vm);
 callHook(vm, 'beforeCreate');
 initInjections(vm); // resolve injections before data/props
 initState(vm);
 initProvide(vm); // resolve provide after data/props
 callHook(vm, 'created');
 ...
 if (vm.$options.el) {
  vm.$mount(vm.$options.el);
 }
 };

而调用$mount()是为了获得一个挂载实例。这个示例就是instance.$el。

vue2 自定义动态组件所遇到的问题

可以在构造方法中传入el对象(注意上面源码中的mark部分,也是进行了挂载vm.$mount(vm.$options.el),但是如果你没有传入el,new之后不会有$el对象的,就需要手动调用$mount()。这个方法可以直接传入元素id。

instance= new MessageConstructor({
  el:".leftlist",
  data:{
   message:msg
}})

 这个el不能直接写在vue文件中,会报错。接下来我们可以简单粗暴的将其设置为Vue对象。

调用

在main.js引入我们的组件:

//..
import VueResource from 'vue-resource'
import MyMsg from './widgets/alert/src/main.js';
//..
//Vue.component("MyMsg", MyMsg);
Vue.prototype.$mymsg = MyMsg;

然后在页面上测试一下:

<el-button type="primary" @click='test'>主要按钮</el-button>
//..
 methods:{
 test(){
 this.$mymsg("hello vue");
 }
 }

这样就实现了基本的传参。最好是在close方法中移除元素:

vue2 自定义动态组件所遇到的问题

close(){
 setTimeout(()=>{
  this.visible = false;
  this.$el.parentNode.removeChild(this.$el);
  },2000)
 },

 回调处理

回调和传参大同小异,可以直接在构造函数中传入。先修改下main.vue中的close方法:

export default{
  data(){
   return{
    message:'',
    visible:true
   } 
  },
  methods:{
   close(){
    setTimeout(()=>{
      this.visible = false;
      this.$el.parentNode.removeChild(this.$el);
    if (typeof this.onClose === 'function') {
     this.onClose(this);
    }
    },2000)
   },
  },
  mounted() {
  this.close();
  }
 }

如果存在onClose方法就执行这个回调。而在初始状态并没有这个方法。然后在main.js中可以传入

var MyMsg=function(msg,callback){
 instance= new MyMsgConstructor({
  data:{
   message:msg
 },
 methods:{
  onClose:callback
 } 
})

这里的参数和原始参数是合并的关系,而不是覆盖。这个时候再调用的地方修改下,就可以执行回调了。

test(){
  this.$mymsg("hello vue",()=>{
  console.log("closed..")
  });
 },

你可以直接重写close方法,但这样不推荐,因为可能搞乱之前的逻辑且可能存在重复的编码。现在就灵活多了。

统一管理

 如果随着自定义动态组件的增加,在main.js中逐个添加就显得很繁琐。所以这里我们可以让widgets提供一个统一的出口,日后也方便复用。在widgets下新建一个index.js

import MyMsg from './alert/src/main.js';
const components = [MyMsg];
let install =function(Vue){
 components.map(component => {
 Vue.component(component.name, component);
 });
 Vue.prototype.$mymsg = MyMsg;
}
if (typeof window !== 'undefined' && window.Vue) {
 install(window.Vue);
};
export default {
 install
}

在这里将所有自定义的组件通过Vue.component注册。最后export一个install方法就可以了。因为接下来要使用Vue.use。

安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法将被作为 Vue 的参数调用。

也就是把所有的组件当插件提供:在main.js中加入下面的代码即可。

...
import VueResource from 'vue-resource'
import Widgets from './Widgets/index.js'

...
Vue.use(Widgets)

这样就很简洁了。

小结: 通过Vue.extend和Vue.use的使用,我们自定义的组件更具有灵活性,而且结构很简明,基于此我们可以构建自己的UI库。以上来自于对Element源码的学习。

widgets部分源码:http://files.cnblogs.com/files/stoneniqiu/widgets.zip

以上所述是小编给大家介绍的vue2 自定义动态组件所遇到的问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
JavaScript触发器详解
Mar 10 Javascript
javascript 支持链式调用的异步调用框架Async.Operation
Aug 04 Javascript
document.getElementById为空或不是对象的解决方法
Jan 24 Javascript
JS中for循序中延迟加载动态效果的具体实现
Aug 18 Javascript
基于HTML5上使用iScroll实现下拉刷新,上拉加载更多
May 21 Javascript
JavaScript代码实现图片循环滚动效果
Mar 19 Javascript
jQuery实现邮箱下拉列表自动补全功能
Sep 08 Javascript
H5用户注册表单页 注册模态框!
Sep 17 Javascript
在点击div中的p时,如何阻止事件冒泡
Feb 07 Javascript
深入理解React高阶组件
Sep 28 Javascript
JS手机端touch事件计算滑动距离的方法示例
Oct 26 Javascript
vue video和vue-video-player实现视频铺满教程
Oct 30 Javascript
vue.js中过滤器的使用教程
Jun 08 #Javascript
了解VUE的render函数的使用
Jun 08 #Javascript
Node.js 使用命令行工具检查更新
Jun 08 #Javascript
在vue.js中抽出公共代码的方法示例
Jun 08 #Javascript
Ionic3 UI组件之autocomplete详解
Jun 08 #Javascript
jQuery+ajax实现局部刷新的两种方法
Jun 08 #jQuery
gulp解决跨域的配置文件问题
Jun 08 #Javascript
You might like
用PHP实现小写金额转换大写金额的代码(精确到分)
2012/01/10 PHP
微信access_token的获取开发示例
2015/04/16 PHP
解决laravel-admin 自己新建页面里 js 需要刷新一次的问题
2019/10/03 PHP
PHPUnit + Laravel单元测试常用技能
2019/11/06 PHP
jQuery 使用手册(一)
2009/09/23 Javascript
改进UCHOME的记录发布,增强可访问性用户体验
2011/01/17 Javascript
删除select中所有option选项jquery代码
2013/08/12 Javascript
利用jquery写的左右轮播图特效
2014/02/12 Javascript
jQuery动态创建html元素的常用方法汇总
2014/09/05 Javascript
jQuery实现鼠标悬停背景翻转的黑色导航菜单代码
2015/09/14 Javascript
使用jQuery操作HTML的table表格的实例解析
2016/03/13 Javascript
vue一个页面实现音乐播放器的示例
2018/02/06 Javascript
react中使用swiper的具体方法
2018/05/15 Javascript
vue this.reload 方法 配置
2018/09/12 Javascript
vue实现随机验证码功能的实例代码
2019/04/30 Javascript
JavaScript实现多张图片放大镜效果示例【不限定图片尺寸,rem单位】
2019/05/14 Javascript
jQuery实现查看图片功能
2020/12/01 jQuery
[09:43]DOTA2每周TOP10 精彩击杀集锦vol.5
2014/06/25 DOTA
[56:41]2018DOTA2亚洲邀请赛 3.31 小组赛 A组 Newbee vs OG
2018/04/01 DOTA
[01:51]历届DOTA2国际邀请赛举办地回顾 TI9落地上海
2018/08/26 DOTA
使用Python的Django框架实现事务交易管理的教程
2015/04/20 Python
Python实现带参数与不带参数的多重继承示例
2018/01/30 Python
解决python Markdown模块乱码的问题
2019/02/14 Python
【python】matplotlib动态显示详解
2019/04/11 Python
django-filter和普通查询的例子
2019/08/12 Python
python退出循环的方法
2020/06/18 Python
HTML5 device access 设备访问详解
2018/05/24 HTML / CSS
墨西哥巴士车票在线购买:ClickBus
2018/03/27 全球购物
KELLER SPORTS荷兰:在线订购最好的运动产品
2020/10/13 全球购物
我的大学生活职业生涯规划
2014/01/02 职场文书
校长师德师风自我剖析材料
2014/09/29 职场文书
2014年学校教学工作总结
2014/12/06 职场文书
匿名信格式范文
2015/05/27 职场文书
2015年国庆节标语大全
2015/07/30 职场文书
2019年冬至:天冷暖人心的问候祝福语大全
2019/12/20 职场文书
Python借助with语句实现代码段只执行有限次
2022/03/23 Python