组件注册

全局注册

  1. 注册组件,传入一个扩展过的构造器
    Vue.component('my-component', Vue.extend({/*...*/}))
    
  2. 注册组件,传入一个选项对象(自动调用Vue.extend)
    Vue.component('my-component', {/*...*/})
    
  3. 获取注册的组件(始终返回构造器)
    let MyComponent = Vue.component('my-component')
    

局部注册

  1. 通过普通的javascript对象来定义组件
    var MyComponent = {/*...*/}
    
  2. 在component选项中定义要使用的组件
    new Vue({
        el:'#app',
        component:{
        'my-component': MyComponent
        }
    })
    

自动化全局注册组件

  • 主要使用require.context
    const contexts = require.context(
        './MyComponent',  // 其组件目录的相对路径
        false,            // 是否查询其子目录
        /\.vue$/          // 匹配基础组件文件名的正则表达式
    )
    
    contexts.keys().forEach(component =>{
        // 如果这个组件选项是通过`export.default` 导出的
        // 那么就会优先使用default
        const componentConfig = contexts(component).default
        // 全局注册组件
        Vue.component(componentConfig.name, componentConfig)
    })
    

组件核心

属性prop

单向数据流

  • 传递初始值,并作为本地数据来调用
    {
        props:['count'],
        data(){
            return {
                counter: this.count
            }
        }
    }
    
  • 传入初始值,使用计算属性来进行装换
    {
        props:['str'],
        computed: {
            normalizedStr(){
                return this.str.trim().toLowerCase()
            }
        }
    }
    

双向绑定```// 子组件派发事件,更新名为title的propthis.$emit('update:title',newTitle)// 父组件监听事件并更新本地数据属性<text-document:title='doc.title'@update:title='doc.title = $event'></text-document>

// 上面可以简写成如下
<text-document
    :title.sync='doc.title'
>
</text-document>

//  如果用一个对象同时设置多个prop时可以采用如下写法
<text-document
    v-bind.sync = 'doc'
>
</text-document>
```

特性继承

  • 默认情况下父作用域的不被认作 props 的特性绑定将会“回退”且作为普通的 HTML 特性应用在子组件的根元素上。
  • 通过inheritAttrs设置为false可将其禁用
  • 反之,$attrs可以让这些特性生效,并提供访问,它包含了父级所有不被prop识别的特性绑定。
  • 使用v-bind=“$attrs”可以将这些特性传入内部组件
  • 注意:class和style例外,vue会对其进行特别处理。

见下代码

Vue.component('base-input', {
    inheritAttrs: false,
    props: ['label', 'value'],
    template: `
    <label>
    {{label}}
    <input
        v-bind="$attrs"
        :value="value"
        @input="$emit('input',$event.target.value)"
    >
    </label>
    `
})

事件

自定义事件

  • 通过v-model语法糖实现数据双向绑定
Vue.component('base-checkbox', {
    model: {
        prop: 'checkbox',
        event: 'change'
    },
    props: {
        checked:Boolean
    },
    template: `
    <input
    type="checkbox"
    :checked="checked"
    @change="$emit('change',$event.target.checked)"
    >
    `
})

绑定原生事件

// 监听组件根元素的原生事件
<base-input
v-on:focus.native="onFocus"
>
</base-input>

// 如果根元素不具备该原生事件,事件监听将静默失败
<label>
    {{label}}
    <input
        v-bind='$attrs'
        :value="value"
        @input="$emit('input',$event.target.value)"
    >
</label>

事件传递

  • $listeners包含了父作用域中的(不含.native修饰符)的v-on事件监听器。
  • 可以通过v-on=“$listeners”传入内部组件。
  • 同时结合v-bind=“$attrs”传入父作用域中所有不被prop识别的属性,完成属性和事件的传递。

下面看一个例子

Vue.component('base-input', {
    inheritAttrs:false,
    props: ['lable', 'value'],
    computed:{
        inputListeners(){
            return Object.assgin({},
            this.$listeners,
            {
                input(event){
                    this.$emit('input',event.target.value)
                }
            }
            )
        }
    },
    template: `
        <label>
            {{label}}
                <input
                    v-bind='$attrs'
                    :value="value"
                    v-on="inputListeners"
                >
        </label>
    `
})

插槽

编译作用域

  • 父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

具名插槽

10-20 04:22