Vue的动态生成组件

3,219 阅读1分钟

一、使用场景

在单元测试和开发插件时,常常需要不使用template标签而创建一个,Vue实例,这个Vue实例可能需要被插到页面中,也可能不会只在内存中存在即可

二、extend 构造Vue实例

  import Toast from "./toast";

  let Constructor = Vue.extend(Toast);
  let toast = new Constructor({
    propsData: toastoptions
  }).$mount();

mounted 的时机可以改变

  let Constructor = Vue.extend(Toast);
  let toast = new Constructor({
    propsData: toastoptions
  });
  toast.$slots.toast = message;
  toast.$mount();

尽量做到模拟我们在 template 里使用组件的情景:mounted之前完成数据准备

三、特定API

1.$el

Vue 实例使用的根 DOM 元素。

  let Constructor = Vue.extend(Toast);
  let toast = new Constructor();
  toast.$mount();
  document.body.appendChild(toast.$el);

虽然 toast 只是mounted到内存中,相当于createElement("div"),依然还是会存在一个容器 div 。$el就是这个 div 

2. $data $props

这两个没什么太大用,因为Vue已经把内部数据全部代理

3. $options

Vue 实例的初始化选项,自定义选项以及自带选项。

自带的:Vue写在构造实例是的options就是

自定义:

new Vue({
  customOption: 'foo',
  created: function () {
    console.log(this.$options.customOption) // => 'foo'
  }
})

可以利用 $options.name 来筛选组件

4. $parent $root $children

  • 父实例,如果当前实例有的话。

  • 当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。

  • 当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。

5. $slots

用来访问被插槽分发的内容。每个具名插槽有其相应的 property (例如:v-slot:foo 中的内容将会在 vm.$slots.foo 中被找到)。default property 包括了所有没有被包含在具名插槽中的节点,或 v-slot:default 的内容。

<slot name:"foo"></slot>

上面插槽的内容可以在 $slots.foo 里找到

6. $refs

一个对象,持有注册过 ref attribute 的所有 DOM 元素组件实例。

7. $attrs

包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。

解决的问题就是 祖父-父-子 组件之间透传的 props ,

<template>
    <div style="padding:50px;">
        <childcom :name="name" :age="age" :sex="sex"></childcom>
    </div>
</template>
<script>
export default {
    'name':'test',
    props:[],
    data(){
        return {
            'name':'张三',
            'age':'30',
            'sex':'男'
        }
    },
    components:{
        'childcom':{
            template:`<div>
                <div>{{name}}</div>
                <grandcom v-bind="$attrs"></grandcom>
            </div>`,
            props:['name'],
            components: {
                'grandcom':{
                    template:`<div>{{$attrs}}</div>`,
                }
            }
        }
    }
}
</script>

7. $listeners

和 $attrs 一样区别在于反向传递数据,$listeners可以让你在孙子组件改变父组件的值,解决的是多次 $emit 的问题

<template>
    <div>
        <childcom :name="name" :age="age" :sex="sex" @testChangeName="changeName"></childcom>
    </div>
</template>
<script>
export default {
    'name':'test',
    props:[],
    data(){
        return {
            'name':'张三',
            'age':'30',
            'sex':'男'
        }
    },
    components:{
        'childcom':{
            props:['name'],
            template:`<div>
                <div>我是子组件   {{name}}</div>
                <grandcom v-bind="$attrs" v-on="$listeners"></grandcom>
            </div>`,
           
            components: {
                'grandcom':{
                    template:`<div>我是孙子组件-------<button @click="grandChangeName">改变名字</button></div>`,
                    methods:{
                        grandChangeName(){
                           this.$emit('testChangeName','kkkkkk')
                        }
                    }
                }
            }
        }
    },
    methods:{
        changeName(val){
            this.name = val
        }
    }
}
</script>

8. $on $off $emit $once

实例事件属性

$event,不要用双引号包起来,单独的,特定的参数

$emit('change',$event)

9. propsdata :方便测试

10. getComputedStyle

返回DOM元素的样式对象