vue关键知识强化

vue关键知识强化:包括/deep/(深度选择器)、@click.native、属性绑定简化写法(v-bind)、attribute属性的绑定和多个prop的简化写法($attrs),v-model的含义,原生事件监听器($listeners)等

1./deep/(深度选择器)

问题:vue组件中,在style设置为scoped的时候,里面在写样式对子组件是不生效的
解决:使用/deep/深度选择器可以使vue组件的style设置为scoped时,其相应的样式仍然对子组件生效(忽略scoped,具有穿透性)
示例:

.wrap{
  .class1{
      font-size:12px;

  }
    /deep/ .class2{

       font-size:20px; //对所有子组件生效.

        /deep/ .class3{   }  //没有必要写多层deep 父类有deep后子类自动也会深度选择 并且这么写在firfox里会失效
    }
}

2.v-bind简化元素属性绑定

v-bind常用用法是将数据绑定到元素属性上,如v-bind:href="",缩写是:href=""

还有一种用法是当元素属性和绑定的对象的key同名时,可以简化为直接绑定该对象(适用于需要绑定属性较多且绑定的属性和绑定对象key同名时)
示例:

<template v-for="item in contractsHeder">
  <el-table-column :fixed="item.fixed" :prop="item.prop" :label="item.label" :width="item.width"
  :key="item.id" :show-overflow-tooltip="item.showOverflowToTip">
  ...
</template>

此时可以简写为

<template v-for="item in contractsHeder">
  <el-table-column v-bind="item"
  :key="item.id" :show-overflow-tooltip="item.showOverflowToTip">
  ...
</template>

3.$attrs-非props的元素属性绑定

官方定义:
$attrs包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)

