vaakian / vaakian.github.io

some notes
https://vaakian.github.io
3 stars 0 forks source link

Vue 不常用但实用的小tips #1

Open vaakian opened 4 years ago

vaakian commented 4 years ago

复选框的双向绑定,自动填入hobbies数组中。

<label :key="index" v-for="(item, index) in [1, 2, 3, 4, 5]">
        <input type="checkbox" :value="item" v-model="hobbies" />
        {{item}}
</label>

父组件使用@hook:mounted调用子组件生命周期钩子事件,本质上是子组件生命周期执行时,会进行this.$emit('hook:mounted', ...args),也就是Vue提供的子组件调用父组件$emit方法。

父组件通过props与子组件通信,子组件通过$emit向父组件发送原生事件通信。

Parent -- props --> Child

Child -- $emit --> Parent

Parent.vue

<template>
    <Child @hook:mounted="doSomething" />
</template>

2021-9-15尝试,该方法在vue3中已经不适用,取而代之的是:@vnode-mounted

<Child @vnode-before-mount="onMount"></Child>

在vue3中使用,挂载子组件生命周期方法对应如下:

beforeCreate -> @vnode-before-create
created -> @vnode-created
mounted -> @vnode-mounted
beforeMount-> @vode-before-mount

....

使用functional声明纯函数组件,没有生命周期、data、methods等等,只单纯渲染,性能更优。 同样的,和非纯函数组件一样,我们可以props访问父组件传递的参数。 2021-09-15 更新,发现functional已经no longer supported了。

image
<template functional> is no longer supported in Vue 3, since functional components no longer have significant performance difference from stateful ones. Just use a normal <template> instead.
<template functional>
    <div>{{ props.message }}</div>
</template>

自定义组件直接使用@click绑定点击事件是行不通的,需要使用.native修饰符,Vue内部最终会自动处理,子组件被点击后,触发一个$emit('click')事件从而执行父组件绑定的click事件。

<template>
    <Child @click.native="doSomething" />
</template>
vaakian commented 4 years ago

插槽slot,父组件访问slot传过来的值。

子组件使用slot创建插槽,使用name添加具名插槽。

创建一个组件,有两个插槽:name-boxsex-boxname-box绑定了一个data属性,称之为插槽 prop

MyDiv.vue

<template functional>
  <div>
      someThing in the component.
    <slot :data="{name: 'xwj', age: 21}" name="name-box">name-default</slot>
    <slot name="sex-box">sex-default</slot>
  </div>
</template>

父组件使用<template v-slot:slot-name="propsName"></template>调用,并访问插槽props

<template>
    <div>
         <MyDiv>
                <template v-slot:name-box="slotProps"> // 此处slotProps可以使用es6解构语法
                     name: {{ slotProps.data.name }}, age: {{ slotProps.data.age }}
                </template>
         </MyDiv>
    </div>
</template>

v-onv-bind 一样,v-slot 也有缩写,即把参数之前的所有内容(v-slot:)替换为字符 #。例如v-slot:header可以被重写为 #header

<template>
    <div>
         <MyDiv>
                <template #name-box="slotProps"> // 此处slotProps可以使用es6解构语法
                     name: {{ slotProps.data.name }}, age: {{ slotProps.data.age }}
                </template>
         </MyDiv>
    </div>
</template>
vaakian commented 4 years ago

动态组件,根据组件名自动切换。

非常适用于导航栏切换。

使用v-bind:is或者简写:is使用动态组件

<component v-bind:is="currentTabComponent"></component>
// currentTabComponent是一个字符串,代表组件名

每次切换组件,组件都会被重新render,如果需要缓存起来的话,需要使用vue提供的<keep-alive>元素将组件包裹起来。

//失活的组件将会被缓存
<keep-alive>
    <component v-bind:is="currentTabComponent">
          // 这里可以往组件的slot里插入数据
    </component>
</keep-alive>
vaakian commented 4 years ago

使用_vm.$onice()

vaakian commented 4 years ago

$listners和$attrs透传,用于创建高阶组件。 所有的@/v-on对于子组件,都通过$listeners获得。 所有的:/v-bind对于子组件,都通过$attrs获得。

首先,$listeners是什么?

假设有父组件Parent和子组件Child

// Parent
<template>
  ...
  <child v-on:event-one="methodOne" v-on:event-two="methodTwo" />
  ...
</template>

那么你在使用Child时,传入的所有v-on事件都可以在$listeners对象中找到。

// Child
created () {
  console.log(this.$listeners) // { 'event-one': f(), 'event-two': f() }
}

应用场景,子组件内的子组件触发事件。

// Parent
<template>
  ...
  <child v-on:event-one="methodOne" v-on:event-two="methodTwo" />
  ...
</template>

// Child1
<template>
  ... // 一些其他组件
  <Child2 v-bind="$listeners" />
  ...
</template>

// Child2
created() {
    this.$emit("method-one", ...args); // 可触发Parent绑定的事件。
}

$attrs:组件获得的所有属性。

// Parent
<template>
  ...
  <MyInput v-bind:value="value" type="text" maxlength="20" />
  ...
</template>
// MyInput

<template>
  ...
  <input v-bind="$attrs" /> // 可获得 value="value" type="text" maxlength="20"等参数
  ...
</template>

综合应用,v-model透传。

我们知道,v-model等价于

<input :value="name" @input="name = $event.target.value">
//<input v-bind:value="name" v-on:input="name = $event.target.value">

这里有v-bind($attrs)和v-on($listeners)所以要实现v-model透传,只需要将这两个参数透传下去即可。

// Parent
<template>
  ...
  <MyInput v-model="value" type="text" maxlength="20" />
  ...
</template>
// MyInput

<template>
  ...
  <input v-bind="$attrs" v-bind="$listenters" /> // 错,只允许一次v-bind
<input v-bind="{...$attrs, ...$listenters}" /> // 合并对象
  ...
</template>

总结:v-on/@绑定的事件,子组件使用$listeners获得;v-bind/:绑定的属性,子组件使用$attrs获得。使用v-bind="$attrs/$listenrs" 全部赋予另外的组件。

vaakian commented 4 years ago

父组件使用v-bind:attr.sync,子组件使用$emit("update:attr", value),达到子组件修改父组件绑定的属性值,attr不允许驼峰命名。使用-作为分隔符。

例子:更优雅的子组件双向绑定

// Parent
<template>
    <MyInput type="text" :value.sync="title" /> 
// attr不一定是value,可随意指定。但只是input->title单向绑定了,需要在子组件内手动绑定v-bind:value="$attrs.title"(不写props的话)
</template>
export default {
  data() {
    return {
      title: "hello"
    };
  }
};
// MyInput
<template>
    <input v-bind="$attrs" @input="event => $emit("update:value", event.target.value)" />
</template>