4373 字
12 分钟
Vue 基础核心笔记
2024-04-10

Vue相关基础#

Vue基本原理#

MVVM#

1. MVVM 的定义#

MVVM(Model-View-ViewModel)是一种软件架构模式,主要用于分离用户界面逻辑和业务逻辑。它由以下三个部分组成:

  • Model(模型):表示数据和业务逻辑层,负责管理应用程序的数据。
  • View(视图):表示用户界面层,负责展示数据给用户。
  • ViewModel(视图模型):==作为 Model 和 View 之间的桥梁,负责将 Model 的数据转换为 View 可以使用的格式,并监听 Model 的变化来更新 View==。

2. MVVM 的核心特点#

  • 数据绑定:ViewModel 和 View 之间通过双向绑定机制保持同步。
  • 命令绑定:View 上的用户交互(如点击按钮)可以通过命令绑定触发 ViewModel 中的方法。
  • 数据驱动:通过修改 ViewModel 中的数据,自动更新 View。

Vue 的 MVVM 实现#

Vue 是一个典型的 MVVM 框架,它的运作原理可以分为以下几个方面:

1. 数据绑定#

Vue 使用数据绑定机制将 Model 和 View 连接起来。具体来说:

  • 单向绑定:从 Model 到 View 的数据流动(即数据变化时自动更新视图)。
  • 双向绑定:不仅支持从 Model 到 View 的数据流动,还支持从 View 到 Model 的数据流动(例如输入框的值会自动更新到数据模型中)。

2. 响应式系统#

Vue 的响应式系统是其实现 MVVM 的核心。以下是其工作原理:

  • 数据劫持:Vue 通过 Object.defineProperty 或 Proxy(Vue 3 中使用)对数据对象进行拦截,监听数据的变化。
  • 依赖收集:当模板中的数据被访问时,Vue 会自动记录哪些数据被使用,从而建立数据和视图之间的依赖关系。
  • 视图更新:当数据发生变化时,Vue 会通知所有依赖该数据的视图进行更新。

3. 模板编译#

Vue 的模板编译器会将 HTML 模板解析为虚拟 DOM(Virtual DOM),并生成渲染函数。具体流程如下:

  • 解析模板:将模板字符串解析为抽象语法树(AST)。
  • 优化:对 AST 进行静态节点标记,提升性能。
  • 生成渲染函数:将 AST 转换为可执行的 JavaScript 渲染函数。

4. 虚拟 DOM#

Vue 使用虚拟 DOM 来提高渲染性能。虚拟 DOM 是一种轻量级的 JavaScript 对象,用于表示真实的 DOM 结构。其主要作用包括:

  • Diff 算法:当数据变化时,Vue 会比较新旧虚拟 DOM 树,计算出最小的差异。
  • 批量更新:Vue 会将多个状态变更合并为一次 DOM 更新,减少操作次数。

Vue 的运作流程#

以下是 Vue 在运行时的基本流程:

  1. 初始化阶段
    • 创建 Vue 实例时,框架会初始化选项(如 datamethodscomputed 等)。
    • 使用 Object.defineProperty 或 Proxy 对 data 属性进行响应式处理。
    • 编译模板,生成渲染函数。
  2. 挂载阶段
    • 将 Vue 实例挂载到指定的 DOM 元素上(==通过 el 配置项==)。
    • 调用 beforeMountmounted 生命周期钩子。
  3. 渲染阶段
    • 执行渲染函数,生成虚拟 DOM。
    • 将虚拟 DOM 转换为真实 DOM 并插入页面。
  4. 更新阶段
    • 当数据发生变化时,触发依赖收集机制。
    • Vue 重新执行渲染函数,生成新的虚拟 DOM。
    • 使用 Diff 算法比较新旧虚拟 DOM,更新真实 DOM。
  5. 销毁阶段
    • 销毁 Vue 实例时,清理所有的事件监听器和子组件。
    • 调用 beforeDestroydestroyed 生命周期钩子。

Vue 的 MVVM 特点#

1. 数据驱动#

Vue 的核心理念是“数据驱动视图”,开发者只需关注数据的变化,而无需手动操作 DOM。例如:

new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});

message 的值发生变化时,Vue 会自动更新视图。

2. 双向绑定#

Vue 提供了内置的 v-model 指令,实现了数据的双向绑定。例如:

