【前端技术】Vue3 02:基础语法

news2024/12/30 3:24:41

接下来介绍下 Vue 的基础语法,包括渐进式框架、单文件组件、组合式 API 和选项式 API等基础要点和 v-xx 指令和其余基础语法,这和官方教程的顺序不大一致,我认为先学习 v-xx 指令可能更有助于大家的理解及学习。

目录

1 前言

1.1 单文件组件

① 计数器示例

② 单文件运行

③ 项目启动路径

1.2 组合式 API 和选项式 API

① 选项式 API

② 组合式 API

2 v-xx 指令

2.1 v-html

2.2 v-bind

2.3 v-if/show

2.4 v-for

① 列表

② 对象

2.5 v-on

① v-on/@

② 修饰符

2.6 v-model

① 基本用法

② 值绑定

③ 修饰符

3 其余基础语法

3.1 响应式基础

① reactive()

② ref()

3.2 计算属性

3.3 Class 与 Style 绑定

① :class

② :style

3.4 生命周期

① 注册周期钩子

② 生命周期图示

3.5 侦听器

① 侦听数据源类型

② 深层侦听器

③ 即时回调的侦听器

④ watchEffect()

3.6 模板引用

① 访问模板引用

② v-for 中的模板引用

3.7 组件基础

① 定义一个组件

② 使用组件


1 前言

Vue 是一个框架,也是一个生态,其功能覆盖了大部分前端开发常见的需求。有一些内容需要提前了解一下,比如单文件组件及API风格,这样才会对 Vue3 有个大致的轮廓。

1.1 单文件组件

在大多数启用了构建工具的 Vue 项目中,我们可以使用一种类似 HTML 格式的文件来书写 Vue 组件,它被称为单文件组件,简单来说就是 *.vue 文件。Vue 的单文件组件会将一个组件的逻辑 (JavaScript—script),模板 (HTML—template) 和样式 (CSS—style) 封装在同一个文件里。

① 计数器示例

<script>
export default {
  data() {
    return {
      count: 0
    }
  }
}
</script>

<template>
  <button @click="count++">Count is: {{ count }}</button>
</template>

<style scoped>
button {
  font-weight: bold;
}
</style>

单文件组件是 Vue 的标志性功能。如果你的用例需要进行构建,我们推荐用它来编写 Vue 组件。

② 单文件运行

有时我们只是想单独运行某个Vue文件,不依赖src,类似运行单独的 HTML 文件,可以采取以下方式进行:

安装全局扩展

注意:该工具目前只适配 node 17及以下版本,否则会安装失败(使用 node -v 查看 node 版本)

npm install -g @vue/cli-service-global

cd到某vue文件下运行

vue serve

③ 项目启动路径

可以看到项目启动遵循以下路径,首先是 index.html,他作为首页入口设置页面标题,然后引入 main.jsmain.js 相当于是 vue 文件和 index.html 的连接器,它指定哪个 vue 文件作为项目的入口,然后就能看到具体页面了。

那我们测试一下该路径与否,首先创建一个计数器 vue 文件(代码如前边的计数器)👇

第二步在 index.html 修改入口页面的标题:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!--修改标题 👇-->
    <title>Yinyu App</title>
  </head>
  <body>
    <div id="app"></div>
    <!--指定/src/main.js 👇-->
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

第三步在 main.js 指定计数器的 vue 页面:

import { createApp } from 'vue'
// 指定 count.vue文件
import App from './count.vue'

import './assets/main.css'

//创建vue应用
createApp(App).mount('#app')

最后启动该项目即可,具体页面如下👇

1.2 组合式 API 和选项式 API

Vue2 版本时只存在选项式 API,然后 Vue3 出现了组合式 API,目前这两种方案都是可用的,以下是官方的建议:

  • 在学习的过程中,推荐采用更易于自己理解的风格。再强调一下,大部分的核心概念在这两种风格之间都是通用的。熟悉了一种风格以后,你也能够很快地理解另一种风格。
  • 在生产项目中:
    • 当你不需要使用构建工具,或者打算主要在低复杂度的场景中使用 Vue,例如渐进增强的应用场景,推荐采用选项式 API。
    • 当你打算用 Vue 构建完整的单页应用,推荐采用组合式 API + 单文件组件。

① 选项式 API

使用选项式 API,我们可以用包含多个选项的对象来描述组件的逻辑,例如 datamethodsmounted。选项所定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例。也就是说,选项式 API 有规定好的格式,更具有规律性。

