vue3知识点集合

551 阅读4分钟

计算属性

html模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护,此时可以考虑使用computed计算属性

<div id="computed-basics">
  <p>Has published books:</p>
  <span>{{ publishedBooksMessage }}</span>
</div>
Vue.createApp({
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  },
  computed: {
    // 计算属性的 getter
    publishedBooksMessage() {
      // `this` points to the vm instance
      return this.author.books.length > 0 ? 'Yes' : 'No'
    }
  }
}).mount('#computed-basics')

计算属性缓存:上面的计算属性也可以写成一个函数来调用,两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的反应依赖关系缓存的。计算属性只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 author.books 还没有发生改变,多次访问 publishedBookMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。而写成函数式,每当触发重新渲染时,调用方法将总会再次执行函数。

计算属性的setter:计算属性默认只有 getter,不过在需要时你也可以提供一个 setter

computed: {
  fullName: {
    // getter
    get() {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set(newValue) {
      const names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}

watch侦听器

当需要在数据变化时执行异步或开销较大的操作时,使用此方式最好。watch会限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态

  const watchExampleVM = Vue.createApp({
    data() {
      return {
        question: '',
        answer: 'Questions usually contain a question mark. ;-)'
      }
    },
    watch: {
      // whenever question changes, this function will run
      question(newQuestion, oldQuestion) {
        if (newQuestion.indexOf('?') > -1) {
          this.getAnswer()
        }
      }
    },
    methods: {
      getAnswer() {
        this.answer = 'Thinking...'
        axios
          .get('https://yesno.wtf/api')
          .then(response => {
            this.answer = response.data.answer
          })
          .catch(error => {
            this.answer = 'Error! Could not reach the API. ' + error
          })
      }
    }
  }).mount('#watch-example')

class与style绑定

对象语法

// 方式一
<div
  class="static"
  :class="{ active: isActive, 'text-danger': hasError }"
></div>
data() {
  return {
    isActive: true,
    hasError: false
  }
}
// 方式二
<div :class="classObject"></div>
data() {
  return {
    classObject: {
      active: true,
      'text-danger': false
    }
  }
}

数组语法

// 方式一
<div :class="[activeClass, errorClass]"></div>
data() {
  return {
    activeClass: 'active',
    errorClass: 'text-danger'
  }
}
// 方式二
<div :class="[isActive ? activeClass : '', errorClass]"></div>

在组件上使用动态class

<div id="app">
  <my-component class="baz"></my-component>
</div>
const app = Vue.createApp({})

app.component('my-component', {
  template: `
    <p :class="$attrs.class">Hi!</p>
    <span>This is a child component</span>
  `
})

可以为 style 绑定中的 property 提供一个包含多个值的数组,常用于提供多个带前缀的值,只会渲染数组中最后一个被浏览器支持的值

<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

条件渲染

可以把一个 <template> 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 <template> 元素。(在template元素上不能使用v-else、v-show)

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS property display。

v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销

不推荐同时使用 v-if 和 v-for。当 v-if 与 v-for 一起使用时,v-if 具有比 v-for 更高的优先级。

列表渲染

v-for遍历数组,不要使用对象或数组之类的非基本类型值作为 v-for 的 key。请用字符串或数值类型的值。

<ul id="array-with-index">
  <li v-for="(item, index) in items" :key="index">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>

v-for遍历对象

<li v-for="(value, name, index) in myObject">
  {{ index }}. {{ name }}: {{ value }}
</li>

可以利用带有 v-for 的 <template> 来循环渲染一段包含多个元素的内容

事件处理

多事件处理

<!-- 这两个 one() 和 two() 将执行按钮点击事件 -->
<button @click="one($event), two($event)">
  Submit
</button>
methods: {
  one(event) {
    // first handler logic...
  },
  two(event) {
    // second handler logic...
  }
}

事件修饰符,使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生

stop:阻止冒泡(通俗讲就是阻止事件向上级DOM元素传递)

prevent:阻止默认事件的发生

capture:捕获冒泡,即有冒泡发生时,有该修饰符的dom元素会先执行,如果有多个,从外到内依次执行,然后再按自然顺序执行触发的事件。

self:将事件绑定到自身,只有自身才能触发,通常用于避免冒泡事件的影响

once:设置事件只能触发一次,比如按钮的点击等

passive:该修饰符大概意思用于对DOM的默认事件进行性能优化

<!-- 阻止单击事件继续传播 -->
<a @click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form @submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a @click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form @submit.prevent></form>

<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div @click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div @click.self="doThat">...</div>

不要把 .passive 和 .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。

按键修饰符

  • .enter
  • .tab
  • .delete (捕获“删除”和“退格”键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input @keyup.enter="submit" />

系统修饰符

在不同操作系统中,系统修饰符可能代表的按键不一样

  • .ctrl
  • .alt
  • .shift
  • .meta
<!-- Alt + Enter -->
<input @keyup.alt.enter="clear" />

<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>

表单输入绑定

v-model 会忽略所有表单元素的 valuecheckedselected attribute 的初始值而总是将当前活动实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件;
  • checkbox 和 radio 使用 checked property 和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。
// 复选框
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
// 单选框
<input type="radio" id="one" value="One" v-model="picked" />
  <label for="one">One</label>

select中如果 v-model 表达式的初始值未能匹配任何选项,<select> 元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。

lazy修饰符

<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg" />

响应式原理(Proxy)

利用Proxy代理,new Proxy创建一个代理对象

let obj = {
    name: '1111',
    age: 8
}
// new Proxy(需要代理的对象, {get(), set()})
let obj2 = new Proxy(obj,{
    // 当访问对象中的某个属性是执行get方法,target参数表示被劫持的对象,property表示访问的属性
    get(target, property){
        return target[property]
    },
    // 修改对象的某个属性时会触发set事件
    set(target, property, newVal) {
        target[property] = newVal
    },
})