首页 > 其他分享 >初始vue3——第三天

初始vue3——第三天

时间:2023-06-09 16:36:02浏览次数:48  
标签:const watch 第三天 value 侦听器 vue3 组件 ref 初始

双向绑定

基本用法

在前端处理表单时,我们常常需要将表单输入框的内容同步给 JavaScript 中相应的变量。手动连接值绑定和更改事件监听器可能会很麻烦:

<input :value="text" @input="event => text = event.target.value">

v-model 指令帮我们简化了这一步骤:

<input v-model="text">

另外,v-model 还可以用于各种不同类型的输入,textareaselect 元素。它会根据所使用的元素自动使用对应的 DOM 属性和事件组合:

  • 文本类型的 inputtextarea 元素会绑定 value 并侦听 input 事件;
  • checkboxradio 会绑定 checked 并侦听 change 事件;
  • select 会绑定 value 并侦听 change 事件。

修饰符

  • .lazy
    默认情况下,v-model 会在每次 input 事件后更新数据 (IME 拼字阶段的状态例外)。你可以添加 lazy 修饰符来改为在每次 change 事件后更新数据:
  • .number
    如果你想让用户输入自动转换为数字,你可以在 v-model 后添加 .number 修饰符来管理输入。如果该值无法被 parseFloat() 处理,那么将返回原始值。.number 修饰符会在输入框有 type="number" 时自动启用。
  • .trim
    如果你想要默认自动去除用户输入内容中两端的空格,你可以在 v-model 后添加 .trim 修饰符.

生命周期

每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码。
image
举例来说,onMounted 钩子可以用来在组件完成初始渲染并创建 DOM 节点后运行代码:

<script setup>
import { onMounted } from 'vue'

onMounted(() => {
  console.log(`the component is now mounted.`)
})
</script>

还有其他一些钩子,会在实例生命周期的不同阶段被调用,最常用的是 onMountedonUpdatedonUnmounted。所有生命周期钩子的完整参考及其用法请参考 API 索引。

侦听器

基本用法

计算属性允许我们声明性地计算衍生值。然而在有些情况下,我们需要在状态变化时执行一些“副作用”:例如更改 DOM,或是根据异步操作的结果去修改另一处的状态。
在组合式 API 中,我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数:

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

const question = ref('')
const answer = ref('Questions usually contain a question mark. ;-)')

// 可以直接侦听一个 ref
watch(question, async (newQuestion, oldQuestion) => {
  if (newQuestion.indexOf('?') > -1) {
    answer.value = 'Thinking...'
    try {
      const res = await fetch('https://yesno.wtf/api')
      answer.value = (await res.json()).answer
    } catch (error) {
      answer.value = 'Error! Could not reach the API. ' + error
    }
  }
})
</script>

<template>
  <p>
    Ask a yes/no question:
    <input v-model="question" />
  </p>
  <p>{{ answer }}</p>
</template>

数据源类型

watch 的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组:

const x = ref(0)
const y = ref(0)

// 单个 ref
watch(x, (newX) => {
  console.log(`x is ${newX}`)
})

// getter 函数
watch(
  () => x.value + y.value,
  (sum) => {
    console.log(`sum of x + y is: ${sum}`)
  }
)

// 多个来源组成的数组
watch([x, () => y.value], ([newX, newY]) => {
  console.log(`x is ${newX} and y is ${newY}`)
})

注意,你不能直接侦听响应式对象的属性值,这里需要用一个返回该属性的 getter 函数:

const obj = reactive({ count: 0 })

// 错误,因为 watch() 得到的参数是一个 number
watch(obj.count, (count) => {
  console.log(`count is: ${count}`)
})

// 提供一个 getter 函数
watch(
  () => obj.count,
  (count) => {
    console.log(`count is: ${count}`)
  }
)

深层侦听

直接给 watch() 传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发:

const obj = reactive({ count: 0 })

watch(obj, (newValue, oldValue) => {
  // 在嵌套的属性变更时触发
  // 注意:`newValue` 此处和 `oldValue` 是相等的
  // 因为它们是同一个对象!
})

obj.count++

相比之下,一个返回响应式对象的 getter 函数,只有在返回不同的对象时,才会触发回调。可以显式地加上 deep 选项,强制转成深层侦听器:

watch(
  () => state.someObject,
  () => {
    // 仅当 state.someObject 被替换时触发
  }
)

watch(
  () => state.someObject,
  (newValue, oldValue) => {
    // 注意:`newValue` 此处和 `oldValue` 是相等的
    // *除非* state.someObject 被整个替换了
  },
  { deep: true }
)

及时回调

watch 默认是懒执行的:仅当数据源变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调。我们可以通过传入 immediate: true 选项来强制侦听器的回调立即执行:

watch(source, (newValue, oldValue) => {
  // 立即执行,且当 `source` 改变时再次执行
}, { immediate: true })