$attrs常用于元素props外的其他属性绑定(元素props外的其他属性可视为元素的attribute)
使用前提:
1.需要将组件的inheritAttrs改为false

    export default {
        inheritAttrs: false,
        data() {
            return {
                //请求数据词典
                apis: [getCustomerList, getContractInfoList, getMotionList],

ps:inheritAttrs: false(禁用Attribute继承,不让组件的根元素继承 attribute)

2.组件内的props里未声明的属性默认都绑定在attrs属性上

      props: {
            //根据index设置表格数据的api和表头 0:商业伙伴,1:源单名称
            index: {
                type: Number,
                required: true
            },
            visiable: {
                type: Boolean,
                require: true
            },
            title: {
                type: String,
                default: '--'
            },

ps:没有在组件的props中显式声明的属性,默认都会存在于$attrs中,$attrs类似于一个存放组件props属性外的其它属性的对象(可视为attribute属性)

使用$attrs

<!--根组件里的引用的子组件,需要将message title age name 等数据传递到son组件里-->
 <son :message = "message" :title = "title" :age="age" :name = "name"></son>

 <!--子组件里引用孙组件,子组件在props中声明了title属性,剩下的message age name 还要继续往下传递-->
   <grandson :message = "message"  :age="age" :name = "name"></grandson>
  
  <!--此时可简写为-->
  <grandson v-bind="$attrs"></grandson>

ps:$attrs相当于

{message:this.message,age:this.age,name:this.name}

4.$listeners-原生事件绑定

使用条件:组件内inheritAttrs:false(禁用根组件继承attribute属性和原生事件)

根组件

<my-input @focus="focus" />

my-input组件内

<template>
    <div>
        <label>输入框:</label><input v-on="$listeners"/>
    </div>
</template>
<script>
export default {
    inheritAttrs:false,
    ...
}
</script>

5.自定义组件使用v-model

v-model是vue的双向数据绑定,对于input元素,vue默认将v-model传入的值绑定到input的value值上,同时对input的input事件添加监听,触发value值的更改
因此

<input v-model="username" />
<!--全写为-->
<input v-bind:value="username" @input="value=>this.username=value"/>`

自定义组件如何使用v-model?
使用组件内的model属性
格式:

model: {
prop: 'someProp',
event: 'someEvent'
}
this.$emit('someEvent', [returnValueToParent])

示例:

<!--子组件:Child-->
<template>
<div class="child">
  <p>我是儿子,父亲对我说: {{give}}</p>
  <a href="javascript:;"rel="external nofollow" @click="returnBackFn">回应</a>
</div>
</template>
<script>
export default {
  props: {
    give: String
  },
  model: {
    prop: 'give',
    event: 'returnBack'
  },
  methods: {
    returnBackFn() {
      this.$emit('returnBack', '还你200块');
    }
  }
}
</script>

<!--父组件-->
<!--原本写法-->
<Child @returnBack="turnBack" :give="sthGiveChild"></Child>
<!--可简化为-->
<Child v-model="sthGiveChild"></Child>

ps:默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event。
因此如果Child组件内使用value绑定传入的值,使用input触发值修改,那么组件内的model可以省略不写
示例

<!-- Child -->
<template>
<div class="child">
  <p>我是儿子,父亲对我说: {{value}}</p>
  <a href="javascript:;" rel="external nofollow" @click="returnBackFn">回应</a>
</div>
</template>
<script>
export default {
  props: {
    value: String
  },
  methods: {
    returnBackFn() {
      this.$emit('input', '还你200块');
    }
  }
}
</script>

6 @click.native

.native - 侦听组件根元素上的原生事件
普通html元素如button,a等绑定点击事件可以直接使用@click
自定义组件或vue组件(如router-link)等不能直接绑定@click,因为此时vue会认为@click是自定义事件,点击时不会触发行为

vue组件绑定click

<router-link @click="clickHandler"></router-link>

ps:此时vue认为@click是自定义事件,因此点击无效

<router-link @click.native="clickHandler"></router-link>

ps:此时vue会把click监听绑定到router-link的根元素上,即a标签,因此点击能正常监听

自定义组何时使用@click.native?

1.自定义组件根元素绑定click事件
示例:
Item.vue

<template>
  <!--Item绑定click.native会默认监听该按钮的点击事件-->
  <button><button>
</template>

2.自定义组件内部手动触发click(未经过验证)
示例:
Item.vue

<template>
  <div>
  <button @click="$emit('click'.fn"><button>
  </div>
</template>

此时外围引用Item组件都可以写成

<Item @click.native="clickHandler"><Item>

此时和以下无区别

<!--外围引用Item组件-->
<Item @receive="clikHandler"></Item>

<!--Item组件内部-->
<template>
  <div>
  <button @click="$emit('receive')"><button>
  </div>
</template>

ps:@click.native具备onclick的一切特性,比如event属性

其他

1.computed可以看作组件的另一个data集,只不过是对data的二次改造后的data,可以返回函数,具有缓存特性

2.watch深度监听和立即监听

watch: {
    docData: {
        handler(newVal) {
            this.change_number++
        },
        //组件初始化立即监听该值,早于组件created执行
        immediate: true,
        //深度监听值的每层,如无必要不必开启,影响性能
        deep:true
    }
}

3.sync使用

<!--子组件-->
<template>
    <label class="child">
        输入框:
        <input :value=val @input="$emit('update:val',$event.target.value)"/>
    </label>
</template>
<script>
export default {
    props:['val']
}
</script>

<!--父组件-->
<template>
  <div class="parent">
    <child :val.sync="name"></child>
    <!--等同于-->
     <child :val="name" @val.update="updateHandler"></child>
  </div>
</template>


最后,以下代码可以强化记忆v-bind,v-on,$attrs,$listeners

<template>
    <div>
        <label>输入框:</label><input v-bind="$attrsAll" v-on="$listenserAll"/>
    </div>
</template>
<script>
export default {
    inheritAttrs:false,
    props:['value'],
    computed:{
         $attrsAll() {
            return {
                value: this.value,
                ...this.$attrs
            }
        },
        $listenserAll(){
            return Object.assign(
                {},
                this.$listeners,
                {input:(event) => this.$emit('input',event.target.value)})
        }
    }
}
</script>

原文地址:https://www.cnblogs.com/ggymx/p/13511487.html