Vue

Vue3.x学习笔记

偏向技术
/ 0 评论 / 277 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2021年04月12日,已超过1320天没有更新,若内容或图片失效,请留言反馈。

记录一下学习Vue3.x的过程

基本格式

javascript
const app = Vue.createApp({
    /* TODO */
})
123

vue生命周期

计算属性缓存 VS 方法

计算属性是基于它们的反应依赖关系缓存的,即计算属性中的变量改变才改变,否则多次使用仍旧是上一次的结果。

事件

模板中包含一个特殊变量$event,同样可以有多个方法,比如:

html
<button @click="one($event), two($event)"></button>
1

原来2.x版本是是通过.native修饰符来指明一个原生事件,现在通过 emits 选项在组件上定义已发出的事件,皆为emit事件,emit事件可增加验证,比如:

js
app.component('custom-form', {
  emits: {
    // 没有验证
    click: null,

    // 验证submit 事件
    submit: ({ email, password }) => {
      if (email && password) {
        return true
      } else {
        console.warn('Invalid submit event payload!')
        return false
      }
    }
  },
  methods: {
    submitForm() {
      this.$emit('submit', { email, password })
    }
  }
})
123456789101112131415161718192021

v-model的语法糖与2.x版本也有所不同,2.x是propvalue和事件input,3.x版本是propmodelValue和事件update:modelValue,如果要修改value名称,可以通过向v-model传递参数,比如:

html
<my-component v-model:title="bookTitle"></my-component>
1

子组件修改如下

js
app.component('my-component', {
  props: {
    title: String
  },
  emits: ['update:title'],
  template: `
    <input
      type="text"
      :value="title"
      @input="$emit('update:title', $event.target.value)">
  `
})
123456789101112

利用此特性,通过传递参数,增加多个v-model双向绑定

关于修饰符,3.x版本提供了一个modelModifiers属性,比如默认的,假设有一个v-model.capitalize="myText",那么子组件内的props属性中将会有modelModifiers字段,字段值为{ capitalize: true }。对于带参数的v-model绑定,子组件内的props属性中将会有arg + "Modifiers",比如,v-model:description.capitalize="myText",子组件的props属性上将会有descriptionModifiers字段

组件

可通过inheritAttrs: false来禁用组件属性和事件继承,继承指的是:在模板中引入组件上的属性和事件,会被组件内的根节点继承,比如:

html
<div id="date-picker" class="demo">
  <date-picker @change="showChange" data-status="activated"></date-picker>
</div

<!-- date-picker组件,会继承父级绑定的属性和事件 -->
app.component('date-picker', {
  template: `
    <select>
      <option value="1">Yesterday</option>
      <option value="2">Today</option>
      <option value="3">Tomorrow</option>
    </select>
  `
})
1234567891011121314

当禁用继承后,我们可以将组件的$attrs属性赋给我们期待的节点上,$attrs属性包括组件 propsemits property 中未包含的所有属性 (例如,classstylev-on 监听器等)。比如:

js
app.component('date-picker', {
  inheritAttrs: false,
  template: `
    <div class="date-picker">
      <input type="datetime" v-bind="$attrs" />
    </div>
  `
})
12345678

多个根节点需显示指定,vue2.x不支持多个根节点

html
<custom-layout id="custom-layout" @click="changeValue"></custom-layout>
1
js
// 这将发出警告
app.component('custom-layout', {
  template: `
    <header>...</header>
    <main>...</main>
    <footer>...</footer>
  `
})

// 没有警告,$attrs被传递到<main>元素
app.component('custom-layout', {
  template: `
    <header>...</header>
    <main v-bind="$attrs">...</main>
    <footer>...</footer>
  `
})
1234567891011121314151617

插槽slot

插槽缩写:#

2.x版本通过slot="<slot_name>"声明使用一个具名插槽,3.x版本通过v-slot:<slot_name>声明使用

2.x版本通过slot-scope="<attribute>"来绑定属性,3.x版本通过v-slot:<slot_name>="<attribute>"来绑定属性

需要注意的是,v-slotv-slot:<slot_name>不能混用,容易导致作用域不明确

