首页 > 其他分享 >初识vue3——第二天

初识vue3——第二天

时间:2023-06-08 19:13:57浏览次数:43  
标签:Vue const 修饰符 第二天 初识 计算 vue3 ref 属性

计算属性

为什么要用计算属性

模板中的表达式虽然方便,但也只能用来做简单的操作。如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。比如说,我们想根据 author 是否已有一些书籍来展示不同的信息:

<script setup>
const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})
</script>

<template>
  <p>Has published books:</p>
  <span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
<template>

这里的模板看起来有些复杂,必须认真看好一会儿才能明白它的计算依赖于 author.books。更重要的是,如果在模板中需要不止一次这样的计算,我们可不想将这样的代码在模板里重复好多遍。因此需要使用计算属性来描述依赖响应式状态的复杂逻辑:

<script setup>
import { reactive, computed } from 'vue'

const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})

// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
  return author.books.length > 0 ? 'Yes' : 'No'
})
</script>

<template>
  <p>Has published books:</p>
  <span>{{ publishedBooksMessage }}</span>
</template>

我们在这里定义了一个计算属性 publishedBooksMessagecomputed() 方法期望接收一个 getter 函数,返回值为一个计算属性 ref。和其他一般的 ref 类似,你可以通过 publishedBooksMessage.value 访问计算结果。计算属性 ref 也会在模板中自动解包,因此在模板表达式中引用时无需添加 .value
Vue 的计算属性会自动追踪响应式依赖。它会检测到 publishedBooksMessage 依赖于 author.books,所以当 author.books 改变时,任何依赖于 publishedBooksMessage 的绑定都会同时更新。

计算属性缓存 vs 方法

若我们将同样的函数定义为一个方法而不是计算属性,两种方式在结果上确实是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要 author.books 不改变,无论多少次访问 publishedBooksMessage 都会立即返回先前的计算结果,而不用重复执行 getter 函数。
这也解释了为什么下面的计算属性永远不会更新,因为 Date.now() 并不是一个响应式依赖,相比之下,方法调用总是会在重渲染发生时再次执行函数。

const now = computed(() => Date.now())

可写计算属性

计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到“可写”的属性,你可以通过同时提供 gettersetter 来创建:

<script setup>
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  // getter
  get() {
    return firstName.value + ' ' + lastName.value
  },
  // setter
  set(newValue) {
    // 注意:我们这里使用的是解构赋值语法
    [firstName.value, lastName.value] = newValue.split(' ')
  }
})
</script>

现在当你再运行 fullName.value = 'John Doe' 时,setter 会被调用而 firstNamelastName 会随之更新。

正确使用

Getter 不应有副作用

计算属性的 getter 应只做计算而没有任何其他的副作用,这一点非常重要,请务必牢记。举例来说,不要在 getter 中做异步请求或者更改 DOM!一个计算属性的声明中描述的是如何根据其他值派生一个值。因此 getter 的职责应该仅为计算和返回该值。在之后的指引中我们会讨论如何使用监听器根据其他响应式状态的变更来创建副作用。

避免直接修改计算属性值

从计算属性返回的值是派生状态。可以把它看作是一个“临时快照”,每当源状态发生变化时,就会创建一个新的快照。更改快照是没有意义的,因此计算属性的返回值应该被视为只读的,并且永远不应该被更改——应该更新它所依赖的源状态以触发新的计算。

类与样式绑定

数据绑定的一个常见需求场景是操纵元素的 CSS class 列表和内联样式。因为 classstyle 都是 attribute,我们可以和其他 attribute 一样使用 v-bind 将它们和动态的字符串绑定。但是,在处理比较复杂的绑定时,通过拼接生成字符串是麻烦且易出错的。因此,Vue 专门为 classstylev-bind 用法提供了特殊的功能增强。除了字符串外,表达式的值也可以是对象或数组。

绑定 class

绑定多个 class

<script setup>
const isActive = ref(true)
const hasError = ref(false)
</script>
<template>
  <div class="static" :class="{ active: isActive, 'text-danger': hasError }"></div>
</template>

直接绑定一个 class 对象

