目录
all.value = all.value.filter((t) => t !== all)
11.Props(使用父组件动态数据defineProps())
能在改变时触发更新的状态被称作是响应式的。我们可以使用 Vue 的
reactive()
API 来声明响应式状态。由reactive()
创建的对象都是 JavaScript Proxy,其行为与普通对象一样:
reactive()
只适用于对象 (包括数组和内置类型,如Map
和Set
)。而另一个 APIref()
则可以接受任何值类型。ref
会返回一个包裹对象,并在.value
属性下暴露内部值。
reactive()
和ref()
的细节:响应式基础 | Vue.js (vuejs.org)例:
<script setup> import { reactive, ref } from 'vue' const counter = reactive({ count: 0 }) const message = ref('Hello World!') </script> <template> <h1>{{ message }}</h1> <p>Count is: {{ counter.count }}</p> </template>
注意我们在模板中访问的
message
ref 时不需要使用.value
:它会被自动解包,让使用更简单。
2.Attribute 绑定(v-bind)
mustache 语法 (即双大括号) 只能用于文本插值。为了给 attribute 绑定一个动态值,需要使用
v-bind
指令例:
把一个动态的
class
绑定添加到这个<h1>
上,并使用titleClass
的 ref 作为它的值。如果绑定正确,文字将会变为红色。<script setup> import { ref } from 'vue' const titleClass = ref('title') </script> <template> <h1 :class="titleClass">Make me red</h1> </template> <style> .title { color: red; } </style>
3.事件监听(v-on)
例:
尝试自行实现
increment
函数并通过使用v-on
将其绑定到按钮上<script setup> import { ref } from 'vue' const count = ref(0) function increment() { count.value++ } </script> <template> <button @click="increment">count is: {{ count }}</button> </template>
4.表单绑定(v-model)
我们可以同时使用
v-bind
和v-on
来在表单的输入元素上创建双向绑定为了简化双向绑定,Vue 提供了一个
v-model
指令,它实际上是上述操作的语法糖例:
试着在文本框里输入——你会看到
<p>
里的文本也随着你的输入更新了<script setup> import { ref } from 'vue' const text = ref('') </script> <template> <input v-model="text" placeholder="Type here"> <p>{{ text }}</p> </template>
5.条件渲染(v-if)
例:
同时展示了两个
<h1>
标签,并且按钮不执行任何操作。尝试给它们添加v-if
和v-else
指令,并实现toggle()
方法,让我们可以使用按钮在它们之间切换。<script setup> import { ref } from 'vue' const awesome = ref(true) function toggle() { awesome.value = !awesome.value } </script> <template> <button @click="toggle">toggle</button> <h1 v-if="awesome">Vue is awesome!</h1> <h1 v-else>Oh no 😢</h1> </template>
6.列表渲染(v-for)
例:
这里有一个简单的 todo 列表——试着实现一下
addTodo()
和removeTodo()
这两个方法的逻辑,使列表能够正常工作!<script setup> import { ref } from 'vue' // 给每个 todo 对象一个唯一的 id let id = 0 const newTodo = ref('') const todos = ref([ { id: id++, text: 'Learn HTML' }, { id: id++, text: 'Learn JavaScript' }, { id: id++, text: 'Learn Vue' } ]) function addTodo() { todos.value.push({ id: id++, text: newTodo.value }) newTodo.value = '' } function removeTodo(todo) { todos.value = todos.value.filter((t) => t !== todo) } </script> <template> <form @submit.prevent="addTodo"> <input v-model="newTodo"> <button>Add Todo</button> </form> <ul> <li v-for="todo in todos" :key="todo.id"> {{ todo.text }} <button @click="removeTodo(todo)">X</button> </li> </ul> </template>
all.value = all.value.filter((t) => t !== all)
该代码通过删除任何等于 的元素来筛选数组中的元素。然后将过滤后的结果分配回 。
todos.value.filter((t) => t !== todo)
当您要从数组中删除特定元素时,可以使用此代码。它遍历数组中的每个元素 () 并检查它是否不等于 。如果条件为 true,则该元素将保留在筛选结果中,否则将删除该元素。
过滤后,生成的数组被赋回变量,有效地使用修改后的数组对其进行更新
<form @submit.prevent=“addTodo”>
该代码为元素上的事件设置事件处理程序。提交表单时,它会调用 Vue.js 实例中指定的方法或函数。
<form @submit.prevent="addTodo">
该指令阻止默认表单提交行为,这通常涉及刷新页面或导航到新 URL。相反,它允许您定义自定义逻辑以使用该方法处理表单提交
7.计算属性(computed())
计算属性会自动跟踪其计算中所使用的到的其他响应式状态,并将它们收集为自己的依赖。计算结果会被缓存,并只有在其依赖发生改变时才会被自动更新。
例:
试着添加
filteredTodos
计算属性并实现计算逻辑!如果实现正确,在隐藏已完成项目的状态下勾选一个 todo,它也应当被立即隐藏。<script setup> import { ref, computed } from 'vue' let id = 0 const newTodo = ref('') const hideCompleted = ref(false) const todos = ref([ { id: id++, text: 'Learn HTML', done: true }, { id: id++, text: 'Learn JavaScript', done: true }, { id: id++, text: 'Learn Vue', done: false } ]) const filteredTodos = computed(() => { return hideCompleted.value ? todos.value.filter((t) => !t.done) : todos.value }) function addTodo() { todos.value.push({ id: id++, text: newTodo.value, done: false }) newTodo.value = '' } function removeTodo(todo) { todos.value = todos.value.filter((t) => t !== todo) } </script> <template> <form @submit.prevent="addTodo"> <input v-model="newTodo"> <button>Add Todo</button> </form> <ul> <li v-for="todo in filteredTodos" :key="todo.id"> <input type="checkbox" v-model="todo.done"> <span :class="{ done: todo.done }">{{ todo.text }}</span> <button @click="removeTodo(todo)">X</button> </li> </ul> <button @click="hideCompleted = !hideCompleted"> {{ hideCompleted ? 'Show all' : 'Hide completed' }} </button> </template> <style> .done { text-decoration: line-through; } </style>
8.生命周期和模板引用(onMounted、ref=)
要在挂载之后执行代码,我们可以使用
onMounted()
函数例:
尝试添加一个
onMounted
钩子,然后通过pElementRef.value
访问<p>
,并直接对其执行一些 DOM 操作。(例如修改它的textContent
)。<script setup> import { ref, onMounted } from 'vue' const pElementRef = ref(null) onMounted(() => { pElementRef.value.textContent = 'mounted!' }) </script> <template> <p ref="pElementRef">hello</p> </template>
结果解释:
给定的代码是使用该语法的 Vue 3 单文件组件 (SFC)。以下是它的功能的细分:
<script setup>
该语句从 'vue' 包导入必要的函数。这些函数用于创建反应式引用和处理组件生命周期事件。
常量是使用该函数创建的。它将引用初始化为 。
调用该函数,该函数设置在 DOM 中挂载组件时要执行的回调。在这种情况下,回调函数将 的文本内容设置为“mounted!
该部分包含组件的 HTML 模板。在模板内部,有一个带有属性的元素。此属性将引用绑定到元素,允许操作其属性。
挂载组件时,会触发回调,并将 引用的元素的文本内容设置为“mounted!因此,渲染的输出将显示“mounted!”而不是“hello”。
9.侦听器(watch())
有时我们需要响应性地执行一些“副作用”——例如,当一个数字改变时将其输出到控制台。我们可以通过侦听器来实现它:
watch()
可以直接侦听一个 ref,并且只要count
的值改变就会触发回调例:
<script setup> import { ref, watch } from 'vue' const todoId = ref(1) const todoData = ref(null) async function fetchData() { todoData.value = null const res = await fetch( `https://jsonplaceholder.typicode.com/todos/${todoId.value}` ) todoData.value = await res.json() } fetchData() watch(todoId, fetchData) </script> <template> <p>Todo id: {{ todoId }}</p> <button @click="todoId++">Fetch next todo</button> <p v-if="!todoData">Loading...</p> <pre v-else>{{ todoData }}</pre> </template>
代码解释:
- 该语句从 'vue' 包导入必要的函数 、 和。 用于创建反应式引用,用于监视反应式引用中的更改,并且是用于发出 HTTP 请求的浏览器 API。
- 使用函数创建两个反应式引用:和。 初始值为 1,最初设置为 null。
- 定义了一个异步函数,该函数使用当前值从指定的 URL 获取待办事项数据。最初,它设置为 null,提取数据,并使用提取的 JSON 响应进行更新。
- 该函数在定义后立即调用,获取初始待办事项数据。
- 该函数用于监视反应式引用的变化。每当更改时,都会再次调用该函数以根据更新的值获取新的待办事项数据。
- 在该部分中,有一个段落 () 元素显示 的当前值
- 存在一个带有事件侦听器的按钮,该按钮在单击时递增值,触发函数并使用更新的
- 下一个元素使用该指令有条件地呈现“正在加载...”何时是伪造的(最初或在数据获取过程中)
- 在最后一个元素中,该指令用于在元素内呈现,一旦它变得真实,将获取的待办事项数据显示为格式化的JSON对象
10.组件(ChildComp)
真正的 Vue 应用往往是由嵌套组件创建的。
父组件可以在模板中渲染另一个组件作为子组件。要使用子组件,我们需要先导入它:
import ChildComp from './ChildComp.vue'
然后我们就可以在模板中使用组件,就像这样:
<ChildComp />
例:
现在尝试一下导入子组件并在模板中渲染它
<script setup> import ChildComp from './ChildComp.vue' </script> <template> <ChildComp /> </template>
ChildComp.vue
<template> <h2>A Child Component!</h2> </template>
11.Props(使用父组件动态数据defineProps())
子组件可以通过 props 从父组件接受动态数据。首先,需要声明它所接受的 props:
<!-- ChildComp.vue --> <script setup> const props = defineProps({ msg: String }) </script>
注意
defineProps()
是一个编译时宏,并不需要导入。一旦声明,msg
prop 就可以在子组件的模板中使用。它也可以通过defineProps()
所返回的对象在 JavaScript 中访问。父组件可以像声明 HTML attributes 一样传递 props。若要传递动态值,也可以使用
v-bind
语法:<ChildComp :msg="greeting" />
例:
ChildComp.vue
<script setup> const props = defineProps({ msg: String }) </script> <template> <h2>{{ msg || 'No props passed yet' }}</h2> </template>
父组件:
<script setup> import { ref } from 'vue' import ChildComp from './ChildComp.vue' const greeting = ref('Hello from parent') </script> <template> <ChildComp :msg="greeting" /> </template>
12.Emits(子组件向父组件触发事件)
除了接收 props,子组件还可以向父组件触发事件:
<script setup> // 声明触发的事件 const emit = defineEmits(['response']) // 带参数触发 emit('response', 'hello from child') </script>
emit()
的第一个参数是事件的名称。其他所有参数都将传递给事件监听器。父组件可以使用
v-on
监听子组件触发的事件——这里的处理函数接收了子组件触发事件时的额外参数并将它赋值给了本地状态:<ChildComp @response="(msg) => childMsg = msg" />
例:父组件:
<script setup> import { ref } from 'vue' import ChildComp from './ChildComp.vue' const childMsg = ref('No child msg yet') </script> <template> <ChildComp @response="(msg) => childMsg = msg" /> <p>{{ childMsg }}</p> </template>
ChildComp.vue
<script setup> const emit = defineEmits(['response']) emit('response', 'hello from child') </script> <template> <h2>Child component</h2> </template>
13.插槽(slots)
<slot>
插口中的内容将被当作“默认”内容:它会在父组件没有传递任何插槽内容时显示例:
没有给
<ChildComp>
传递任何插槽内容,所以你将看到默认内容。让我们利用父组件的msg
状态为子组件提供一些插槽内容ChildComp.vue
<template> <slot>Fallback content</slot> </template>
父组件:
<script setup> import { ref } from 'vue' import ChildComp from './ChildComp.vue' const msg = ref('from parent') </script> <template> <ChildComp>Message: {{ msg }}</ChildComp> </template>