初入Vue.js

对于vue.js渐进式教程的一些总结与思考,方便自己以后查阅。以下是一些基础概念,我会在进一步学习后补全。

起步(什么是Vue.js)

Vue.js是一个渐进式的前端框架,它是一套用于构建用户界面的渐进式框架。它与其它大型框架不同,它专注于MVVM(模型-视图-视图模型)架构和组件化开发。

语法

Vue.js的语法与其它前端框架有所不同,它使用了HTML-based模板语法,并提供了一些自定义指令来绑定数据和DOM。

声明式渲染

  1. Vue 的核心功能就是声明式渲染:通过扩展于标准 HTML 的模板语法,我们可以根据 JavaScript 的状态来描述 HTML 应该是什么样子的。当状态改变时,HTML 会自动更新。

  2. 能在改变时触发更新的状态被称作是响应式的。

  3. 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++;
    }
  4. 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'

// 给每个 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" 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>

<!-- ChildComp.vue -->

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

<!-- ChildComp.vue -->

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

<!-- ParentComp.vue -->

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

<!-- ParentComp.vue -->

<script setup>
import { ref } from 'vue'
import ChildComp from './ChildComp.vue'

const msg = ref('from parent')
</script>

<template>
<ChildComp>Message: {{ msg }}</ChildComp>
</template>

注意:父组件可以向子组件传递内容,子组件可以用 <slot> 元素来接收。