<script setup>
const classObject = reactive({
  active: true,
  'text-danger': false
})
</script>
<template>
  <div :class="classObject"></div>
</template>

绑定 class 数组

<script setup>
const activeClass = ref('active')
const errorClass = ref('text-danger')
</script>
<template>
  <div :class="[isActive ? activeClass : '', errorClass]"></div>
  <div :class="[{ active: isActive }, errorClass]"></div>
</template>

子组件 class 传递

<!-- 子组件模板 -->
<p class="foo bar">Hi!</p>

<!-- 在使用组件时 -->
<MyComponent class="baz boo" />

<!-- 子组件渲染结果-->
<p class="foo bar baz boo">Hi!</p>

如果你的组件有多个根元素,你将需要指定哪个根元素来接收这个 class。你可以通过组件的 $attrs 属性来实现指定:

<p :class="$attrs.class">Hi!</p>
<span>This is a child component</span>

<MyComponent class="baz" />

<!-- 子组件渲染结果-->
<p class="baz">Hi!</p>
<span>This is a child component</span>

绑定 style

常用绑定

styleclass 的绑定方式基本相同,在此不做过多介绍:

<template>
  <!-- 绑定属性-->
  <div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
  <!-- 绑定对象-->
  <div :style="styleObject"></div>
  <!-- 绑定数组-->
  <div :style="[baseStyles, overridingStyles]"></div>
</template>

特殊情况

当你在 :style 中使用了需要浏览器特殊前缀的 CSS 属性时,Vue 会自动为他们加上相应的前缀。Vue 是在运行时检查该属性是否支持在当前浏览器中使用。如果浏览器不支持某个属性,那么将尝试加上各个浏览器特殊前缀,以找到哪一个是被支持的。
你可以对一个样式属性提供多个 (不同前缀的) 值,数组仅会渲染浏览器支持的最后一个值。在这个示例中,在支持不需要特别前缀的浏览器中都会渲染为 display: flex

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

条件渲染

批量渲染

因为 v-if 是一个指令,他必须依附于某个元素。但如果我们想要切换不止一个元素呢?在这种情况下我们可以在一个 <template> 元素上使用 v-if,这只是一个不可见的包装器元素,最后渲染的结果并不会包含这个 <template> 元素。

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

v-if 与 v-show 比较

v-if 是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建;v-if 也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。相比之下,v-show 简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display 属性会被切换。
总的来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show 较好;如果在运行时绑定条件很少改变,则 v-if 会更合适。

列表渲染

解构

在定义 v-for 的变量别名时使用解构,和解构函数参数类似:

<li v-for="{ message } in items">
  {{ message }}
</li>

<!-- 有 index 索引时 -->
<li v-for="({ message }, index) in items">
  {{ message }} {{ index }}
</li>

of 遍历

使用 of 作为分隔符来替代 in,这更接近 JavaScript 的迭代器语法:

<div v-for="item of items"></div>

遍历对象

使用 v-for 来遍历一个对象的所有属性。遍历的顺序会基于对该对象调用 Object.keys() 的返回值来决定。

const myObject = reactive({
  title: 'How to do lists in Vue',
  author: 'Jane Doe',
  publishedAt: '2016-04-10'
})
<ul>
  <li v-for="value in myObject">
    {{ value }}
  </li>
</ul>

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

特殊情况

同时使用 v-if 和 v-for 是不推荐的,因为这样二者的优先级不明显。

当它们同时存在于一个节点上时,v-ifv-for 的优先级更高。这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名:

<!--
 这会抛出一个错误,因为属性 todo 此时
 没有在该实例上定义
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo.name }}
</li>

在外新包装一层 <template> 再在其上使用 v-for 可以解决这个问题 (这也更加明显易读):

<template v-for="todo in todos">
  <li v-if="!todo.isComplete">
    {{ todo.name }}
  </li>
</template>

规范写法

为了给 Vue 一个提示,以便它可以跟踪每个节点的标识,从而重用和重新排序现有的元素,你需要为每个元素对应的块提供一个唯一的 key