<input v-model="message" />
<p>{{ message }}</p>

在上述代码中,输入框的值和 message 数据会相互同步。

3. 模板语法#

Vue 提供了简洁的模板语法,方便开发者快速构建动态视图。例如:

<ul>
<li v-for="item in items">{{ item.name }}</li>
</ul>

4. 计算属性和监听器#

  • 计算属性:用于基于已有数据派生新数据。
  • 监听器:用于监听数据变化并执行特定逻辑。

Vue生命周期#

1.生命周期#

  • 创建阶段(Creation):Vue 实例被创建时的初始化过程。包括 beforeCreate 和 created 钩子。
  • 挂载阶段(Mounting):Vue 实例将模板编译并挂载到 DOM 上的过程。包括 beforeMount 和 mounted 钩子。
  • 更新阶段(Updating):当数据发生变化时,Vue 会对 DOM 进行重新渲染和更新的过程。包括 beforeUpdate 和 updated 钩子。
  • 销毁阶段(Destroying):Vue 实例被销毁时的清理过程。包括 beforeDestroy 和 destroyed 钩子(在 Vue 3 中分别为 beforeUnmount 和 unmounted)。

2.八个核心生命周期钩子函数#

1. beforeCreate#

  • 触发时机:实例刚刚被创建,尚未初始化数据和事件监听器。
  • 特点
    • 数据观测 (data) 和方法 (methods) 尚未初始化。
    • $el 属性不可用。
  • 用途:几乎没有实际用途,通常用于调试或了解初始化前的状态。
beforeCreate() {
console.log(this.$data); // undefined
}

2. created#

  • 触发时机:实例已经完成数据观测、计算属性、方法等初始化,但尚未挂载到 DOM。
  • 特点
    • 可以访问 datamethods
    • $el 属性仍然不可用。
  • 用途
    • 发送异步请求(如获取 API 数据)。
    • 初始化一些数据或绑定事件。
created() {
console.log(this.$data); // 已经初始化
this.fetchData(); // 调用方法发送请求
}

3. beforeMount#

  • 触发时机:模板编译完成,但尚未挂载到 DOM。
  • 特点
    • 模板已经编译为虚拟 DOM,但尚未渲染到页面上。
    • ==$el 属性存在,但内容为空。==
  • 用途
    • 类似于 created,可以在此处进行初始化操作。
beforeMount() {
console.log(this.$el); // 存在,但内容为空
}

==4. mounted==#

  • 触发时机:实例已经挂载到 DOM,页面可以正常显示。
  • 特点
    • ==$el 属性可用,且已替换为真实的 DOM 元素。==
    • 页面上的 DOM 已经渲染完成。
  • 用途
    • 操作 DOM 元素。
    • 初始化第三方插件(如地图、图表等)。
mounted() {
console.log(this.$el); // 真实的 DOM 元素
this.initMap(); // 初始化地图
}

5. beforeUpdate#

  • 触发时机:数据发生变化,DOM 更新之前。
  • 特点
    • 数据已经更新,但 DOM 尚未更新。
    • 可以访问旧的 DOM 结构。
  • 用途
    • 在 DOM 更新前进行额外的操作(如移除手动绑定的事件监听器)。
beforeUpdate() {
console.log('DOM 即将更新');
}

6. updated#

  • 触发时机:数据变化导致的 DOM 更新完成后。
  • 特点
    • DOM 已经更新完毕。
    • 不建议在此修改状态,否则可能引发无限循环。
  • 用途
    • 操作更新后的 DOM 元素。
updated() {
console.log('DOM 已更新');
}

==7. beforeDestroy (Vue 2) / beforeUnmount (Vue 3)==#

  • 触发时机:实例即将被销毁。
  • 特点
    • ==实例仍然完全可用。==
  • 用途
    • 清理定时器、解绑事件监听器等。
beforeDestroy() {
console.log('实例即将销毁');
clearInterval(this.timer); // 清理定时器
}

8. destroyed (Vue 2) / unmounted (Vue 3)#

  • 触发时机:实例已经被销毁。
  • 特点
    • 所有指令和事件监听器已被移除。
    • 子实例也被销毁。
  • 用途:无特殊用途,主要用于确认实例已销毁。
destroyed() {
console.log('实例已销毁');
}