<script>
export default {
  // data() 返回的属性将会成为响应式的状态
  // 并且暴露在 `this` 上
  data() {
    return {
      count: 0
    }
  },

  // methods 是一些用来更改状态与触发更新的函数
  // 它们可以在模板中作为事件监听器绑定
  methods: {
    increment() {
      this.count++
    }
  },

  // 生命周期钩子会在组件生命周期的各个不同阶段被调用
  // 例如这个函数就会在组件挂载完成后被调用
  mounted() {
    console.log(`The initial count is ${this.count}.`)
  }
}
</script>

<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>

② 组合式 API

通过组合式 API,我们可以使用导入的 API 函数来描述组件逻辑。在单文件组件中,组合式 API 通常会与 <script setup> 搭配使用。这个 setup attribute 是一个标识,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API。比如,<script setup> 中的导入和顶层变量/函数都能够在模板中直接使用。

下面是使用了组合式 API 与 <script setup> 改造后和上面的模板完全一样的组件:

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

// 响应式状态
const count = ref(0)

// 用来修改状态、触发更新的函数
function increment() {
  count.value++
}

// 生命周期钩子
onMounted(() => {
  console.log(`The initial count is ${count.value}.`)
})
</script>

<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>

以上选项式 API 和组合式 API 的简单区别,之后还会对其进行深入的了解。

2 v-xx 指令

这里看到的 v-xx attribute 被称为一个指令。指令由 v- 作为前缀,表明它们是一些由 Vue 提供的特殊 attribute,它们将为渲染的 DOM 应用特殊的响应式行为。

2.1 v-html

{{}}-双大括号会将数据解释为纯文本,而不是 HTML。若想插入并解析 HTML,你需要使用 v-html 指令。

📌 语法:

  • v-html="html代码"

📌 使用举例

<script setup>
//定义rawHtml 
const rawHtml = '<span style="color: red">This should be red.</span>'
</script>

<template>
  <p>使用双大括号: {{ rawHtml }} <br /> </p>
  <p>使用 v-html 指令:
      <span v-html="rawHtml"></span>
  </p>
</template>

📌 页面效果

可以看到若使用双大括号,直接会将 HTML 代码输出,而 v-html 则可以直接解析 HTML。

2.2 v-bind

双大括号不能在 HTML attributes/属性 中使用。若要给 HTML 标签的属性赋值,应该使用 v-bind 指令。

📌 语法:

  • v-bind:属性名="常量-属性值":给已知属性赋值,属性值通过js动态获取
  • :属性名="常量-属性值":缩写,只需要冒号
  • :disabled="isDisabled":isDisabled 为 true 或一个空字符串 (即 <button disabled="">) 时,元素会包含这个 disabled attribute。而当其为其他假值时 attribute 将被忽略
  • v-bind:[常量-属性名]="常量-属性值":给未知属性名赋值,属性名以及属性值通过js动态获取
  • v-bind="属性集合":动态绑定多个值

📌 使用举例

<script setup>
const url =  'http://www.baidu.com'
const isDisabled = true
const attr1 = "herf"
const attrs = {
  href:  url,
  type: 'text/html'
}
</script>

<template>
    <div id="app">
      <!--1.给已知属性赋值,属性值通过js动态获取-->
      <a v-bind:href="url">点击1 <br /></a>
      <!--缩写-->
      <a :href="url">点击1(缩写)) <br /></a>

      <!--2.isDisabled为false时,该按钮才可用,否则不可用/置灰-->
      <button :disabled="isDisabled">按钮</button>

      <!--3.给未知属性名赋值,属性名以及属性值通过js动态获取-->
      <a v-bind:[attr1]="url"><br />点击2 <br /></a>

      <!--4.动态绑定多个值-->
      <a v-bind="attrs">点击3(动态绑定多个值) <br /></a>
    </div>
</template>

📌 页面效果

2.3 v-if/show

用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值/true时才被渲染。

📌 语法:

  • v-if="expression":表达式返回真值时才渲染,也可用在 template 上
  • v-else:必须跟在一个 v-if 或者 v-else-if 元素后面
  • v-else-if:必须紧跟在一个 v-if 或一个 v-else-if 元素后面。 
  • v-show="expression":v-show 会在 DOM 渲染中保留该元素,不可用在 template 上

📌 使用举例

<script setup>
const isShow = false
const type = 'C'
</script>