<template v-for="todo in todos" :key="todo.name">
  <li>{{ todo.name }}</li>
</template>

数组变化侦测

Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。这些变更方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

其中 filter()concat()slice(),这些都不会更改原数组,而总是返回一个新数组。你可能认为这将导致 Vue 丢弃现有的 DOM 并重新渲染整个列表。
幸运的是,情况并非如此。Vue 实现了一些巧妙的方法来最大化对 DOM 元素的重用,因此用另一个包含部分重叠对象的数组来做替换,仍会是一种非常高效的操作。
有时,我们希望显示数组经过过滤或排序后的内容,而不实际变更或重置原始数据。在这种情况下,你可以创建返回已过滤或已排序数组的计算属性。

const numbers = ref([1, 2, 3, 4, 5])

const evenNumbers = computed(() => {
  return numbers.value.filter((n) => n % 2 === 0)
})

在计算属性中使用 reverse()sort() 的时候务必小心!这两个方法将变更原始数组,计算函数中不应该这么做,请在调用这些方法之前创建一个原数组的副本。

事件处理

我们可以使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click="handler"@click="handler"。事件处理器会自动接收原生 DOM 事件并触发执行。

访问原生 DOM 事件

有时我们需要在内联事件处理器中访问原生 DOM 事件。你可以向该处理器方法传入一个特殊的 $event 变量,或者使用内联箭头函数:

<!-- 使用特殊的 $event 变量 -->
<button @click="warn('Form cannot be submitted yet.', $event)">
  Submit
</button>

<!-- 使用内联箭头函数 -->
<button @click="(event) => warn('Form cannot be submitted yet.', event)">
  Submit
</button>
function warn(message, event) {
  // 这里可以访问原生事件
  if (event) {
    event.preventDefault()
  }
  alert(message)
}

事件修饰符

在处理事件时调用 event.preventDefault()event.stopPropagation() 是很常见的。尽管我们可以直接在方法内调用,但如果方法能更专注于数据逻辑而不用去处理 DOM 事件的细节会更好。
为解决这一问题,Vue 为 v-on 提供了事件修饰符。修饰符是用 . 表示的指令后缀,包含以下这些:

  • .stop
  • .prevent
  • .self
  • .capture
  • .once
  • .passive
<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>

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

<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>

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

<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>

使用修饰符时需要注意调用顺序,因为相关代码是以相同的顺序生成的。因此使用 @click.prevent.self 会阻止元素及其子元素的所有点击事件的默认行为,而 @click.self.prevent 则只会阻止对元素本身的点击事件的默认行为。

.capture.once.passive 修饰符与原生 addEventListener 事件相对应:

<!-- 添加事件监听器时,使用 `capture` 捕获模式 -->
<!-- 例如:指向内部元素的事件,在被内部元素处理前,先被外部处理 -->
<div @click.capture="doThis">...</div>

<!-- 点击事件最多被触发一次 -->
<a @click.once="doThis"></a>

<!-- 滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成 -->
<!-- 以防其中包含 `event.preventDefault()` -->
<div @scroll.passive="onScroll">...</div>

.passive 修饰符一般用于触摸事件的监听器,可以用来改善移动端设备的滚屏性能。请勿同时使用 .passive.prevent,因为 .passive 已经向浏览器表明了你不想阻止事件的默认行为。如果你这么做了,则 .prevent 会被忽略,并且浏览器会抛出警告。

按键修饰符