watchEffect()

侦听器的回调使用与源完全相同的响应式状态是很常见的。例如下面的代码,在每当 todoId 的引用发生变化时使用侦听器来加载一个远程资源:

const todoId = ref(1)
const data = ref(null)

watch(todoId, async () => {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
  )
  data.value = await response.json()
}, { immediate: true })

特别是注意侦听器是如何两次使用 todoId 的,一次是作为源,另一次是在回调中。
我们可以用 watchEffect 函数 来简化上面的代码。watchEffect() 允许我们自动跟踪回调的响应式依赖。上面的侦听器可以重写为:

watchEffect(async () => {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
  )
  data.value = await response.json()
})

这个例子中,回调会立即执行,不需要指定 immediate: true。在执行期间,它会自动追踪 todoId.value 作为依赖(和计算属性类似)。每当 todoId.value 变化时,回调会再次执行。有了 watchEffect(),我们不再需要明确传递 todoId 作为源值。
对于这种只有一个依赖项的例子来说,watchEffect() 的好处相对较小。但是对于有多个依赖项的侦听器来说,使用 watchEffect() 可以消除手动维护依赖列表的负担。此外,如果你需要侦听一个嵌套数据结构中的几个属性,watchEffect() 可能会比深度侦听器更有效,因为它将只跟踪回调中被使用到的属性,而不是递归地跟踪所有的属性。

触发时机

当你更改了响应式状态,它可能会同时触发 Vue 组件更新和侦听器回调。默认情况下,用户创建的侦听器回调,都会在 Vue 组件更新之前被调用。这意味着你在侦听器回调中访问的 DOM 将是被 Vue 更新之前的状态。如果想在侦听器回调中能访问被 Vue 更新之后的 DOM,你需要指明 flush: 'post' 选项:

watch(source, callback, {
  flush: 'post'
})

watchEffect(callback, {
  flush: 'post'
})

后置刷新的 watchEffect() 有个更方便的别名 watchPostEffect()

import { watchPostEffect } from 'vue'

watchPostEffect(() => {
  /* 在 Vue 更新后执行 */
})

模板引用

虽然 Vue 的声明性渲染模型为你抽象了大部分对 DOM 的直接操作,但在某些情况下,我们仍然需要直接访问底层 DOM 元素。要实现这一点,我们可以使用特殊的 ref 属性:

<input ref="input">

ref 是一个特殊的属性,和 v-for 章节中提到的 key 类似。它允许我们在一个特定的 DOM 元素或子组件实例被挂载后,获得对它的直接引用。这可能很有用,比如说在组件挂载时将焦点设置到一个 input 元素上,或在一个元素上初始化一个第三方库。

引用访问

为了通过组合式 API 获得该模板引用,我们需要声明一个同名的 ref

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

// 声明一个 ref 来存放该元素的引用
// 必须和模板里的 ref 同名
const input = ref(null)

onMounted(() => {
  input.value.focus()
})
</script>

<template>
  <input ref="input" />
</template>

注意,你只可以在组件挂载后才能访问模板引用。如果你想在模板中的表达式上访问 input,在初次渲染时会是 null。这是因为在初次渲染前这个元素还不存在呢!

如果你需要侦听一个模板引用 ref 的变化,确保考虑到其值为 null 的情况:

watchEffect(() => {
  if (input.value) {
    input.value.focus()
  } else {
    // 此时还未挂载,或此元素已经被卸载(例如通过 v-if 控制)
  }
})

v-for 中的模板引用

当在 v-for 中使用模板引用时,对应的 ref 中包含的值是一个数组,它将在元素被挂载后包含对应整个列表的所有元素:

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

const list = ref([
  /* ... */
])

const itemRefs = ref([])

onMounted(() => console.log(itemRefs.value))
</script>

<template>
  <ul>
    <li v-for="item in list" ref="itemRefs">
      {{ item }}
    </li>
  </ul>
</template>

应该注意的是,ref 数组并不保证与源数组相同的顺序。

函数模板引用

除了使用字符串值作名字,ref 属性还可以绑定为一个函数,会在每次组件更新时都被调用。该函数会收到元素引用作为其第一个参数:

<input :ref="(el) => { /* 将 el 赋值给一个数据属性或 ref 变量 */ }">

注意我们这里需要使用动态的 :ref 绑定才能够传入一个函数。当绑定的元素被卸载时,函数也会被调用一次,此时的 el 参数会是 null。你当然也可以绑定一个组件方法而不是内联函数。

组件模板引用

模板引用也可以被用在一个子组件上。这种情况下引用中获得的值是组件实例:

<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'

const child = ref(null)

onMounted(() => {
  // child.value 是 <Child /> 组件的实例
})
</script>

<template>
  <Child ref="child" />
</template>

