对于vue.js渐进式教程的一些总结与思考,方便自己以后查阅。以下是一些基础概念,我会在进一步学习后补全。
起步(什么是Vue.js)
Vue.js是一个渐进式的前端框架,它是一套用于构建用户界面的渐进式框架。它与其它大型框架不同,它专注于MVVM(模型-视图-视图模型)架构和组件化开发。
语法
Vue.js的语法与其它前端框架有所不同,它使用了HTML-based模板语法,并提供了一些自定义指令来绑定数据和DOM。
声明式渲染
Vue 的核心功能就是声明式渲染:通过扩展于标准 HTML 的模板语法,我们可以根据 JavaScript 的状态来描述 HTML 应该是什么样子的。当状态改变时,HTML 会自动更新。
能在改变时触发更新的状态被称作是响应式的。
reactive()
: 用于将一个普通的对象转换成响应式数据。reactive返回一个响应式的Proxy对象,通过修改该对象的属性值,可以触发组件更新。
1 2 3 4 5 6 7 8 9
| import { reactive } from 'vue';
const state = reactive({ count: 0 });
function increment() { state.count++; }
|
ref()
: 于将一个普通的数据类型转换成响应式数据。ref返回一个包含value属性的对象,通过修改value属性的值,可以触发组件更新。
1 2 3 4 5 6 7
| import { ref } from 'vue';
const count = ref(0);
function increment() { count.value++; }
|
注意:reactive() 和 ref() 的区别在于:在使用上,ref更方便一些,使用起来更简单直观。而reactive比较灵活,可以将任意对象转换成响应式数据,并且可以进行深层次的响应式处理。
Vue 单文件组件 (Single-File Component,缩写为 SFC)。单文件组件是一种可复用的代码组织形式,它将从属于同一> 个组件的 HTML、CSS 和 JavaScript 封装在使用 .vue 后缀的文件中。
Attribute 绑定
Vue.js的指令可以绑定数据到DOM元素的属性上。
v-bind
是 Vue.js 中一个非常重要的指令,用于动态绑定 HTML 属性或组件 props。通过 v-bind
,你可以将一个数据属性的值绑定到 DOM 元素的属性上,实现数据与视图的同步。
1 2 3
| <div v-bind:id="dynamicId"></div> <-- 简写 --> <div :id="dynamicId"></div>
|
事件监听
v-on
用于监听 DOM 事件并执行相应的 JavaScript 代码。通过 v-on
,你可以监听 DOM 事件并在触发时执行 JavaScript 代码,实现视图与逻辑的解耦。
1 2 3
| <button v-on:click="increment">{{ count }}</button> <-- 简写 --> <button @click="increment">{{ count }}</button>
|
表单绑定
v-on
and v-bind
的关系:
- 数据驱动:v-bind 用于将数据动态绑定到元素的属性上,而 v-on 则用于响应用户的交互(如点击、输入等)并更新数据。它们共同构成了 Vue 的响应式系统。
- 更新视图:使用 v-on 触发的事件可以改变数据,随后 v-bind 会自动更新绑定的属性,从而实现视图的同步更新。
我们可以同时使用 v-bind 和 v-on 来在表单的输入元素上创建双向绑定:
1 2 3
| <input :value="text" @input="onInput"> <-- 等价于 --> <input v-model="text">
|
v-model 会将被绑定的值与 <input>
的值自动同步,这样我们就不必再使用事件处理函数了。
v-model 不仅支持文本输入框,也支持诸如多选框、单选框、下拉框之类的输入类型。
条件渲染
v-if
是 Vue.js 中用于条件渲染的指令,可以根据布尔值动态决定是否渲染某个元素。当条件为真时,元素会被渲染;当条件为假时,元素不会出现在 DOM 中。
1 2
| <div v-if="show">Hello</div> <div v-else>Bye</div>
|
列表渲染
v-for
是 Vue.js 中用于遍历数组或对象并渲染列表的指令。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <script setup> import { ref } from 'vue'
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" required placeholder="new todo"> <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>
|
计算属性
computed()
:是 Vue.js 中用于创建计算属性的选项。它可以帮助我们将数据转换为可读的状态,并根据需要缓存计算结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <script setup> import { ref, computed } from 'vue'
const firstName = ref('John') const lastName = ref('Doe')
const fullName = computed(() => { return `${firstName.value} ${lastName.value}` }) </script>
<template> <div> <p>Full Name: {{ fullName }}</p> <button @click="firstName.value = 'Jane'">Change First Name</button> <button @click="lastName.value = 'Smith'">Change Last Name</button> </div> </template>
|
生命周期和模板引用
onMounted()
: 在组件被挂载到 DOM 之后执行的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13
| <script setup> import { ref, onMounted } from 'vue'
const pElementRef = ref(null)
onMounted(() => { pElementRef.value.textContent = 'mounted!' }) </script>
<template> <p ref="pElementRef">Hello</p> </template>
|
注意:模板引用是一种特殊的语法,它允许我们在模板中嵌入一个组件,并将其作为一个变量来使用。模板引用的语法是 #
,后面跟着组件的名字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <template> <div> <h1>My Component</h1> <p>This is a paragraph.</p> <my-child></my-child> </div> </template>
<script setup> import MyChild from './MyChild.vue' </script>
<template #my-child> <div> <h2>My Child Component</h2> <p>This is a child component.</p> </div> </template>
|
侦听器
watch()
:是 Vue.js 中用于观察数据的变化并执行相应的函数的选项。它可以帮助我们在数据变化时执行异步或开销较大的操作,并自动更新 DOM。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <script setup> import { ref, watch } from 'vue'
const count = ref(0)
watch(count, (newValue, oldValue) => { console.log(`count is: ${newValue}`) }) </script>
<template> <div> <p>{{ count }}</p> <button @click="count++">Increment</button> </div> </template>
|
注意:watch() 接收两个参数:要观察的表达式(可以是一个函数)和回调函数。回调函数会在表达式的值发生变化时被调用,并接收两个参数:当前值和上一个值。
组件
真正的 Vue 应用往往是由嵌套组件创建的。父组件可以在模板中渲染另一个组件作为子组件。
1 2 3 4 5 6 7 8 9 10 11 12 13
| <template> <h2>A Child Component!</h2> </template>
<script setup> import ChildComp from './ChildComp.vue' </script>
<template> <ChildComp /> </template>
|
Props
props
: 是 Vue.js 中用于定义组件属性的选项。它可以接收一个数组,包含组件接收的 props 的名称。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <script setup> const props = defineProps({ msg: String }) </script>
<template> <h2>{{ msg || 'No props passed yet' }}</h2> </template>
<script setup> import ChildComp from './ChildComp.vue'
const name = 'John' </script>
<template> <ChildComp :name="name" /> </template>
|
注意:props 选项应该定义在组件的选项对象中,而不是 data 选项中。
Emits
emits
: 选项允许我们定义一个自定义事件,这个事件可以在父组件中用 v-on
监听。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <script setup> const emit = defineEmits(['response'])
emit('response', 'hello from child') </script>
<template> <h2>Child component</h2> </template>
<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>
|
注意:emits 选项应该定义在组件的选项对象中,而不是 data 选项中。
插槽
<slot>
: 是 Vue.js 中用于定义组件插槽的元素。它可以让我们在父组件中向子组件提供内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <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>
|
注意:父组件可以向子组件传递内容,子组件可以用 <slot>
元素来接收。