<!--可以在一个<template>元素上使用v-if-->
<template v-if="true">
    <h1 v-if="isShow">Vue is awesome!</h1>
    <h1 v-else>Oh no 😢</h1>

    <div v-if="type === 'A'">A</div>
    <div v-else-if="type === 'B'">B</div>
    <div v-else>Not A/B</div>

    <h1 v-show="isShow">Hello!</h1>
</template>

📌 页面效果

📌 v-if vs v-show

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

2.4 v-for

我们可以使用 v-for 指令基于一个数组来渲染一个列表/对象。v-for 指令的值需要使用 item in/of items 形式的特殊语法,其中 items 是源数据的数组/对象,而 item 是迭代项的别名。

Vue 2.2.0+的版本里,当在组件中使用v-for时,key是必须的。key 绑定的值期望是一个基础类型的值,例如字符串或 number 类型。不要用对象作为 v-for 的 key,具体如何请看下文。

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

① 列表

items 即为定义好的列表~

📌 语法:

  • <li v-for="item in items" :key="item.message">{{ item.message }}</li>:正常使用,item表示列表中的元素
  • <li v-for="(item, index) in items" :key="item.message">{{ index }} - {{ item.message }}</li>:第二个参数表示当前项的位置索引
  • <span v-for="n in 10" :key="n">{{ n }}</span>:在 v-for 里使用范围值
  • 如何在 <template> 上使用 v-for 和多层嵌套请查看使用举例

📌 使用举例

<script setup>
import { ref ,reactive} from 'vue'
const items = ref([{ message: 'yin'}, { message: 'yu' }])
const parentMessage = ref('Parent')

</script>

<!-- 4.<template> 上使用 v-for -->
<template v-for="it in items" :key="it">
    <!-- Vue 2.2.0+的版本里,当在组件中使用v-for时,key是必须的。 -->
    <!-- key 绑定的值期望是一个基础类型的值,例如字符串或 number 类型。不要用对象作为 v-for 的 key。 -->

    <!-- 1.普通 -->
    <li v-for="item in items" :key="item.message"> 
        {{ item.message }}
    </li>

    <!-- 2.第二个参数表示当前项的位置索引 -->
    <li v-for="(item, index) in items" :key="item">
        {{ parentMessage }} - {{ index }} - {{ item.message }}
    </li>

    <!-- 3.在 v-for 里使用范围值 -->
    <span v-for="n in 10" :key="n">{{ n }}</span>

    
    <!-- 5.多层嵌套,假设 item有 children元素列表 -->
    <li v-for="item in items" :key="item">
        <span v-for="childItem in item.children" :key="childItem">
            {{ item.message }} {{ childItem }}
        </span>
    </li>
</template>

📌 页面效果

② 对象

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

📌 语法:

  • <li v-for="value in myObject" :key="value">{{ value }}</li>:遍历对象的所有属性值
  • <li v-for="(value, key) in myObject" :key="value">{{ key }}: {{ value }}</li>:第二个参数表示属性名
  • <li v-for="(value, key, index) in myObject" :key="value">{{ index }}. {{ key }}: {{ value }}</li>:第三个参数表示位置索引

📌 使用举例

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

const myObject = reactive({
  title: 'How to do lists in Vue',
  author: 'yinyu',
  publishedAt: '2023-05-10'
})
</script>

<template>
    <!-- Vue 2.2.0+的版本里,当在组件中使用v-for时,key是必须的。 -->

    <!-- 1.遍历对象的所有属性值 -->
    <li v-for="value in myObject" :key="value">
        {{ value }}
    </li>

    <!-- 2.第二个参数表示属性名  -->
    <li v-for="(value, key) in myObject" :key="value">
        {{ key }}: {{ value }}
    </li>

    <!-- 2.第三个参数表示位置索引  -->
    <li v-for="(value, key, index) in myObject" :key="value">
        {{ index }}. {{ key }}: {{ value }}
    </li>

</template>

📌 页面效果

2.5 v-on

我们可以使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click="handler" 或 @click="handler",主要有以下两种方式。

① v-on/@

📌 语法:

  • <button @click="count++">Add 1</button>:内联事件处理器—事件被触发时执行的内联 JavaScript 语句 (与 onclick 类似),通常用于简单场景
  • <button @click="方法名">Greet</button>:方法事件处理器—v-on 也可以接受一个方法名或对某个方法的调用
  • <button @click="方法名('方法入参')">Say hello</button>:在内联处理器中调用方法
  • <button @click="方法名('方法入参1', $event)"> Submit </button>:有时我们需要在内联事件处理器中访问原生 DOM 事件。你可以向该处理器方法传入一个特殊的 $event 变量

