Vue(三)——组件

组件的注册

vue 中,我们可以通过 new Vue 来创建一个组件,不过通常它是作为整个应用的顶层根组件存在的,我们还可以通过另外的方式来注册一个更为通用的组件

一、Vue.component()

Vue.component('组件名称', {组件选项})
  •  组件名称遵循自定义组件命名规范:全小写、连字符(如,kkb-cricle。虽然驼峰式一般也没问题)
  • 组件选项与 new Vue 选项配置基本一致(也有一些细节的不同)

如果要在子组件中监听js原生事件,需要使用指令修饰符".native":

如下,直接写@click="fn"函数是 不会起作用的


    

1.1全局组件与局部组件

通过 Vue.component 注册的组件,我们称为全局组件,因为它可以在任意范围内使用,我们还可以定义局部组件

new Vue({
  ...,
  components: {
  	'组件名称': {组件选项}	
	}
})

在一个组件内部通过 components 选项注册的组件是局部组件,只能在当前 components 选项所在的组件内部使用  

注意:局部注册的组件只能中当前注册的组件中使用,不能在它的子组件中使用

二、data

在非 new Vue 的组件(局部组件)中,data 必须为函数,函数返回值必须是一个对象,作为组件的最终 data 。(为避免共用同一个对象)

为什么局部组件data必须为函数,且返回值必须是一个对象?

因为组件的复用性,如果局部组件中用的是对象,则多个组件可能用的是同一个对象。为解决多个组件可能会共用data中的同一个对象问题,局部组件中,data是一个函数,返回值是一个对象。每次实例化一个局部组件时都会去调用一次data()方法,方法再返回一个对象,这样每个组件得到的数据结构是一样的,但是都是通过一个新的函数调用生成的,所以各个组件之间产生的对象就不会冲突。

而根组件只有一个,所以data不会冲突。

三、props

组件中内部私有数据存储中组件 data 中,通过外部传入的数据,则通过 props 选项接收。