如果一个子组件使用的是选项式 API 或没有使用 <script setup>,被引用的组件实例和该子组件的 this 完全一致,这意味着父组件对子组件的每一个属性和方法都有完全的访问权。这使得在父组件和子组件之间创建紧密耦合的实现细节变得很容易,当然也因此,应该只在绝对需要时才使用组件引用。大多数情况下,你应该首先使用标准的 propsemit 接口来实现父子组件交互。
有一个例外的情况,使用了 <script setup> 的组件是默认私有的:一个父组件无法访问到一个使用了 <script setup> 的子组件中的任何东西,除非子组件在其中通过 defineExpose 宏显式暴露:

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

const a = 1
const b = ref(2)

// 像 defineExpose 这样的编译器宏不需要导入
defineExpose({
  a,
  b
})
</script>

当父组件通过模板引用获取到了该组件的实例时,得到的实例类型为 { a: number, b: number } (ref 都会自动解包,和一般的实例一样)。

标签:const,watch,第三天,value,侦听器,vue3,组件,ref,初始
From: https://www.cnblogs.com/cxy-orange/p/17467449.html

相关文章

  • Ubuntu的初始化
                       1.查看系统中已安装的软件包Ubuntu使用的是dpkg命令管理软件包,在终端输入dpkg-l|more命令确认安装包的信息。结果如下可供参考,其中只截取了一小部分。Ubuntu中经常进行故障修复和功能完善,更新系统需要用到管理员权限。它......
  • 自动初始化
    在LINUX系统中,只有在全局或静态作用域下定义的数组才会被自动初始化为0; 在这种情况下,arr数组在全局下定义,他的元素将会被自动初始化为0,所以他的输出结果是 注意,只有在全局或者静态作用域下定义的数组才会被自动初始化为0;在局部或者函数作用域下定义的数组在为手动......
  • MySQL 5.7 更改初始密码及密码规则
    查看默认的密码规则:showvariableslike'validate_password%';1、修改validate_password_policy参数的值:setglobalvalidate_password_policy=0;2、修改密码长度,默认最短为4位:setglobalvalidate_password_length=6;设置密码:setpassword=password('redhat');......
  • vue3+ TS pinyin uniapp 索引列表-(A-Z)按首字母排序 ,锚点定位
    获取一维数组地址列表<scriptlang="ts"setup>import{getLocationList}from"@/apis/activity";import{onLoad}from"@dcloudio/uni-app";import{pinyin}from"pinyin-pro"import{ref}from"vue";const......
  • ai问答:Vue3中使用computed和watch监听pinia数据的区别
    在Vue3中,通过computed来监听pinia中的state数据:import{defineStore}from'pinia'import{useStore}from'pinia'import{computed}from'vue'conststore=defineStore('store',{/*...*/})exportdefault{setup(){......
  • 神经网络的k和b初始化方式问题笔记
    初始化是为了防止梯度消失和爆炸编写代码,假设输入是512的行向量,经过10个512x512的矩阵,计算输出的平均值和标准差。输入行向量,每个矩阵,都是标准正态分布importtorch#随机生成一个512的输入值,服从正态分布x=torch.randn(512)y=xforiinrange(10):a=torch.rand......
  • 总结vue3 的一些知识点:MySQL 运算符
    MySQL运算符本章节我们主要介绍MySQL的运算符及运算符的优先级。MySQL主要有以下几种运算符:算术运算符比较运算符逻辑运算符位运算符算术运算符MySQL支持的算术运算符包括:运算符作用+加法-减法*乘法/或DIV除法%或MOD取余在除法......
  • 总结vue3 的一些知识点:MySQL NULL 值处理
    MySQLNULL值处理我们已经知道MySQL使用SQLSELECT命令及WHERE子句来读取数据表中的数据,但是当提供的查询条件字段为NULL时,该命令可能就无法正常工作。为了处理这种情况,MySQL提供了三大运算符:ISNULL: 当列的值是NULL,此运算符返回true。ISNOTNULL: 当列的......
  • 总结vue3 的一些知识点:MySQL 排序
    MySQL排序我们知道从MySQL表中使用SQLSELECT语句来读取数据。如果我们需要对读取的数据进行排序,我们就可以使用MySQL的 ORDERBY 子句来设定你想按哪个字段哪种方式来进行排序,再返回搜索结果。语法以下是SQLSELECT语句使用ORDERBY子句将查询数据排序后再返回......
  • 总结vue3 的一些知识点:MySQL NULL 值处理
    MySQLNULL值处理我们已经知道MySQL使用SQLSELECT命令及WHERE子句来读取数据表中的数据,但是当提供的查询条件字段为NULL时,该命令可能就无法正常工作。为了处理这种情况,MySQL提供了三大运算符:ISNULL: 当列的值是NULL,此运算符返回true。ISNOTNULL: 当列的......