方法与内联事件判断:模板编译器会通过检查 v-on 的值是否是合法的 JavaScript 标识符或属性访问路径来断定是何种形式的事件处理器。比如:foo、foo.bar 和 foo['bar'] 会被视为方法事件处理器,而 foo() 和 count++ 会被视为内联事件处理器。

📌 使用举例

<script setup>
import {ref} from "vue";

const count = ref(0)
const name = ref('yinyu')

function greet(event) {
  alert(`Hello ${name.value}!`)
  // `event` 是 DOM 原生事件
  if (event) {
    alert(event.target.tagName)
  }
}

function say(message) {
  alert(message)
}

function warn(message, event) {
  // 这里可以访问原生事件
  if (event) {
    event.preventDefault()
  }
  alert(message)
}

</script>

<template>
  <!-- 1.内联事件处理器:事件被触发时执行的内联 JavaScript 语句 (与 onclick 类似) -->
  <button v-on:click="count++" >Add 1</button>
  <p>Count is: {{ count }}</p>
  <p>----------</p>

  <!-- 2.方法事件处理器:v-on 也可以接受一个方法名或对某个方法的调用 -->
  <!-- `greet` 是上面定义过的方法名 -->
  <button @click="greet">Greet</button>
  <p>----------</p>

  <!-- 3.在内联处理器中调用方法,允许我们向方法传入自定义参数以代替原生事件 -->
  <button @click="say('hello')">Say hello</button>
  <p>----------</p>

  <!-- 4.在内联处理器中调用方法,使用特殊的 $event 变量 -->
  <button @click="warn('Form cannot be submitted yet.', $event)">
    Submit
  </button>

</template>

📌 页面效果

② 修饰符

📌 事件修饰符

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

<!-- 单击事件将停止传递 -->
<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>

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

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

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

📌 按键修饰符

<!-- 仅在 `key` 为 `Enter` 时调用 `submit` -->
<input @keyup.enter="submit" />

<!-- 仅会在 $event.key 为 'PageDown' 时调用事件处理。 -->
<input @keyup.page-down="onPageDown" />

📌 按键别名