支持动态插槽名,v-slot:[dynamicSlotName]

Provide / Inject

跨祖孙组件传递数据时很有用,假设有一个组件继承关系如下,A组件包含B组件,B组件包含C组件,如果有需求需要A组件传值给C组件,可通过以下方式

js
// A组件
provide: {
  user: 'John Doe'
}

// C组件
inject: ['user']
1234567

需要注意的是,如果provide了组件实例上的属性,将会抛出异常,但是,如果provide返回了对象的函数,将会可以正常传递

js
app.component('todo-list', {
  data() {
    return {
      todos: ['Feed a cat', 'Buy tickets']
    }
  },
  provide: {
    todoLength: this.todos.length // 将会导致错误 `Cannot read property 'length' of undefined`
  },
  template: `
    ...
  `
})
12345678910111213
js
app.component('todo-list', {
  data() {
    return {
      todos: ['Feed a cat', 'Buy tickets']
    }
  },
  provide() {
    return {
      todoLength: this.todos.length // 正常传递
    }
  },
  template: `
    ...
  `
})
123456789101112131415

默认情况下,传递不是响应式的,即todoLength改变,inject接收到的值不会跟着改变,可以通过传递一个 ref property 或 reactive 对象给 provide 来改变这种行为。这里通过分配一个组合式 API computed 来保持响应式。

js
provide() {
  return {
    todoLength: Vue.computed(() => this.todos.length)
  }
}
12345

组合式API

setup函数接收propscontext参数,setup返回的内容将暴露给组件其余部分,还可以返回一个渲染函数

context有三个参数,attrsslotsemit

ref接收参数,内部将其响应式,并返回一个带有value属性的对象,因为对象是引用传递,而NumberString是值传递

引用传递

toRefs,响应式对象不能使用ES6解构,因为它会消除响应性,通过toRefs可以实现ES6解构,比如props

toRef可以给响应式对象添加一个响应式的属性,比如const title = toRef(props, 'title')

reactive为JavaScript 对象创建响应式状态

Ref 展开仅发生在被响应式 Object 嵌套的时候。当从 Array 或原生集合类型如 Map访问 ref 时,不会进行展开:

setup中也可以使用生命周期钩子,结构前缀为 on,比如onMounted

watch响应式更改,接收3个参数

  • 一个响应式引用或getter函数
  • 一个回调
  • 可选的配置选项

执行setup时,组件实例尚未被创建,因此只能访问propsattrsslotsemit,无法访问datacomputedmethods

自定义指令

钩子函数相比2.x版本有所变化

  • created:在绑定元素的 attribute 或事件监听器被应用之前调用,在指令需要附加须要在普通的 v-on 事件监听器前调用的事件监听器时,这很有用。
  • beforeMount:当指令第一次绑定到元素并且在挂载父组件之前调用。
  • mounted:在绑定元素的父组件被挂载后调用。
  • beforeUpdate:在更新包含组件的 VNode 之前调用。
  • updated:在包含组件的 VNode 及其子组件的 VNode 更新后调用。
  • beforeUnmount:在卸载绑定元素的父组件之前调用
  • unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次。

teleport

可以自定义挂载到的元素,比如<teleport to="body">

渲染函数

js
// @returns {VNode}
h(
  // {String | Object | Function | null} tag
  // 一个 HTML 标签名、一个组件、一个异步组件,或者 null。
  // 使用 null 将会渲染一个注释。
  //
  // 必需的。
  'div',

  // {Object} props
  // 与 attribute、prop 和事件相对应的对象。
  // 我们会在模板中使用。
  //
  // 可选的。
  {},

  // {String | Array | Object} children
  // 子 VNodes, 使用 `h()` 构建,
  // 或使用字符串获取 "文本 Vnode" 或者
  // 有插槽的对象。
  //
  // 可选的。
  [
    'Some text comes first.',
    h('h1', 'A headline'),
    h(MyComponent, {
      someProp: 'foobar'
    })
  ]
)
123456789101112131415161718192021222324252627282930

Proxy

Proxy 是一个包含另一个对象或函数并允许你对其进行拦截的对象。使用语法new Proxy(target, handler)

1

评论 (0)

取消