Vue.js 完全指南:从入门到精通
1. Vue.js 简介
1.1 什么是 Vue.js?
Vue.js(通常简称为 Vue)是一个用于构建用户界面的渐进式 JavaScript 框架。所谓"渐进式",意味着 Vue 的设计是由浅入深的,你可以根据自己的需求选择使用它的一部分或全部功能。
Vue 最初由尤雨溪(Evan You)在 2014 年创建,其设计灵感部分来源于 Angular,但更轻量级且更加灵活。Vue 专注于视图层(View Layer),易于与其他库或现有项目集成。
1.2 Vue.js 的核心特性
Vue.js 的核心特性包括:
- 声明式渲染:Vue 使用模板语法,允许我们以声明式的方式将数据渲染到 DOM。
- 响应式系统:Vue 自动追踪依赖关系并在数据变化时更新 DOM。
- 组件化开发:Vue 应用由独立、可复用的组件构建而成,每个组件都包含自己的 HTML、CSS 和 JavaScript。
- 虚拟 DOM:Vue 使用虚拟 DOM 来高效地更新实际 DOM。
- 指令系统:Vue 提供了一系列以
v-
开头的特殊属性,用于在 HTML 中实现各种功能。 - 过渡效果:Vue 提供了内置的过渡和动画系统。
- 状态管理:通过 Vuex 或 Pinia 提供集中式状态管理。
- 路由管理:通过 Vue Router 提供客户端路由管理。
1.3 Vue.js 的优势
Vue.js 相比其他框架具有以下优势:
- 易学易用:Vue 的 API 设计简洁直观,学习曲线平缓,特别适合初学者。
- 灵活渐进:可以逐步采用,从简单的 CDN 引入到完整的单页应用开发。
- 高性能:通过虚拟 DOM 和响应式系统实现高效的 DOM 更新。
- 轻量级:核心库非常小(约 20KB gzipped),不增加太多应用的加载时间。
- 生态系统:拥有丰富的插件、组件库和开发工具。
- 良好的文档:官方文档详细清晰,并有多语言版本。
- 活跃的社区:大量的开发者和企业支持,资源丰富。
1.4 Vue.js 的版本演进
Vue.js 的主要版本演进:
- Vue 1.x:初始版本,奠定了 Vue 的基础。
- Vue 2.x:引入虚拟 DOM,提升性能和稳定性,增加了服务端渲染支持。
- Vue 3.x:重写核心代码,使用 Proxy 代替 Object.defineProperty 实现响应式系统,引入 Composition API,支持 TypeScript,性能更佳。
2. 安装与环境搭建
2.1 Vue.js 的安装方式
Vue.js 提供了多种安装方式,可以根据不同的项目需求选择:
2.1.1 使用 CDN 直接引入
最简单的方式是通过 CDN 直接在 HTML 文件中引入 Vue.js:
<!-- 开发环境版本,包含有用的警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script><!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
Vue 2.x 的 CDN 链接:
<!-- 开发环境版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><!-- 生产环境版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.min.js"></script>
2.1.2 使用 npm 或 yarn 安装
对于更复杂的项目,推荐使用 npm 或 yarn 安装:
# npm
npm install vue# yarn
yarn add vue
2.1.3 使用 Vue CLI 创建项目
Vue CLI 是 Vue.js 的官方脚手架工具,用于快速搭建 Vue 项目:
# 安装 Vue CLI
npm install -g @vue/cli# 创建一个新项目
vue create my-project# 或者使用图形界面
vue ui
2.1.4 使用 Vite 创建项目
Vite 是一个现代化的构建工具,由 Vue 团队开发,特别适合 Vue 项目:
# npm
npm create vite@latest my-vue-app -- --template vue# yarn
yarn create vite my-vue-app --template vue
2.2 项目结构解析
一个典型的 Vue CLI 创建的项目结构如下:
my-project/
├── node_modules/ # 依赖包
├── public/ # 静态资源,不会被 webpack 处理
│ ├── favicon.ico # 网站图标
│ └── index.html # 页面模板
├── src/ # 源代码目录
│ ├── assets/ # 资源文件,会被 webpack 处理
│ ├── components/ # Vue 组件
│ ├── views/ # 页面级别的组件
│ ├── router/ # Vue Router 配置
│ ├── store/ # Vuex 状态管理
│ ├── App.vue # 根组件
│ └── main.js # 入口文件
├── .gitignore # Git 忽略文件
├── babel.config.js # Babel 配置
├── package.json # 项目依赖和脚本
├── README.md # 项目说明
└── vue.config.js # Vue CLI 配置文件
Vite 创建的项目结构稍有不同:
my-vue-app/
├── node_modules/ # 依赖包
├── public/ # 静态资源
├── src/ # 源代码目录
│ ├── assets/ # 资源文件
│ ├── components/ # Vue 组件
│ ├── App.vue # 根组件
│ └── main.js # 入口文件
├── .gitignore # Git 忽略文件
├── index.html # HTML 入口文件(注意位置不同)
├── package.json # 项目依赖和脚本
├── README.md # 项目说明
└── vite.config.js # Vite 配置文件
2.3 开发工具配置
为了提高 Vue.js 开发效率,推荐使用以下工具:
2.3.1 编辑器推荐
- Visual Studio Code:轻量级且功能强大的编辑器,有丰富的 Vue.js 插件支持。
2.3.2 推荐的 VS Code 插件
- Volar:Vue 3 的官方 VS Code 插件,提供语法高亮、智能提示等功能。
- ESLint:代码质量检查工具。
- Prettier:代码格式化工具。
- GitLens:Git 集成工具。
- Auto Import:自动导入组件和函数。
2.3.3 浏览器扩展
- Vue.js devtools:Chrome 和 Firefox 的浏览器扩展,用于调试 Vue 应用。可以查看组件层次结构、状态、事件等信息。
2.4 第一个 Vue 应用
创建一个简单的 Vue 应用,了解基本概念:
2.4.1 使用 CDN 创建
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>My First Vue App</title><script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>
</head>
<body><div id="app"><h1>{{ message }}</h1><button @click="reverseMessage">反转消息</button></div><script>const { createApp } = Vue;createApp({data() {return {message: 'Hello Vue!'}},methods: {reverseMessage() {this.message = this.message.split('').reverse().join('')}}}).mount('#app');</script>
</body>
</html>
2.4.2 使用 Vue CLI 或 Vite 创建
创建项目后,修改 App.vue
文件:
<template><div id="app"><h1>{{ message }}</h1><button @click="reverseMessage">反转消息</button></div>
</template><script>
export default {name: 'App',data() {return {message: 'Hello Vue!'}},methods: {reverseMessage() {this.message = this.message.split('').reverse().join('')}}
}
</script><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;text-align: center;margin-top: 60px;
}
</style>
3. Vue 实例与生命周期
3.1 Vue 实例
在 Vue 2 中,每个 Vue 应用都是通过创建一个 Vue
实例开始的:
const vm = new Vue({// 选项
})
在 Vue 3 中,我们使用 createApp
函数创建应用实例:
const app = Vue.createApp({// 选项
})// 挂载到 DOM 元素
app.mount('#app')
3.2 Vue 实例选项
Vue 实例接受许多选项,常用的包括:
3.2.1 数据选项
- data:Vue 实例的数据对象,在组件中是一个返回对象的函数。
- props:接收来自父组件的数据。
- computed:计算属性,基于依赖进行缓存。
- methods:实例的方法。
- watch:监听数据变化的回调函数。
3.2.2 DOM 相关选项
- el:指定挂载的 DOM 元素(Vue 2)。
- template:字符串模板。
- render:渲染函数,代替模板。
3.2.3 生命周期钩子
- beforeCreate、created
- beforeMount、mounted
- beforeUpdate、updated
- beforeDestroy、destroyed(Vue 2)/ beforeUnmount、unmounted(Vue 3)
3.2.4 资源选项
- directives:自定义指令。
- filters(Vue 2):自定义过滤器。
- components:注册组件。
3.2.5 组合选项
- mixins:混入对象。
- extends:扩展另一个组件。
- provide/inject:依赖注入。
3.3 Vue 实例属性和方法
Vue 实例暴露了一些有用的实例属性和方法,以 $
前缀标识:
const vm = new Vue({data: {message: 'Hello'}
})// 实例属性
console.log(vm.$data.message) // 'Hello'
console.log(vm.$el) // DOM 元素// 实例方法
vm.$watch('message', function(newValue, oldValue) {// 当 message 变化时调用
})
vm.$set(object, key, value) // 响应式地设置属性
vm.$delete(object, key) // 响应式地删除属性
3.4 Vue 生命周期详解
Vue 组件实例有一个完整的生命周期,从创建到销毁,可以在特定阶段执行自定义代码。
3.4.1 生命周期图示
创建阶段 挂载阶段 更新阶段 销毁阶段
┌─────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐
│ │ │ │ │ │ │ │
│ beforeCreate │ │ beforeMount │ │ beforeUpdate │ │ beforeDestroy │
│ │ │ │ │ │ │ (Vue 2) │
│ ↓ │ │ ↓ │ │ ↓ │ │ or │
│ │ │ │ │ │ │ beforeUnmount │
│ created │ │ mounted │ │ updated │ │ (Vue 3) │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ ↓ │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ destroyed │
│ │ │ │ │ │ │ (Vue 2) │
│ │ │ │ │ │ │ or │
│ │ │ │ │ │ │ unmounted │
│ │ │ │ │ │ │ (Vue 3) │
└─────────────────────┘ └───────────────────────┘ └───────────────────────┘ └───────────────────────┘
3.4.2 生命周期钩子函数详解
-
beforeCreate:
- 实例初始化后,数据观测和事件配置之前调用。
- 此时无法访问 data、computed、methods 等选项。
-
created:
- 实例创建完成后立即调用。
- 可以访问 data、computed、methods 等,但尚未挂载到 DOM。
- 适合执行初始化数据获取。
-
beforeMount:
- 挂载开始前调用。
- 相关的 render 函数首次被调用。
-
mounted:
- 实例挂载到 DOM 后调用。
- 可以访问 DOM 元素,适合执行需要访问 DOM 的操作。
- 不能保证所有子组件也都已经挂载完成。
-
beforeUpdate:
- 数据更新时,虚拟 DOM 重新渲染前调用。
- 适合在更新前访问现有的 DOM。
-
updated:
- 数据更改导致的虚拟 DOM 重新渲染后调用。
- 应避免在此钩子中修改数据,可能导致无限循环。
-
beforeDestroy(Vue 2)/ beforeUnmount(Vue 3):
- 实例销毁前调用。
- 实例仍然完全可用,适合清理事件监听器、定时器等资源。
-
destroyed(Vue 2)/ unmounted(Vue 3):
- 实例销毁后调用。
- 所有指令解绑,事件监听器移除,子实例也被销毁。
3.4.3 其他生命周期钩子
-
activated:
- 被 keep-alive 缓存的组件激活时调用。
-
deactivated:
- 被 keep-alive 缓存的组件停用时调用。
-
errorCaptured:
- 捕获一个来自后代组件的错误时调用。
-
renderTracked(Vue 3):
- 跟踪虚拟 DOM 重新渲染时调用。
-
renderTriggered(Vue 3):
- 虚拟 DOM 重新渲染被触发时调用。
3.4.4 生命周期钩子使用示例
export default {data() {return {message: 'Hello Vue'}},beforeCreate() {console.log('beforeCreate: 实例初始化')// 此时无法访问 dataconsole.log('this.message:', this.message) // undefined},created() {console.log('created: 实例已创建')// 可以访问 dataconsole.log('this.message:', this.message) // 'Hello Vue'// 可以执行异步操作this.fetchData()},beforeMount() {console.log('beforeMount: 挂载前')// DOM 尚未创建console.log(this.$el) // 尚未挂载的元素},mounted() {console.log('mounted: 已挂载')// 可以访问 DOMconsole.log(this.$el) // 实际 DOM 元素// 适合执行需要访问 DOM 的操作this.setupChart()},beforeUpdate() {console.log('beforeUpdate: 数据更新前')// 可以在更新前访问现有的 DOM},updated() {console.log('updated: 数据更新后')// DOM 已更新},beforeUnmount() { // Vue 3 使用 beforeUnmount,Vue 2 使用 beforeDestroyconsole.log('beforeUnmount: 卸载前')// 清理资源this.cleanupResources()},unmounted() { // Vue 3 使用 unmounted,Vue 2 使用 destroyedconsole.log('unmounted: 已卸载')// 实例已销毁},// 辅助方法methods: {fetchData() {// 获取初始数据},setupChart() {// 设置图表},cleanupResources() {// 清理资源}}
}
4. 模板语法与数据绑定
Vue 使用基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定到底层组件实例的数据。
4.1 插值
4.1.1 文本插值
最基本的数据绑定形式是使用"Mustache"语法(双大括号):
<span>消息:{{ message }}</span>
{{ message }}
会被替换为对应数据对象上 message
属性的值。每当 message
属性变化时,插值内容也会更新。
4.1.2 原始 HTML
双大括号会将数据解释为普通文本,如果要输出 HTML,需要使用 v-html
指令:
<p>使用文本插值:{{ rawHtml }}</p>
<p>使用 v-html 指令:<span v-html="rawHtml"></span></p>
注意:在网站上动态渲染任意 HTML 可能会导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。
4.1.3 属性绑定
Mustache 语法不能用在 HTML 属性上,应该使用 v-bind
指令:
<div v-bind:id="dynamicId"></div>
简写形式(推荐使用):
<div :id="dynamicId"></div>
对于布尔属性,如果条件是 truthy 值,则属性会被包含;否则会被省略:
<button :disabled="isButtonDisabled">按钮</button>
4.1.4 使用 JavaScript 表达式
Vue 支持在绑定表达式中使用完整的 JavaScript 表达式:
{{ number + 1 }}{{ ok ? 'YES' : 'NO' }}{{ message.split('').reverse().join('') }}<div :id="`list-${id}`"></div>
每个绑定只能包含单个表达式,以下内容不会生效:
<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}<!-- 流控制也不会生效,使用三元表达式 -->
{{ if (ok) { return message } }}
4.2 指令
指令是带有 v-
前缀的特殊属性,用于在表达式的值改变时响应式地作用于 DOM。
4.2.1 指令基础
<p v-if="seen">现在你看到我了</p>
当 seen
的值为 true 时,<p>
元素会被渲染;否则会被移除。
4.2.2 指令参数
一些指令可以接收一个"参数",在指令名后以冒号表示:
<a v-bind:href="url">链接</a>
<a v-on:click="doSomething">点击</a>
4.2.3 动态参数
可以使用方括号括起来的 JavaScript 表达式作为指令的参数:
<a v-bind:[attributeName]="url">链接</a>
<a v-on:[eventName]="doSomething">点击</a>
这里的 attributeName
会被作为一个 JavaScript 表达式进行动态求值,求值结果作为最终的参数使用。
4.2.4 修饰符
修饰符是以 .
开头的特殊后缀,用于指定指令应该以特殊方式绑定:
<form v-on:submit.prevent="onSubmit">提交</form>
这里 .prevent
修饰符表示调用 event.preventDefault()
方法,阻止表单的默认提交行为。
4.3 常用内置指令
Vue 提供了许多内置指令,以下是一些最常用的:
4.3.1 v-bind
绑定 HTML 属性或组件 prop 到表达式:
<img v-bind:src="imageSrc">
<!-- 简写 -->
<img :src="imageSrc"><!-- 动态属性名 -->
<button :[key]="value"></button><!-- 绑定多个属性 -->
<div v-bind="{ id: 'container', class: 'wrapper' }"></div>
4.3.2 v-on
绑定事件监听器:
<button v-on:click="doThis"></button>
<!-- 简写 -->
<button @click="doThis"></button><!-- 动态事件名 -->
<button @[event]="doThis"></button><!-- 内联语句 -->
<button @click="count++"></button><!-- 对象语法 -->
<button v-on="{ click: onClick, mouseover: onMouseOver }"></button>
4.3.3 v-model
创建双向数据绑定:
<input v-model="message">
<textarea v-model="message"></textarea>
<select v-model="selected"><option value="">请选择</option><option value="1">选项 1</option><option value="2">选项 2</option>
</select>
4.3.4 v-if, v-else-if, v-else
条件性渲染元素:
<div v-if="type === 'A'">A</div>
<div v-else-if="type === 'B'">B</div>
<div v-else>Not A/B</div>
4.3.5 v-show
根据条件显示/隐藏元素(元素始终会被渲染):
<div v-show="isVisible">内容</div>
4.3.6 v-for
基于数组/对象渲染列表:
<ul><li v-for="item in items" :key="item.id">{{ item.text }}</li>
</ul><ul><li v-for="(item, index) in items" :key="item.id">{{ index }}: {{ item.text }}</li>
</ul><div v-for="(value, key, index) in object">{{ index }}. {{ key }}: {{ value }}
</div>
4.3.7 v-once
只渲染元素和组件一次:
<span v-once>这个将不会改变: {{ message }}</span>
4.3.8 v-html
更新元素的 innerHTML:
<div v-html="htmlContent"></div>
4.3.9 v-text
更新元素的文本内容:
<span v-text="message"></span>
<!-- 等同于 -->
<span>{{ message }}</span>
4.3.10 v-cloak
用于隐藏尚未编译的 Mustache 标签,直到组件实例准备完毕:
<div v-cloak>{{ message }}</div>
需要配合 CSS 规则使用:
[v-cloak] {display: none;
}
4.3.11 v-pre
跳过这个元素和它的子元素的编译过程:
<span v-pre>{{ 这里的内容不会被编译 }}</span>
4.4 数据绑定的响应式原理
Vue 的响应式系统是其核心特性之一,使得数据和视图之间保持同步。
4.4.1 Vue 2 响应式原理
Vue 2 使用 Object.defineProperty
劫持对象属性的 getter 和 setter,在访问或修改属性时进行依赖收集和通知更新。
基本流程:
- 将普通 JavaScript 对象传入 Vue 实例作为
data
选项。 - Vue 遍历该对象所有属性,并使用
Object.defineProperty
把这些属性全部转为 getter/setter。 - 这些 getter/setter 使 Vue 能够追踪依赖,在属性被访问和修改时通知变更。
- 每个组件实例都对应一个 watcher 实例,在组件渲染的过程中记录被访问的属性。
- 当 setter 被调用时,会通知 watcher,从而使它关联的组件重新渲染。
限制:
- 无法检测对象属性的添加或删除。
- 无法直接检测数组的变化,如通过索引设置值或修改数组长度。
4.4.2 Vue 3 响应式原理
Vue 3 使用 ES6 的 Proxy
代替 Object.defineProperty
,可以监听整个对象而不是个别属性,解决了 Vue 2 中的限制。
基本流程:
- 将普通 JavaScript 对象传入
reactive
函数。 - Vue 3 使用
Proxy
包装该对象,拦截对该对象的所有操作。 - 在渲染过程中,会自动建立依赖关系。
- 当对象被修改时,会触发相关组件的重新渲染。
优势:
- 可以检测到对象和数组的所有变化。
- 可以检测属性的添加和删除。
- 可以检测数组索引和长度的变化。
- 性能更好,不需要递归遍历对象的所有属性。
5. 计算属性与侦听器
5.1 计算属性
计算属性用于声明依赖于其他属性的复杂逻辑。计算属性是基于它们的依赖进行缓存的,只有在依赖变化时才会重新计算。
5.1.1 基本用法
export default {data() {return {firstName: 'John',lastName: 'Doe'}},computed: {fullName() {return this.firstName + ' ' + this.lastName}}
}
在模板中使用:
<p>{{ fullName }}</p>
5.1.2 计算属性 vs 方法
计算属性会基于其依赖进行缓存,只有在依赖发生变化时才会重新计算。而方法在每次重新渲染时都会执行。
// 计算属性
computed: {expensiveComputation() {console.log('计算属性被执行')return this.items.filter(item => item.active).map(item => item.value)}
}// 方法
methods: {expensiveMethod() {console.log('方法被执行')return this.items.filter(item => item.active).map(item => item.value)}
}
当多次访问 expensiveComputation
时,如果依赖没有变化,计算结果会从缓存中返回,而不会重新执行过滤和映射操作。而每次访问 expensiveMethod()
都会导致函数重新执行。
5.1.3 计算属性的 setter
计算属性默认只有 getter,但我们也可以提供 setter:
computed: {fullName: {// getterget() {return this.firstName + ' ' + this.lastName},// setterset(newValue) {const names = newValue.split(' ')this.firstName = names[0]this.lastName = names[names.length - 1]}}
}
现在当我们运行 this.fullName = 'Jane Smith'
时,setter 会被调用,this.firstName
和 this.lastName
会被相应地更新。
5.1.4 Composition API 中的计算属性
在 Vue 3 的 Composition API 中,计算属性通过 computed
函数创建:
import { ref, computed } from 'vue'export default {setup() {const firstName = ref('John')const lastName = ref('Doe')const fullName = computed(() => {return firstName.value + ' ' + lastName.value})// 带有 setter 的计算属性const fullNameWithSetter = computed({get: () => firstName.value + ' ' + lastName.value,set: (newValue) => {const names = newValue.split(' ')firstName.value = names[0]lastName.value = names[names.length - 1]}})return {firstName,lastName,fullName,fullNameWithSetter}}
}
5.2 侦听器
侦听器(watch)用于在数据变化时执行异步或开销较大的操作。
5.2.1 基本用法
export default {data() {return {question: '',answer: '问题包含问号(?)才能得到答案。'}},watch: {// 监听 question 变化question(newQuestion, oldQuestion) {if (newQuestion.includes('?')) {this.getAnswer()}}},methods: {async getAnswer() {this.answer = '思考中...'try {const response = await fetch('https://yesno.wtf/api')const data = await response.json()this.answer = data.answer} catch (error) {this.answer = '错误!无法获取答案。'}}}
}
5.2.2 侦听复杂数据
对于复杂数据类型(对象、数组),默认只检测引用变化,要检测内部变化需要使用深度侦听:
watch: {// 对象深度监听userProfile: {handler(newValue, oldValue) {console.log('用户资料变化了')},deep: true},// 监听对象的特定属性'userProfile.name'(newValue, oldValue) {console.log('用户名变化了')}
}
5.2.3 侦听器选项
侦听器支持以下选项:
- deep:深度监听对象或数组内部变化。
- immediate:侦听器创建后立即执行一次回调。
- flush(Vue 3):控制侦听器回调的时机(
'pre'
、'post'
或'sync'
)。
watch: {searchQuery: {handler(newQuery, oldQuery) {// 执行搜索this.fetchResults(newQuery)},// 立即执行一次immediate: true,// 在组件更新后调用flush: 'post' // Vue 3 特有}
}
5.2.4 $watch 方法
除了在组件选项中定义侦听器外,还可以使用实例方法 $watch
命令式地创建侦听器:
// 创建侦听器
const unwatch = this.$watch('question', function(newQuestion, oldQuestion) {// 执行操作if (newQuestion.includes('?')) {this.getAnswer()}
}, {immediate: true,deep: true
})// 停止侦听
unwatch() // 当不再需要时
5.2.5 Composition API 中的侦听器
在 Vue 3 的 Composition API 中,侦听器通过 watch
和 watchEffect
函数创建:
import { ref, watch, watchEffect } from 'vue'export default {setup() {const question = ref('')const answer = ref('问题包含问号(?)才能得到答案。')// 基本侦听watch(question, (newQuestion, oldQuestion) => {if (newQuestion.includes('?')) {getAnswer()}})// 侦听多个来源const firstName = ref('John')const lastName = ref('Doe')watch([firstName, lastName], ([newFirst, newLast], [oldFirst, oldLast]) => {console.log('名字变化了')})// 深度侦听const userProfile = ref({name: 'John',age: 30})watch(userProfile, (newProfile, oldProfile) => {console.log('用户资料变化了')}, { deep: true })// watchEffect 会自动跟踪所有依赖,并在依赖变化时重新执行watchEffect(() => {console.log(`问题是: ${question.value}`)console.log(`回答是: ${answer.value}`)})async function getAnswer() {answer.value = '思考中...'try {const response = await fetch('https://yesno.wtf/api')const data = await response.json()answer.value = data.answer} catch (error) {answer.value = '错误!无法获取答案。'}}return {question,answer}}
}
5.3 计算属性 vs 侦听器
虽然计算属性和侦听器在很多情况下可以互换使用,但它们有不同的用途:
- 计算属性:适用于根据其他属性派生值的场景,自动缓存结果。适合同步转换数据。
- 侦听器:适用于需要在数据变化时执行异步或开销较大操作的场景。适合需要副作用的操作。
选择合适工具的基本原则:
- 需要派生/组合值 → 计算属性
- 需要执行副作用 → 侦听器
6. Class 与 Style 绑定
6.1 绑定 HTML Class
6.1.1 对象语法
通过传递对象给 :class
来动态切换 class:
<div :class="{ active: isActive, 'text-danger': hasError }"></div>
上面的语法表示 active
这个 class 存在与否将取决于数据属性 isActive
的真假值,text-danger
同理。
也可以绑定一个返回对象的计算属性:
data() {return {isActive: true,error: null}
},
computed: {classObject() {return {
相关文章:
Vue.js 完全指南:从入门到精通
1. Vue.js 简介 1.1 什么是 Vue.js? Vue.js(通常简称为 Vue)是一个用于构建用户界面的渐进式 JavaScript 框架。所谓"渐进式",意味着 Vue 的设计是由浅入深的,你可以根据自己的需求选择使用它的一部分或全部功能。 Vue 最初由尤雨溪(Evan You)在 2014 年创…...
《TypeScript 7天速成系列》第3天:TypeScript高级类型通关秘籍:泛型+联合+交叉类型实战
TypeScript 的类型系统是其最强大的特性之一,但也是许多开发者感到困惑的地方。今天我们就来破解 TypeScript 中最难的类型系统,掌握泛型、联合类型和交叉类型的使用技巧。 一、泛型函数与泛型接口 泛型是 TypeScript 中创建可重用组件的重要工具&…...
Python----数据分析(足球运动员数据分析)
一、数据展示 1.1、数据 1.2、列名 字段名备注Name姓名Nationality国籍National_Position国家队位置National_Kit国家队号码Club所在俱乐部Club_Position所在俱乐部位置Club_Kit俱乐部号码Club_Joining加入俱乐部时间Contract_Expiry合同到期时间Rating评分Height身高Weight体…...
音视频 三 看书的笔记 MediaPlayer的C/S架构
MediaPlayer在运行时分为Client和Server两部分 Client层:位于Java层,用户通过调用Java层的API(如setDataSource)来操作MediaPlayer。 Server层:位于C层,负责实际的媒体处理工作。Server层通过Binder机…...
Elasticsearch:使用 AI SDK 和 Elastic 构建 AI 代理
作者:来自 Elastic Carly Richmond 你是否经常听到 AI 代理(AI agents)这个词,但不太确定它们是什么,或者如何在 TypeScript(或 JavaScript)中构建一个?跟我一起深入了解 AI 代理的概…...
echarts添加坐标轴点击事件
echarts添加坐标轴点击事件 chart.on(click, (params) > {if(params.componentType yAxis && this.type ! 1){console.log(params);// 检查是否点击了系列数据console.log(你点击了 ${params.name} 的数据点,值为 ${params.value}); this.$bus.$emi…...
如何在linux中部署dns服务 主备dns (详细全过程)
环境centos 7.9 主DNS:192.168.60.131 备DNS:192.168.60.134 我以 chenxingyu0.com 指向 192.168.60.200为例 首先是主dns #!/bin/bash# 检查是否为 root 用户 if [ "$(id -u)" ! "0" ]; thenecho "请使用…...
GitLab 中文版17.10正式发布,27项重点功能解读【二】
GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料: 极狐GitLab 官网极狐…...
matplotlib——南丁格尔玫瑰
南丁格尔玫瑰图(Nightingale Rose Chart),是一种特殊形式的柱状图,它以南丁格尔(Florence Nightingale)命名,她在1858年首次使用这种图表来展示战争期间士兵死亡原因的数据。 它将数据绘制在极坐…...
WPF 与 C# 融合开发:从基础到高级应用(一)
WPF 与 C# 融合开发:从基础到高级应用 一、C# 语言基础回顾 1.1 C# 语言概述 C# 是微软开发的一种现代、面向对象的编程语言,它融合了 C、C 和 Java 等语言的优点,具有简洁、安全、高效等特点。C# 广泛应用于 Windows 平台的应用开发&…...
ref和reactive区别
在 Vue 3 中,ref 和 reactive 是两种创建响应式数据的主要 API,但它们的适用场景和使用方式有所不同。以下是它们的核心区别和示例: 一、核心区别 特性refreactive适用数据类型所有类型(基本类型、对象、数组)仅对象或…...
精选10个好用的WordPress免费主题
10个好用的WordPress免费主题 1. Astra Astra 是全球最受欢迎的 WordPress 主题。它功能丰富,易于使用,SEO友好,是第一个安装量突破100万的非默认主题,并获得了5000多个五星好评。 它完美集成了Elementor、Beaver,古…...
DerpNStink: 1靶场渗透
DerpNStink: 1 来自 <DerpNStink: 1 ~ VulnHub> 1,将两台虚拟机网络连接都改为NAT模式 2,攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.182,靶场IP192.168.23.213 3,对靶机进行端…...
apache安装脚本使用shell建立
注意防火墙,yum,网络连接等 以下是具体的apache安装脚本 #!/bin/bash # Set Apache version to install ## author: yuan # 检查外网连接 echo "检查外网连接..." ping www.baidu.com -c 3 > /dev/null 2>&1 if [ $? -eq 0 ]; …...
Azure SDK 使用指南
Azure SDK(软件开发工具包)是一组由微软提供的工具和库,旨在帮助开发者以多种编程语言(如 .NET、Java、Python、JavaScript 等)与 Azure 服务进行交互。 通过使用 Azure SDK,开发者可以更高效地构建、部…...
DeepSeek-V3-0324 版本升级概要
DeepSeek-V3-0324 魔搭社区汇聚各领域最先进的机器学习模型,提供模型探索体验、推理、训练、部署和应用的一站式服务。https://modelscope.cn/models/deepseek-ai/DeepSeek-V3-0324 发布背景与改进 根DeepSeek-V3-0324 展示了以下关键改进: 推理性能提…...
leetcode 150. 逆波兰表达式求值
150. 逆波兰表达式求值 - 力扣(LeetCode) class Solution:def evalRPN(self, tokens: List[str]) -> int:stack[]for item in tokens:if item not in ( ,-,* , / ):stack.append(item)else:preint(stack.pop())pre_beforeint(stack.pop())sign itemi…...
LangChain4j与DashScope深度集成实战:一站式开发指南
本篇文章会通篇详细的讲清楚LangChain4j与DashScope集成的各个方面,从Springboot的集成到Ai对话、会话记忆、RAG、FunctionCalling、互联网搜索、结构化的输出、多模态等都给出相应的说明,希望通过这篇文章对于LLM不了解的同仁一样可以扩展出自己的AI应用…...
逼用户升级Win11,微软开始给Win10限速
随着Windows10的支持时间越来越短,微软也加大了对Win10用户的驱赶力度。 最近,微软官宣了将要在今年6月份降低OneNote for Windows 10的同步速度。软件也将和Windows10在今年的10月14日一同停止支持和维护。 这将影响实时协作和多设备访问。 对OneNote…...
工作流引擎Flowable介绍及SpringBoot整合使用实例
Flowable简介 Flowable 是一个轻量级的业务流程管理(BPM)和工作流引擎,基于 Activiti 项目发展而来,专注于提供高性能、可扩展的工作流解决方案。它主要用于企业级应用中的流程自动化、任务管理和审批流等场景。 Flowable 的核心…...
推荐一个可以自定义github主页的网站
一、简介 Profile Readme Generator 是一个开源工具,可以帮助你快速创建个性化的 GitHub 个人简介(README)。它支持自定义内容和样式,让你的 GitHub 个人主页更加美观和专业。 二、使用步骤 (一)访问网站…...
【R语言可视化】相关系数热图
目录 热图无显著性 结果展示01: 热图显著性 结果展示02: ggplot2绘制三角热图 结果展示03: corrplot绘制三角热图 结果展示04: 热图无显著性 # 示例数据 data(mtcars) df <- mtcars# 计算相关矩阵 cor_matrix <- round(cor(df…...
【区块链 + 文化版权】文创链 | FISCO BCOS 应用案例
“文创链”是由四川省区块链行业协会、成都音像出版社有限公司共同发起, 由成都九天星空科技有限公司等联合打造的数字文创领域联盟链。平台采用FISCO BCOS 开源底层框架, 为数字文创产业构建一个高效、透明、可信的版权管理与交易平台。 平台专注于数字…...
# 使用自定义Shell脚本hello快速配置Linux用户账户
使用自定义Shell脚本快速配置Linux用户账户 在学校实验室管理Linux服务器,或者公司小团队管理服务器时,大家需要一个能隔离自己服务,但是自己又需要对服务器的完整权限的情形。创建和配置用户账户是一项常见但繁琐的任务。特别是当你需要频繁…...
PyTorch中的Tensor
PyTorch中的Tensor 是核心数据结构,类似于 NumPy 的多维数组,但具备 GPU 加速和自动求导等深度学习特性。 一、基本概念 核心数据结构 Tensor 是存储和操作数据的基础单元,支持标量(0D)、向量(1D&am…...
16-CSS3新增选择器
知识目标 掌握属性选择器的使用掌握关系选择器的使用掌握结构化伪类选择器的使用掌握伪元素选择器的使用 如何减少文档内class属性和id属性的定义,使文档变得更加简洁? 可以通过属性选择器、关系选择器、结构化伪类选择器、伪元素选择器。 1. 属性选择…...
关于笔记本电脑突然没有wifi图标解决方案
笔记本电脑突然没有wifi图标解决方案,设置里也看不见wifi,电脑突然就连不网络了 解决方案: 我的电脑——>管理——>服务和应用程序——>服务——>找到WLAN AutoConfig——>点击启动就好了...
Pytorch学习笔记(七)Learn the Basics - Optimizing Model Parameters
这篇博客瞄准的是 pytorch 官方教程中 Learn the Basics 章节的 Optimizing Model Parameters 部分。 官网链接:https://pytorch.org/tutorials/beginner/basics/optimization_tutorial.html 完整网盘链接: https://pan.baidu.com/s/1L9PVZ-KRDGVER-AJnXOvlQ?pwd…...
数据可视化TensorboardX和tensorBoard安装及使用
tensorBoard 和TensorboardX 安装及使用指南 tensorBoard 和 TensorBoardX 是用于可视化机器学习实验和模型训练过程的工具。TensorBoard 是 TensorFlow 官方提供的可视化工具,而 TensorBoardX 是其社区驱动的替代品,支持 PyTorch 等其他框架。以下是它…...
工业4G路由器赋能智慧停车场高效管理
工业4G路由器作为智慧停车场管理系统通信核心,将停车场内的各个子系统连接起来,包括车牌识别系统、道闸控制系统、车位检测系统、收费系统以及监控系统等。通过4G网络,将这些系统采集到的数据传输到云端服务器或管理中心,实现信息…...
深度学习1—Python基础
深度学习1—python基础 你的第一个程序 print(hello world and hello deep learning!)基本数据结构 空值 (None):在 Python 中,None 是一个特殊的对象,用于表示空值或缺失的值。它不同于数字 0,因为 0 是一个有意义的数字&#…...
数据结构十三、set map
一、set 1、size / empty size:返回set中实际元素的个数 empty:判断set是否为空 2、begin / end 这是两个迭代器,因此可以使用范围for来遍历整个红黑树。其中,遍历是按照中序遍历的顺序,因此是一个有序序列。 3、in…...
【大模型基础_毛玉仁】3.5 Prompt相关应用
目录 3.5 相关应用3.5.1 基于大语言模型的Agent3.5.2 数据合成3.5.3 Text-to-SQL3.5.4 GPTs 3.5 相关应用 Prompt工程应用广泛,能提升大语言模型处理基础及复杂任务的能力,在构建Agent、数据合成、Text-to-SQL转换和设计个性化GPTs等方面不可或缺。 . …...
自动驾驶VLA模型技术解析与模型设计
1.前言 2025年被称为“VLA上车元年”,以视觉语言动作模型(Vision-Language-Action Model, VLA)为核心的技术范式正在重塑智能驾驶行业。VLA不仅融合了视觉语言模型(VLM)的感知能力和端到端模型的决策能力,…...
【AI】Orin NX+ubuntu22.04上移植YoloV11,并使用DeepStream测试成功
【AI】郭老二博文之:AI学习目录汇总 1、烧写系统 新到的开发板,已经烧写好Ubuntu系统,版本为22.04。 如果没有升级到Ubuntu22.04,可以在电脑Ubuntu系统中使用SDKManager来烧写Ubuntu系统,网络情况好的话,也可以直接将CUDA、cuDNN、TensorRT、Deepstream等也安装上。 2…...
vscode 通过Remote-ssh远程连接服务器报错 could not establish connection to ubuntu
vscode 通过Remote-ssh插件远程连接服务器报错 could not establish connection to ubuntu,并且出现下面的错误打印: [21:00:57.307] Log Level: 2 [21:00:57.350] SSH Resolver called for "ssh-remoteubuntu", attempt 1 [21:00:57.359] r…...
ESP32S3 WIFI 实现TCP服务器和静态IP
一、 TCP服务器代码 代码由station_example_main的官方例程修改 /* WiFi station ExampleThis example code is in the Public Domain (or CC0 licensed, at your option.)Unless required by applicable law or agreed to in writing, thissoftware is distributed on an &q…...
第三课:Stable Diffusion图生图入门及应用
文章目录 Part01 图生图原理Part02 图生图基本流程Part03 随机种子作用解析Part04 图生图的拓展应用 Part01 图生图原理 当提示词不能足够表达用户需求的时候,加入图片能让AI更好的理解你的想法图片上的像素信息会在加噪和去噪的过程中,作为一种特征反映…...
蓝桥与力扣刷题(蓝桥 蓝桥骑士)
题目:小明是蓝桥王国的骑士,他喜欢不断突破自我。 这天蓝桥国王给他安排了 N 个对手,他们的战力值分别为 a1,a2,...,an,且按顺序阻挡在小明的前方。对于这些对手小明可以选择挑战,也可以选择避战。 身为高傲的骑士&a…...
Photoshop怎样保存为ico格式
1. 打开图像 开启 Photoshop 软件,选择 “文件” 菜单,点击 “打开” 选项,然后找到你想要保存为 ICO 格式的图像文件并打开。 2. 调整图像大小(可选) ICO 图标通常有特定尺寸要求,你可以根据需求调整图像…...
Ubuntu xinference部署本地模型bge-large-zh-v1.5、bge-reranker-v2-m3
bge-large-zh-v1.5 下载模型到指定路径: modelscope download --model BAAI/bge-large-zh-v1.5 --local_dir ./bge-large-zh-v1.5自定义 embedding 模型,custom-bge-large-zh-v1.5.json: {"model_name": "custom-bge-large…...
python笔记之判断月份有多少天
1、通过随机数作为目标月份 import random month random.randint(1,12)2、判断对应的年份是闰年还是平年 因为2月这个特殊月份,闰年有29天,而平年是28天,所以需要判断对应的年份属于闰年还是平年,代码如下 # 判断年份是闰年还…...
Kotlin泛型: 协变|逆变|不变
引言 无论java 通配符上限还是下限,都多少存在缺陷,要么存不安全,要么取不安全。而kotlin就解决这个问题。让out 纯输出, 让in纯输入。 java这块知识: java泛型的协变、逆变和不变-CSDN博客 协变 生产者out T 协变…...
高斯数据库的空分区的查看和清理
在 高斯数据库(GaussDB) 中,分区表是一种常见的表设计方式,用于优化大数据的查询性能。 一、空分区的影响: 存储空间占用 元数据开销:即使分区中没有数据,数据库仍然需要维护分区的元数据&…...
word使用自带的公式
文章目录 Word公式中word公式快捷键:word2016公式框输入多行word 公式加入空格:word公式如何输入矩阵:公式图片转为Latex语法word 能直接输入 latex 公式么word公式中有的是斜体有的不是 word文本中将文字转为上标的快捷键 Tips几个好用的网站࿱…...
Linux系统-ls命令
一、ls命令的定义 Linux ls命令(英文全拼:list directory contents)用于显示指定工作目录下之内容(列出目前工作目录所含的文件及子目录)。 二、ls命令的语法 ls [选项] [目录或文件名] ls [-alrtAFR] [name...] 三、参数[选项…...
数据结构:利用递推式计算next表
next 表是 KMP 算法的核心内容,下面介绍一种计算 next 表的方法:利用递推式计算 如图 6.3.1 所示,在某一趟匹配中,当对比到最后一个字符的时候,发现匹配失败(s[i] ≠ t[j])。根据 BF 算法&…...
Git操作
1 git init 项目初始化(init)成仓库 2、git add 管理文件 3、git commit -m <message> 告诉Git,把文件提交到仓库 4、git status 查看当前管理文件的状态,命令 5、git log 查看提交(commit)的…...
什么是快重传
原理: 在TCP连接中,接受方会对收到的数据包发送确认(ACK)。如果接受方收到一个乱序的数据包(即期望的下一个数据包尚未到达),它会重复发送对上一个已成功接受的数据包的确认。 当发送方连续收…...
计算机网络——物理层设备
目录 编辑 中继器 集线器(Hub) 集线器,中继器的一些特性 集线器和中继器不能“无限串联” 集线器连接的网络,物理上是星型拓扑,逻辑上是总线型拓扑 集线器连接的各网段会“共享带宽” 中继器 如果我们想要网络…...