Vue 为一些常用的按键提供了别名:

  • .enter
  • .tab
  • .delete (捕获“Delete”和“Backspace”两个按键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

📌 系统按键修饰符

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

  • .ctrl
  • .alt
  • .shift
  • .meta

比如:

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

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

📌 鼠标按键修饰符

  • .left
  • .right
  • .middle

2.6 v-model

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

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

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

<input v-model="text">

📌 提示

  • 文本类型的 <input> 和 <textarea> 元素会绑定 value property 并侦听 input 事件
  • <input type="checkbox"> 和 <input type="radio"> 会绑定 checked property 并侦听 change 事件
  • <select> 会绑定 value property 并侦听 change 事件

① 基本用法

📌 语法:

  • <input v-model="message1" />:文本
  • <textarea v-model="message2" placeholder="add multiple lines"></textarea>:多行文本
  • <input type="checkbox" id="checkbox" v-model="checked" />:单一的复选框,绑定布尔类型值
  • 单选按钮、选择器就请看使用举例了~

📌 使用举例:

<script setup>
import {reactive, ref} from "vue";
const message1 = ref('')
const message2 = ref('')
const checked = ref('false')
const picked = ref('')
const selected1 = ref('')
const selected2 = ref([])
</script>

<template>
    <!-- 1.文本 -->
    <p>Message is: {{ message1 }}</p>
    <input v-model="message1" placeholder="edit me" />
    <p>----------</p>

    <!-- 2.多行文本 -->
    <span>Multiline message is:</span>
    <p style="white-space: pre-line;">{{ message2 }}</p>
    <textarea v-model="message2" placeholder="add multiple lines"></textarea>
    <p>----------</p>

    <!-- 3.复选框 -->
    <input type="checkbox" id="checkbox" v-model="checked" />
    <label for="checkbox">{{ checked }}</label>
    <p>----------</p>

    <!-- 4.单选按钮 -->
    <div>Picked: {{ picked }}</div>
    <input type="radio" id="one" value="One" v-model="picked" />
    <label for="one">One</label>
    <input type="radio" id="two" value="Two" v-model="picked" />
    <label for="two">Two</label>
    <p>----------</p>

    <!-- 5.1选择器-单选 -->
    <div>Selected: {{ selected1 }}</div>
    <select v-model="selected1">
        <option disabled value="">Please select one</option>
        <option>A</option>
        <option>B</option>
        <option>C</option>
    </select>
    <p>----------</p>

    <!-- 5.2选择器-多选 -->
    <div>Selected: {{ selected2 }}</div>
    <select v-model="selected2" multiple>
        <option>A</option>
        <option>B</option>
        <option>C</option>
    </select>
</template>

📌 页面效果

② 值绑定

前边 v-model 绑定的值通常是静态的字符串 (或者对复选框是布尔值),但有时我们可能希望将该值绑定到当前组件实例上的动态数据。这可以通过使用 v-bind 来实现。

📌 语法:

  • <input type="checkbox" v-model="checked1" true-value="yes" false-value="no"/>复选框,true-value 和 false-value 是 Vue 特有的 attributes,仅支持和 v-model 配套使用
  • <input type="checkbox" v-model="checked2" :true-value="dynamicTrue" :false-value="dynamicFalse"/>可以通过 v-bind 将其绑定为其他动态值
  • 单选按钮、选择器就请看使用举例了~

📌 使用举例:

<script setup>
import {ref} from "vue";
const checked1 = ref()
const checked2 = ref()
const dynamicTrue = ref('dynamicTrue')
const dynamicFalse = ref('dynamicFalse')
const pick = ref()
const first = ref('first')
const second = ref('second')
const selected = ref()
</script>

<template>
    <!-- 1.1 复选框,true-value 和 false-value 是 Vue 特有的 attributes,仅支持和 v-model 配套使用。-->
    <div>Checked: {{ checked1 }}</div>
    <input type="checkbox" v-model="checked1" true-value="yes" false-value="no"/>
    <p>----------</p>

    <!-- 1.2 复选框,可以通过 v-bind 将其绑定为其他动态值-->
    <div>Checked: {{ checked2 }}</div>
    <input type="checkbox" v-model="checked2" :true-value="dynamicTrue" :false-value="dynamicFalse"/>
    <p>----------</p>

    <!--2.单选按钮,pick 会在第一个按钮选中时被设为 first,在第二个按钮选中时被设为 second。-->
    <div>Picked: {{ pick }}</div>
    <input type="radio" v-model="pick" :value="first" />
    <input type="radio" v-model="pick" :value="second" />
    <p>----------</p>

    <!--3.选择器选项,v-model 同样也支持非字符串类型的值绑定!在下面这个例子中,当某个选项被选中,selected 会被设为该对象字面量值 { number: 123 }。-->
    <div>Selected: {{ selected }}</div>
    <select v-model="selected">
      <!-- 内联对象字面量 -->
      <option :value="{ number: 123 }">123</option>
    </select>
</template>

📌 页面效果

③ 修饰符

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

3 其余基础语法

除了 v-xx 指令,还有一些必要的语法需要大家掌握,比如响应式基础、计算属性、生命周期等等~

3.1 响应式基础

① reactive()

我们可以使用 reactive() 函数创建一个响应式对象或数组,能够跟踪对响应式对象属性的访问与更改操作:

import { reactive } from 'vue'

const state = reactive({ count: 0 })

我们可以在同一个作用域下定义更新响应式状态的函数,并将他们作为方法与状态一起暴露出去:

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

const state = reactive({ count: 0 })

function increment() {
  state.count++
}
</script>

<template>
  <button @click="increment">
    {{ state.count }}
  </button>
</template>

📌 页面效果

📌 reactive() 的局限性

  1. 仅对对象类型有效(对象、数组和 Map、Set 这样的集合类型),而对 string、number 和 boolean 这样的 原始类型无效。
  2. 因为 Vue 的响应式系统是通过属性访问进行追踪的,因此我们必须始终保持对该响应式对象的相同引用。若随意地“替换”一个响应式对象,这将导致对初始引用的响应性连接丢失,也就是说响应性失败。

② ref()

基于 reactive() 的局限性,Vue 提供了一个 ref() 方法来允许我们创建可以使用任何值类型的响应式 ref!

import { ref } from 'vue'

const count = ref(0)

代码如下:

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

const count = ref(0)

function increment() {
  count.value++
}
</script>

<template>
  <button @click="increment">
    {{ count }} <!-- 无需 .value -->
  </button>
</template>

3.2 计算属性

首先不推荐在{{}}模板中写太多逻辑,这会难以维护,因此 Vue 推荐使用计算属性来描述依赖响应式状态的复杂逻辑:

<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>

📌 页面效果

计算属性值会基于其响应式依赖被缓存,一个计算属性仅会在其响应式依赖更新时才重新计算。也就是说,只要 author.books 不改变,无论多少次访问 publishedBooksMessage 都会立即返回先前的计算结果,而不用重复执行 getter 函数。

📌 可写计算属性

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

<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(' ')
    }
  })

  function changeBlue(name) {
    fullName.value = name
    return firstName.value + ' ' + lastName.value
  }