关于$el结点#

  • $el 是 ==Vue 实例的一个属性,表示 Vue 组件或应用挂载到页面上的根 DOM 元素。==
  • 它==只有在组件被挂载(即 mounted 钩子之后)时才可用==。

1.使用场景#

  1. 访问挂载的 DOM 元素 在某些情况下,你可能需要直接操作 DOM,例如初始化第三方库(如地图、图表等),此时可以通过 $el 获取挂载点的 DOM 元素。
  2. 调试和检查 使用 $el 可以帮助开发者快速定位挂载的 DOM 元素,方便调试。
  3. 动态操作 DOM 如果需要对挂载后的 DOM 进行一些额外的操作(例如添加样式、绑定事件等),可以通过 $el 来实现。

2.注意事项#

  1. ==避免直接修改 $el 的内容== ==Vue 的核心理念是通过数据驱动视图更新,而不是直接操作 DOM。==因此,尽量避免直接修改 $el 的内容,否则可能导致 Vue 的响应式系统失效。
  2. 确保 $el 已经挂载 如果在 mounted 钩子之前尝试访问 $el,会得到 undefined 或空值。
  3. Vue 3 中的变化 在 Vue 3 中,$el 的行为与 Vue 2 类似,但在使用 Composition API 时,由于没有 this 上下文,可以通过 ref 和模板引用的方式获取 DOM 元素。

模板语法#

1. 插值(Interpolation)==单向绑定 用于文本数据==#

1.1 基本用法#

Vue 使用双大括号 {{ }} 来进行插值,将数据动态插入到模板中。