注意

  • 自定义组件不能用自结束标签形式(如,
  •  如果传入的 props 值为一个表达式,则必须使用 v-bind。如果直接传入值则不需要;
  • 组件中的 dataprops 数据都可以通过组件实例进行直接访问
  • data 中的 keyprops 中的 key 不能冲突

需求:自定义两个组件,计算圆的面积。

通过局部注册方式实现;





    
    
    组件



    

四、组件通信

注意:不要修改 props 传入的数据

父组件通过 props 传入数据到子组件内部,但是子组件内部不要修改外部传入的 propsvue 提供了一种事件机制通知父级更新,父级中使用子组件的时候监听对应的事件绑定对应的处理函数即可

props数据的在子组件中的两种用法:

  • 在子组件中直接展示;
  • 如果组件的数据是要变化的,则通过data存储。如果子组件需要改变props中传入的值,可以将props作为data的初始值。如props: ['quantity'],  c_quantity: this.quantity;

4.1 $emit()

vue 为每个组件对象提供了一个内置方法 $emit() ,它等同于自定义事件中的 new Event,trigger

this.$emit('自定义事件名称', 事件数据)
  •  事件数据就是中触发事件的同时携带传递的数据 - event
  • 父级在使用该组件的过程中,可以通过 @事件名称 来注册绑定事件函数
  • 事件函数的第一个参数就是事件数据。如,incrementSum(v)的参数v。

示例:需求:父组件中传入值,两个子组件按钮点击后进行累加,最后由父组件计算两个子组件累加和。





    
    
    组件——组件通信



    

父组件:{{p_quantity}}


react采用的是回调方式,,vue采用事件机制。

react:

move(function(){

})

function move(callback){
    callback();
}

vue:

move().addEventListener('end',()=>{
    ....
});

 

五、组件双绑的实现

虽然并不推荐在组件内部修改 props ,但是,有的时候确实希望组件内部状态变化的时候改变 props ,我们可以通过子组件触发事件,父级监听事件来达到这个目的,不过过程会比较繁琐,vue 提供了一些操作来简化这个过程

需求:模拟面板的展开、收缩功能时数据双绑。此处使用v-bind,v-model和 .sync三种方式实现。

5.1 v-bind手动实现双绑

步骤分析:

  • 通过外部传入的expanded数据控制面板展开收缩;
  • 使用外部button值真假,控制面板收缩展开,同时子组件接收外部的标题,内容等数据;
  • button点击面板展开收缩,面板标题点击时也展开收缩(两者数据一致)

示例:





    
    
    组件——v-bind实现数据双绑
    



    



5.2 v-model实现双绑

v-modelvue 提供的一个用于实现数据双向绑定的指令,用来简化 props 到 datadata 到 props 的操作流程。

v-model注意点

  • v-model只能有一个值传入,进行事件绑定
  • 子组件中使用model属性中的prop属性(默认绑定value)进行双绑,并通过model中的触发event属性中定义的事件(默认input事件)
  • 如果this.$emit('change',this.status)事件与model中的event是一致的,则这个函数的第二个参数的值将自动更新与model中自动绑定的数据(不用再绑定change事件和事件实现方法)
  • 不要滥用v-model,确定子组件与外部有关联才使用,如果外部传入了如v-bind="expand",则子组件中的model属性就失效了
  • 通过 v-model 来进行双向绑定,会给状态维护带来一定的问题,因为修改比较隐蔽,同时只能处理一个 prop 的绑定

5.2.1 model选项

prop 指定要绑定的属性,默认是 value

event 指定要绑定触发的事件,默认是 input 事件

示例:





    
    
    组件——v-model实现数据双绑
    



    



示例单选按钮的双绑:




    
    
    
    Document
    


    



5.3 .sync 实现双绑

通过 v-model 来进行双向绑定,会给状态维护带来一定的问题,因为修改比较隐蔽,同时只能处理一个 prop 的绑定,我们还可以通过另外一种方式来达到这个目的。

可以同步多个值。

5.2.1 update:[prop]

这里事件名称要使用 update 加上 prop 名称 的格式

示例:




    
    
    
    Document
    


    

val1: {{val1}}

val2: {{val2}}


示例二:





    
    
    组件——.sync实现数据双绑
    



    



 

六、插槽

相当于react中的this.props.children。

默认情况下,组件模板解析后会替换整个组件内容,如果我们想在组件引用被包含的内容,可以通过 vue 提供的内置组件 slot 来获取。

如下,在content内容比较少时,可以直接通过content="这是内容"将数据传递到子组件中

slot.css

.dialog {
    position: fixed;
    left: 50%;
    top: 30%;
    transform: translateX(-50%) translateY(-50%);
    border-radius: 2px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
    box-sizing: border-box;
    background: #fff;
    width: 30%;
}

.dialog_header {
    padding: 20px 20px 0;
    text-align: left;
}

.dialog_title {
    font-size: 16px;
    font-weight: 700;
    color: #1f2d3d;
}

.dialog_content {
    padding: 30px 20px;
    color: #48576a;
    font-size: 14px;
    text-align: left;
}

.dialog_close_btn {
    position: absolute;
    right: 10px;
    top: 5px;
}

.dialog_close_btn:before {
    content: 'x';
    color: #999;
    font-size: 20px;
    cursor: pointer;
}




    
    
    
    插槽



    

这是内容

但是当content内容足够多时再使用这种方式就不能用,如content内容是form表单或者table。如果写在子组件内部,这个表格等又会被子组件中定义的template内容覆盖:





    
    
    
    插槽



    
1 2 3

此时就需要使用slot插槽:此时的即代表子组件下的内容,包括p标签和整个table不会被覆盖,同时template中的title也可以显示。





    
    
    
    插槽slot



    

这是内容

1 2 3

Vue(三)——组件_第1张图片 

 

6.1具名插槽

6.1.1 v-slot

使用内置组件 templatev-slot 指令进行配置,用来命名插槽,在组件模板中,通过 来使用

  1. 取名
  2. 使用来显示,不写名字即为默认插槽




    
    
    
    具名插槽



    

6.2作用域插槽

组件内部与组件包含的内容属于不同的作用域(被包含的内容是组件父级下的作用域)。

在slot标签中,使用例如:user="user"形式将数据传递给父级组件。父级组件通过如,进行获取。

注意:作用域插槽中,父级组件接收到的数据都是对象形式的。如 则

{{data}}

接收到的数据形式为{a:"1";b:"2"}。





    
    
    
    作用域插槽



    

 

七、props验证

组件的 props 就是组件的参数,为了确保传入的数据在可控的合理范围内,我们需要对传入的 props 的值类型进行必要的验证

Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

 示例:





    
    
    props验证



    

结果:没有通过校验会直接报错

Vue(三)——组件_第2张图片

八、非prop特性

一个非 prop 特性是指传向一个组件,但是该组件并没有相应 prop 定义的特性,这些 props 会被自动添加到组件的根元素上

九、替换/合并已有的特性

默认情况下,非prop 特性的属性会覆盖组件根元素上同名的内容,但是针对 styleclass 有特殊的处理,它们会合并(同名样式还是会覆盖)

十、禁用特性继承

如果你不希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false,我们可以通过组件的 this.$attrs 来获取这些属性

注意 inheritAttrs: false 选项不会影响 styleclass 的绑定

你可能感兴趣的:(Vue,前端,vue,Vue组件)