</script>

<template>
  <p>Has published books:</p>
  <span>{{ changeBlue("yin yu") }}</span>
</template>

3.3 Class 与 Style 绑定

Vue 专门为 class 和 style 的 v-bind 用法提供了特殊的功能增强。除了字符串外,表达式的值也可以是对象或数组。

① :class

:class (v-bind:class 的缩写) 传递一个对象来动态切换 class:

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

  const isActive = ref(true)
  const hasError = ref(false)
</script>

<template>
  <div class="static" :class="{ active: isActive , 'text-danger': hasError}">yin yu</div>
</template>

📌 页面效果

当 isActive 或者 hasError 改变时,class 列表会随之更新。举例来说,如果 hasError 变为 true,class 列表也会变成 "static active text-danger"。

📌 绑定对象

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

  const classObject = reactive({
    active: true,
    'text-danger': false
  })

</script>

<template>
  <div :class="classObject"></div>
</template>

📌 绑定数组

我们可以给 :class 绑定一个数组来渲染多个 CSS class:

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

  const activeClass = ref('active')
  const errorClass = ref('text-danger')
  const isActive = ref(true)

</script>

<template>
  <div :class="[activeClass, errorClass]"></div>

  <!--如果你也想在数组中有条件地渲染某个 class,你可以使用三元表达式:-->
  <div :class="[isActive ? activeClass : '', errorClass]"></div>
</template>

② :style

:style 支持绑定 JavaScript 对象值,对应的是 HTML 元素的 style 属性:

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

  const activeColor = ref('green')
  const fontSize = ref(30)

</script>

<template>
  <div :style="{ color: activeColor, fontSize: fontSize + 'px' }">yin yu</div>
</template>

📌 页面效果

📌 绑定对象

直接绑定一个样式对象可以使模板更加简洁:

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

  const styleObject = reactive({
    color: 'red',
    fontSize: '13px'
  })

</script>

<template>
  <div :style="styleObject">yin yu</div>
</template>

📌 绑定数组

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

  const baseStyles = ref({color:'green'})
  const overridingStyles = ref({fontSize:'30px'})

</script>

<template>
  <div :style="[baseStyles, overridingStyles]">yin yu</div>
</template>

3.4 生命周期

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

① 注册周期钩子

比如,onMounted 钩子可以用来在组件完成初始渲染并创建 DOM 节点后运行代码:

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

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

还有其他一些钩子,会在实例生命周期的不同阶段被调用,最常用的是 onMountedonUpdated onUnmounted

所有生命周期钩子的完整参考及其用法请参考:组合式 API:生命周期钩子 | Vue.js (vuejs.org)

② 生命周期图示

下面是实例生命周期的图表:

3.5 侦听器