<div id="app">
<p>{{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
</script>
  • 特点
    • 双大括号中的内容会被解析为 JavaScript 表达式。
    • 插值只能用于文本内容,不能用于属性绑定。

1.2 注意事项#

  • 如果需要绑定属性(如 srcclass),应使用 v-bind 指令。
  • 插值不支持多行表达式或复杂逻辑,仅限于简单的表达式。

2. 指令(Directives)#

指令是 Vue 提供的特殊属性,以 v- 开头,用于增强 HTML 的功能。


2.1 v-html ==(单向插入html文本)==#

双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令

<template>
<div>
<div v-html="content"></div>
</div>
</template>
<script>
export default {
data() {
return {
content: '<p style="color: red;">这是通过 v-html 渲染的内容!</p>'
};
}
};
</script>

这个 span 的内容将会被替换成为 property 值 rawHtml,直接作为 HTML——会忽略解析 property 值中的数据绑定。注意,你不能使用 v-html 来复合局部模板,因为 Vue 不是基于字符串的模板引擎。反之,对于用户界面 (UI),组件更适合作为可重用和可组合的基本单位。

你的站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要 对用户提供的内容使用插值。

2.2 v-bind:属性绑定 ==单向绑定html属性值 v-bind :==#

基本用法#

v-bind 用于动态绑定 HTML 属性。

<img v-bind:src="imageSrc" alt="Vue Logo">
<!-- 简写 -->
<img :src="imageSrc" alt="Vue Logo">

示例#

data: {
imageSrc: 'https://example.com/vue-logo.png'
}

动态绑定多个属性#

可以结合对象动态绑定多个属性。

<a v-bind="{ href: url, target: '_blank' }">链接</a>
<!-- 简写 -->
<a :href="url" :target="'_blank'">链接</a>

注意事项#

  • v-bind 支持动态计算属性值。
  • 对于布尔属性(如 disabled),如果值为 false,属性会被移除。

2.2 v-on:事件监听 ==v-on:事件 /@事件==#

基本用法#

v-on 用于监听 DOM 事件,并执行方法或表达式。

<button v-on:click="increment">点击我</button>
<!-- 简写 -->
<button @click="increment">点击我</button>

示例#

data: {
count: 0
},
methods: {
increment() {
this.count++;
}
}

内联处理器#

可以在事件处理函数中直接传参或调用表达式。

<button @click="greet('你好')">打招呼</button>
methods: {
greet(message) {
alert(message);
}
}

修饰符#

v-on 支持多种修饰符来改变事件行为:

修饰符功能
.stop阻止事件冒泡
.prevent阻止默认行为
.capture在捕获阶段触发事件
.self只当事件从目标元素本身触发时才触发
.once只触发一次

1. .stop#

  • 作用:阻止事件冒泡(Event Bubbling)。
  • 场景:当一个事件从子元素传播到父元素时,可以使用 .stop 阻止这种传播。
  • 示例
<div @click="handleParentClick">
Parent
<button @click.stop="handleChildClick">Child</button>
</div>

在这个例子中,点击按钮时,handleChildClick 会被触发,但 handleParentClick 不会被触发,因为事件冒泡被阻止了。


2. .prevent#

  • 作用:阻止默认行为(Default Behavior)。
  • 场景:适用于表单提交、链接跳转等需要阻止默认操作的场景。
  • 示例
<form @submit.prevent="onSubmit">
<button type="submit">Submit</button>
</form>

在这个例子中,表单提交时不会刷新页面,而是调用 onSubmit 方法。


3. .capture#

  • 作用:在捕获阶段(Capture Phase)触发事件,而不是在冒泡阶段。
  • 场景:当需要在事件传播的早期阶段处理事件时使用。
  • 示例
<div @click.capture="handleParentClick">
Parent
<button @click="handleChildClick">Child</button>
</div>

在这个例子中,点击按钮时,handleParentClick 会在 handleChildClick 之前被触发,因为事件在捕获阶段就被捕获了。


4. .self#

  • 作用:只有当事件是从目标元素本身触发时才触发处理函数。
  • 场景:防止子元素的事件影响父元素。
  • 示例
<div @click.self="handleDivClick">
Parent
<button>Child</button>
</div>

在这个例子中,点击按钮时,handleDivClick 不会被触发,因为事件不是从 div 本身触发的。


5. .once#

  • 作用:事件只触发一次。
  • 场景:适用于只需要响应一次的事件。
  • 示例
<button @click.once="handleClick">Click me</button>

在这个例子中,点击按钮后,handleClick 只会执行一次,后续点击将不再触发。


总结#

这些修饰符可以单独使用,也可以组合使用。例如:

<form @submit.prevent.stop="onSubmit">
<button type="submit">Submit</button>
</form>

==在这个例子中,.prevent 阻止了表单的默认提交行为,.stop 阻止了事件冒泡。==


2.3 v-if / v-else-if / v-else:条件渲染#

基本用法#

根据条件决定是否渲染元素。

<div v-if="isVisible">显示此内容</div>
<div v-else>显示其他内容</div>

示例#

data: {
isVisible: true
}

注意事项#

  • v-if 是惰性的,只有在条件为真时才会渲染。
  • ==如果需要频繁切换,建议使用 v-show。(反复渲染虚拟dom)==

2.4 v-show:条件显示#

基本用法#

无论条件如何,v-show 总是渲染元素,通过 CSS 的 display 属性控制显示/隐藏。

<div v-show="isVisible">显示此内容</div>

区别#

特性v-ifv-show
渲染时机条件为真时渲染始终渲染
切换性能第一次切换较慢切换较快
场景不经常切换频繁切换

2.5 v-for:列表渲染#

基本用法#

用于循环渲染列表。

<ul>
<li v-for="(item, index) in items" :key="index">{{ item }}</li>
</ul>

示例#

data: {
items: ['苹果', '香蕉', '橙子']
}

参数说明#

  • (item, index)item 是当前项,index 是索引。
  • ==key:必须为每个节点指定唯一键值,推荐使用数组中的唯一标识。==

对象迭代#

也可以用于遍历对象的键值对。

<ul>
<li v-for="(value, key) in object">{{ key }}: {{ value }}</li>
</ul>
data: {
object: { name: 'Alice', age: 25 }
}

2.6 v-model:==双向绑定 v-model===#

基本用法#

==用于表单输入与数据的双向绑定==。

<input v-model="message" placeholder="编辑消息">
<p>你输入的内容是:{{ message }}</p>

示例#

data: {
message: ''
}

修饰符#

v-model 支持以下修饰符:

修饰符功能
.lazychange 事件后同步数据
.number自动将输入值转换为数字
.trim自动去除首尾空格

1. .lazy#

  • 功能:在 change 事件后同步数据,而不是默认的 input 事件。
  • 场景:适用于需要在用户完成输入(如失去焦点)后再更新绑定值的情况。
  • 示例
<input v-model.lazy="message" type="text">

在这个例子中,message 的值只有在输入框失去焦点或按下回车键时才会更新。


2. .number#

  • 功能:自动将输入值转换为数字类型。
  • 场景:适用于需要确保输入值为数字类型的场景,例如表单中的数字字段。
  • 示例
<input v-model.number="age" type="number">

如果用户输入了 "42"age 的值会被自动转换为数字 42。如果输入的内容无法转换为数字(如 "abc"),则值会变为 NaN


3. .trim#

  • 功能:自动去除输入值的首尾空格。
  • 场景:适用于需要清理用户输入中的多余空格的情况。
  • 示例
<input v-model.trim="name" type="text">

如果用户输入了 " Alice "name 的值会被自动处理为 "Alice"


总结#

这些修饰符可以单独使用,也可以组合使用。例如:

<input v-model.lazy.trim.number="value" type="text">

在这个例子中:

  • .lazy:只在 change 事件后同步数据。
  • .trim:自动去除首尾空格。
  • .number:将输入值转换为数字。

3. 表达式(Expressions)#

Vue 的模板支持简单的 JavaScript 表达式。可放入插槽

示例#

<p>{{ number + 1 }}</p>
<p>{{ ok ? 'YES' : 'NO' }}</p>
<p>{{ message.split('').reverse().join('') }}</p>

限制#

  • ==模板中只能包含单个表达式,不能包含语句(如 iffor)。==
  • 复杂逻辑应提取到计算属性或方法中。

4. 过滤器(Filters)#

过滤器用于格式化文本输出。

基本用法#

<p>{{ message | capitalize }}</p>

定义过滤器#

filters: {
capitalize(value) {
if (!value) return '';
return value.charAt(0).toUpperCase() + value.slice(1);
}
}

全局过滤器#

可以通过 Vue.filter 定义全局过滤器。

Vue.filter('capitalize', function (value) {
if (!value) return '';
return value.charAt(0).toUpperCase() + value.slice(1);
});

链式调用#

可以同时应用多个过滤器。

<p>{{ message | filterA | filterB }}</p>

5. 修饰符(Modifiers)#

修饰符是以 .xxx 形式附加在指令后的特殊后缀,用于改变指令的行为。

常见修饰符#

指令修饰符功能
v-on.prevent阻止默认行为
v-on.stop阻止事件冒泡
v-model.lazy延迟更新
v-model.number转换为数字
v-model.trim去除首尾空格

6. 插槽(Slots)#

插槽允许父组件向子组件传递内容。

6.1 默认插槽#

<!-- 子组件 -->
<template>
<div>
<slot>默认内容</slot>
</div>
</template>
<!-- 父组件 -->
<my-component>
<p>这是从父组件传入的内容</p>
</my-component>

6.2 具名插槽#

允许多个插槽。

<!-- 子组件 -->
<template>
<div>
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
</div>
</template>
<!-- 父组件 -->
<my-component>
<template v-slot:header>
<h1>标题</h1>
</template>
<p>主体内容</p>
<template #footer>
<p>页脚</p>
</template>
</my-component>

6.3 作用域插槽#

允许子组件向父组件传递数据。

<!-- 子组件 -->
<template>
<div>
<slot :user="user"></slot>
</div>
</template>
<!-- 父组件 -->
<my-component v-slot:default="slotProps">
{{ slotProps.user.name }}
</my-component>

7. 计算属性和侦听器#

7.1 计算属性#

==computed中的计算函数,每当其内部依赖值发生改变就将重新计算== 用于复杂的数据处理逻辑。

computed: {
// 计算总价
totalPrice() {
return this.carlist
.filter(item => { item.isSelected })
.reduce((total, item) => { total + item.Number * item.price }, 0)
}
},
<div style=" width: 60%;text-align: center; margin-top: 20px;">
<h3>Total Price: {{ totalPrice }} $</h3>
</div>

7.2 侦听器#

用于监听数据变化并执行副作用。 ==监听属性,这里面的函数名是监听属性的名称 参数是传入新值与旧值==

watch: {
message(newVal, oldVal) {
console.log(`消息已从 ${oldVal} 更改为 ${newVal}`);
}
}
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Vue 基础核心笔记
https://minikou.cloud/posts/vue/
作者
minikou
发布于
2024-04-10
许可协议
Unlicensed

部分信息可能已经过时

目录