在监听键盘事件时,我们经常需要检查特定的按键。Vue 允许在 v-on@ 监听按键事件时添加按键修饰符。Vue 为一些常用的按键提供了别名:

  • .enter
  • .tab
  • .delete (捕获“Delete”和“Backspace”两个按键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
<!-- 仅在 `key` 为 `Enter` 时调用 `submit` -->
<input @keyup.enter="submit" />

你可以使用以下系统按键修饰符来触发鼠标或键盘事件监听器,只有当按键被按下时才会触发。

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

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

.exact 修饰符允许控制触发一个事件所需的确定组合的系统按键修饰符。

<!-- 当按下 Ctrl 时,即使同时按下 Alt 或 Shift 也会触发 -->
<button @click.ctrl="onClick">A</button>

<!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 仅当没有按下任何系统按键时触发 -->
<button @click.exact="onClick">A</button>

鼠标修饰符

  • .left
  • .right
  • .middle

标签:Vue,const,修饰符,第二天,初识,计算,vue3,ref,属性
From: https://www.cnblogs.com/cxy-orange/p/17460215.html

相关文章

  • vue3 祖孙通信
    利用provide和inject  provide用于向子组件(或子组件中的子组件,无限嵌套)提供自身的一些数据,或者将自身所有属性全部提供,但是提供的数据均为非响应式数据。 inject用于引入父级组件所提供的数据 1、祖父组件import{ref,reactive,provide}from"vue";constgrandFat......
  • uniapp+微信小程序+vue3 实现富文本编辑器遇到的坑
     问题一:富文本编辑器初始化实例出不来,有两个原因:找的参考代码不适用微信小程序,需要用.in(this)uni.createSelectorQuery().in(this).select("#editor").context(res=>{this.editorCtx=res?.context;}).ex......
  • vue3中使用less
    在Vue3中使用Less(LeanerStyleSheets)可以通过以下步骤完成:安装less和less-loader:首先,你需要安装Less和LessLoader依赖。在Vue项目的根目录下,可以使用npm或yarn运行以下命令来安装它们:npminstalllessless-loader或yarnaddlessless-loader配置webpack:VueCLI默认......
  • Vue3从入门到精通(二)
    vue3侦听器在Vue3中,侦听器的使用方式与Vue2相同,可以使用watch选项或$watch方法来创建侦听器。不同之处在于,Vue3中取消了immediate选项,同时提供了新的选项和API。创建侦听器可以使用watch选项或$watch方法来创建侦听器,语法与Vue2相同。示例如下:<template><div>{{messa......
  • 初识云平台-3DEXPERIENCE在线课程 硕迪科技
     3DEXPERIENCE平台可以理解为人与人协作、数据与数据关联、人与数据互动的企业运营支撑平台。本期课程为大家介绍第一次进入3DEXPERIENCE所需要做的一些基础准备工作。内容分为两大部分,一部分是作为平台管理员在平台所需做的基础设置;另一部则是作为平台基本用户可以做的自定义设......
  • 初识C语言:从0开始,由菜鸟变大牛(完结)
    上篇内容分享了两种语句(选择语句、循环语句)、函数、数组、各种操作符,本篇文章我们再来了解关于初识C语言的内容,同样,涉及到的知识不会太复杂,废话不多说,正文开始:1.常见关键字autobreakcasecharconstcontinuedefaultdodoubleelseenumexternfloatf......
  • vue3实现自定义指令
    创建一个empty.jsimport{nextTick}from'vue';constemptyImgUrl=newURL('@/assets/images/empty-icon.jpeg',import.meta.url).href;//在vue3中不支持require引入静态图片,这是一种引入方式另外一种是直接importconstempty={install(app,options){app......
  • Vue3 之 响应式 API reactive、 effect源码,详细注释
    Vue3之响应式APIreactive、effect源码,详细注释目录一.实现响应式API:reactive、shallowReactive、readonly、shallowReadonly1.针对不同的API创建不同的响应式对象2.实现createReactiveObject3.实现不同的拦截函数baseHandlers.ts二.实现响应式effect1.创建响应式的......
  • vue3 mock接口
    以下基于mock的vite-plugin-mock版本为2.9.6实现,其他版本有可能导致报错1.安装依赖:https://www.npmjs.com/package/[email protected].在vite.config.js配置文件启动插件//mock插件提供的方法import{viteMockServe}f......
  • vue3使用ElementPlus的消息el-message样式不生效或者被遮盖(z-index)
    一、el-message自定义样式不生效想改弹出框的位置时不生效,使用了el-message的自定义类的custom-class属性也不行。原因应该是加了scoped后使用到里面样式的dom会添加data-v-xxxx这种属性防止css污染,但是message生成的dom是没有添加data-v-xxx属性的,所以样式无效。解决方式:js动态设......