在组合式 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)
const obj = reactive({ count: 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 函数,监听响应式对象的属性值
watch(
  () => obj.count,
  (count) => {
    console.log(`count is: ${count}`)
  }
)

② 深层侦听器

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

const obj = reactive({ count: 0 })

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

obj.count++

③ 即时回调的侦听器

watch 默认是懒执行的:仅当数据源变化时,才会执行回调。我们可以通过传入 immediate: true 选项来强制侦听器的回调立即执行:

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

④ watchEffect()

watchEffect() 允许我们自动跟踪回调的响应式依赖,此处回调会立即执行,不需要指定 immediate: true。在执行期间,它会自动追踪 todoId.value 作为依赖(和计算属性类似)。每当 todoId.value 变化时,回调会再次执行。有了 watchEffect(),我们不再需要明确传递 todoId 作为源值。

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

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

3.6 模板引用

ref 是一个特殊的 attribute,和 v-for 章节中提到的 key 类似。它允许我们在一个特定的 DOM 元素或子组件实例被挂载后,获得对它的直接引用。

① 访问模板引用

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

<template>
  <div>
    <input ref="element">
      <br /> {{ item }}
  </div>
</template>

<script setup>
  import { ref , watchEffect} from 'vue';
  const element=ref(null)
  const item = ref("yinyu");

  watchEffect(()=>{
    if(element.value){
      console.log(element);
    }else{
      console.log('未加载');
    }
  })
</script>

📌 页面效果

② v-for 中的模板引用

需要 v3.2.25 及以上版本

当在 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>

3.7 组件基础

Vue 实现了自己的组件模型,使我们可以在每个组件内封装自定义内容与逻辑。

① 定义一个组件

当使用构建步骤时,我们一般会将 Vue 组件定义在一个单独的 .vue 文件中,这被叫做单文件组件 (简称 SFC):

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

const count = ref(0)
</script>

<template>
  <button @click="count++">You clicked me {{ count }} times.</button>
</template>

② 使用组件

要使用一个子组件,我们需要在父组件中导入它。假设我们把计数器组件放在了一个叫做 ButtonCounter.vue 的文件中,这个组件将会以默认导出的形式被暴露给外部。

<script setup>
import ButtonCounter from './ButtonCounter.vue'
</script>

<template>
  <h1>Here is a child component!</h1>
  <ButtonCounter />
</template>

📌 页面效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/515516.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】Linux中的编辑器vim

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;Linux的学习之路 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录 前言一、vim的概念二、命令模式2…

SpringBoot【开发实用篇】---- 数据层解决方案

SpringBoot【开发实用篇】---- 数据层解决方案 1. SQL数据源技术持久化技术数据库技术 2. NoSQLSpringBoot整合Redis安装基本操作整合 SpringBoot整合MonggoDB安装基本操作整合 SpringBoot整合ES安装基本操作整合 开发实用篇前三章基本上是开胃菜&#xff0c;从第四章开始&…

“1+X+N”模式助力企业数字化转型

近期&#xff0c;中电金信顺利完成某股份制银行“基于战略解析与业务架构的全行科技规划项目”交付。针对客户的实际业务需求&#xff0c;中电金信采用“1XN”服务模式&#xff0c;服务客户全面的企业架构转型规划。项目组联合行方协同创新&#xff0c;首次将企架建模方法应用于…

【腾讯云 findops Crane集训营】深入了解 Crane 开源项目之实验操作指南

引言&#xff1a; 最近我参加了由腾讯云联合 CSDN 推出的“腾讯云 Finops Crane 开发者集训营”活动&#xff0c;通过这个活动我对腾讯云的 Finops Crane 开源项目有了更深入的了解。在本篇博客中&#xff0c;我将分享我对该项目的认识和体验&#xff0c;并介绍其中一些关键特性…

C++:使用红黑树封装map和set

目录 一. 如何使用一颗红黑树同时实现map和set 二. 红黑树的节点插入操作 三. 红黑树迭代器的实现 3.1 begin()和end() 3.2 operator和operator-- 3.3 红黑树迭代器实现完整版代码 四. map和set的封装 附录&#xff1a;用红黑树封装map和set完整版代码 1. RBTree.h文件…

表情识别 emotion recognition

facial expression recognition 表情&#xff0c;人脸上的肌肉状态&#xff0c;可以表达人类的情绪。 1970年&#xff0c;Ekman定义了六种基本表情 如何定义&#xff1f; 动作单元(action unit)是定义表情的重要工具。 心理学家和生物学家认为&#xff0c;人的表情可以分解…

【HCIP】三层架构综合实验

目录 需求&#xff1a; 一、拓扑设计 二、配置 ①eth-trunk ②创建vlan & 划分vlan & trunk干道配置 ③STP生成树根节点备份&负责分担 ④SVI及VRRP网关冗余设置 ⑤DHCP ⑥通公网 ⑦验证 三层架构&#xff1a;核心层&#xff0c;汇聚层&#xff0c;接入层 …

QT桌面项目(第一个应用程序 桌面壁纸软件)

文章目录 前言一、壁纸切换程序的布局二、添加资源文件三、代码编写四、主界面代码五、程序的编写思路六、程序效果总结 前言 上节课我们已经做好了APP的按键图标了&#xff0c;这篇文章就让我们来开始制作第一个桌面程序吧。 一、壁纸切换程序的布局 这个是windows上浏览器…

vue3使用指南

vue3使用指南 主要介绍vue3的使用&#xff0c;同时会涉及到vue2&#xff0c;并会讲解其中的一些差异。 安装 CDN引入 如果想快速体验&#xff0c;可以直接通过cdn进行引入。 <div id"app">{{msg}}</div> <script src"https://unpkg.com/vue…

谷歌推出下一代大型语言模型 PaLM 2

谷歌在 2023 年度 I/O 大会上宣布推出了其下一代大型语言模型 PaLM 2&#xff0c;擅长高级推理任务&#xff0c;包括代码和数学、分类和问答、翻译和多语言能力以及自然语言生成。 谷歌声称 PaLM 2 是一种最先进的语言模型&#xff0c;要优于其之前所有的 LLM&#xff0c;包括…

网络拓扑架构规划设计

小型组网架构 1.网络拓扑 终端用户接入到交换机,交换机直连防火墙构成的简单网络,防火墙连接internet,对内网的用户进行安全控制 2.特点 用户接入数量较少:小型网络应用于接入用户数量较少的场景,一般支持几个至几十个用户 网络覆盖范围小:网络覆盖范围一般也是一个…

网络拓扑图制作软件

1.亿图图示(EdrawMax) 最像VISIO的网络拓扑制作工具 亿图图示实际上就是国产的Visio,与Visio非常相似。支持B/S架构,查看拓扑非常方便,模版也比较丰富。缺点与Visio也类似,画简单的网络拓扑没有问题,但针对大型网络拓扑管理而言,既需要能制作拓扑,又需要具有管理分析…

Hystrix详解及实践---SpringCloud组件(四)

Hystrix详解及实践 1.Hystrix简介2.雪崩问题3.服务降级、线程隔离、原理3.1.服务降级实践&#xff08;在feign的基础上实现&#xff09;1 添加Hystrix依赖2.在yml中开启熔断功能3.编写降级逻辑4.重启测试 4.服务熔断(Circuit Breaker)、原理4.1. 熔断原理4.2.动手实践 5.Hystri…

5个模板非常多的免费样机素材分享

样机素材是设计行业的不可缺少的素材之一&#xff0c;设计师可以将自己的设计作品&#xff0c;应用到一个效果图中进行展示&#xff0c;让你的设计作品看起来更加形象逼真。 本文分享5个非常给力的样机素材网站 1.即时设计资源社区 即时设计是一款「专业UI设计工具」&#x…

【edusrc】某校园网登录系统存在的一个简单爆破

前言 红中(hong_zh0) CSDN内容合伙人、2023年新星计划web安全方向导师、 华为MindSpore截至目前最年轻的优秀开发者、IK&N战队队长、 阿里云专家博主、华为网络安全云享专家、腾讯云自媒体分享计划博主 本文主讲思路&#xff0c;可能有点废话。 该漏洞已修复 最开始的思…

华为OD机试真题 Java 实现【字符串重新排序】【2023Q1 100分】

一、题目描述 给定一个字串s&#xff0c;s包含以空格分隔的若干个单词&#xff0c;请对s进行如下处理后输出&#xff1a; 1、单词内部调整 对每个单词字母重新按字典序排序。 2、单词间顺序调整: 统计每个单词出现的次数&#xff0c;并按次数降序排列&#xff1b;次数相同…

存下吧!Spring高频面试题总结

Spring是什么&#xff1f; Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。 Spring的优点 通过控制反转和依赖注入实现松耦合。支持面向切面的编程&#xff0c;并且把应用业务逻辑和系统服务分开。通过切面和模板减少样板式代码。声明式事务的支持。可以从单…

Windows系统下Chromedriver.exe安装及配置

Windows系统下Chromedriver.exe安装及配置 在利用selenium工具进行Web自动化测试时&#xff0c;必须先要安装浏览器驱动&#xff0c;通常比较常用的是谷歌浏览器和火狐浏览器。 一、浏览器驱动下载地址 1.浏览器驱动官网&#xff1a;http://chromedriver.storage.googleapis…

计算环境安全

计算环境安全 操作系统安全安全机制标识与鉴别访问控制权限管理信道保护安全审计内存保护与文件系统保护 安全部署原则操作系统安全配置密码远程暴力破解安全审计 针对系统的攻击信息收集公开信息收集-搜索引擎信息收集与分析的防范 缓冲区溢出缓冲区溢出基础-堆栈、指针、寄存…

Dubbo源码篇03---点点直连如何实现及背后原理

Dubbo源码篇03---从点点直连探究Complier编译的原理 什么是点点直连实际需求如何实现动态编译&#xff1f;如何发起调用?点点直连原理实现点点直连消费端提供端测试 点点直连小结 什么是点点直连 Dubbo正常的请求模型&#xff0c;都是消费端从注册中心拉取服务提供者列表&…