【Vue】Vue 快速教程
Vue tutorial
参考:教程 | Vue.js (vuejs.org)
该教程需要前置知识:HTML, CSS, JavaScript
学习前置知识,你可以去 MDN
Vue framework 是一个 JavaScript framework,以下简称 Vue,下面是它的特点
- 声明式渲染(Declarative Rendering):即声明 JavaScript 对象,改变对象状态来更改 HTML,这个过程由 Vue 完成
- 响应式(Reactivity):JavaScript 的对象状态改变会马上反映到 DOM(不知道 DOM 的去查 MDN 文档)
Declarative Rendering and Reactivity
Vue 实现了:
JavaScript Obejct <-> Vue <-> DOM
但是 Vue 显然是利用 JavaScript 机制,那就是 Proxy,Proxy 可以实现
JavaScript Object <-> Proxy <-> DOM
所以 Vue 把 Proxy 改造后封装成了 reactive(),调用这个 API 会返回一个特殊的对象,称之为响应式对象(reactive object)。
reactive()
import { reactive } from 'vue'const counter = reactive({count: 0
})console.log(counter.count) // 0
counter.count++
但是 reactive() 参数只能是对象(还有数组和内置类型),Vue 又把 reactive() 改造封装成了 ref(),它也会返回一个响应式对象,并且带一个 .value property,只不过它的参数可以填写值。
ref()
import { ref } from 'vue'const message = ref('Hello World!')console.log(message.value) // "Hello World!"
message.value = 'Changed'
以上给 ref() 或 reactive() 填写参数得到响应式对象的过程,就被成为数据绑定(data binding)。
Template syntax
在这里复习一下 HTML element 和 attribute 概念
Anatomy of an HTML element
这是 HTML element
这是 HTML attribute
在此之中,
Class为 attribute name,editor-note为 attribute value
Vue 自己创造了一套 template language。最基本的数据绑定是文本插值(Text Interpolation),它可以改变 element 的 content,像这样
<span>{{ message }}</span>
这种语法被成为 “Mustache”语法 (即双大括号)。再结合上节讲到的 reactive object,我们可以这样写
import { ref } from 'vue'const message = ref('Hello World!')
效果是这样的

可能你会有些疑问,为什么不是写 {{message.value}},因为它是 top-level property,会自动解包(unwrapping)
const object = { id: ref(1) }
比如这个里面,id 就不是 top-level property,如果你这么写
{{ object.id + 1 }}
渲染的结果将是 [object Object]1

你需要手动解包,才会渲染出 2
{{ object.id.value + 1 }}

Directive
v-xxx 就是一种 attribute,在它的 template language 中被称为 directive
v-bind
Attribute bind
在 Vue 中,Mustache 语法只能用于文本插值来改变 element content,没法儿操作 element attribute。而且 element attribute 是静态的,为了给 element attribute 绑定一个动态值,需要使用 Vue 的 v-bind directive
<div v-bind:id="dynamicId"></div>
冒号后面的 id 被称为 directive 的参数(argument),dynamicId 则为参数值,它会和响应式对象的 property 同步。它可以简写为
<div :id="dynamicId"></div>
例子:
<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>
v-on
Event Listen
可以通过 v-on 来监听 DOM event
<button v-on:click="increment">{{ count }}</button>
简写
<button @click="increment">{{ count }}</button>
点击 button 会触发 increment() 这个函数。
例子:
<script setup>
import { ref } from 'vue'const count = ref(0)function increment() {count.value++
}
</script><template><button @click="increment">count is: {{ count }}</button>
</template>
v-model
Form bind
同时使用 v-bind 和 v-on 对表单(form)进行绑定和监听
<script setup>
import { ref } from 'vue'const text = ref('')function onInput(e) {text.value = e.target.value
}
</script><template><input :value="text" @input="onInput" placeholder="Type here"><p>{{ text }}</p>
</template>
啊,这么写实在太麻烦,所以 vue 提供了 v-model。当然,最好看一下它支持哪些 element。
<script setup>
import { ref } from 'vue'const text = ref('')
</script><template><input v-model="text" placeholder="Type here"><p>{{ text }}</p>
</template>
v-if and v-else
Conditional Rendering
v-if 和 v-else 可以根据条件来决定 element 是否在 DOM 中。
例子:
<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>
改变 awesome 的值来显示 “Vue is awesome!” 和 “Oh no 😢”。
v-for
当你想写一个列表时,一个个写列表的 element 实在太累了,如果有 1000 个那不就完蛋了,所以 v-for 可以通过循环,直接渲染出列表(当然,你得给相应的数据)
<script setup>
import { ref } from 'vue'// 给每个 todo 对象一个唯一的 id
let id = 0const 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()
template 里面可以写这种计算表达式
<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
const author = reactive({name: 'John Doe',books: ['Vue 2 - Advanced Guide','Vue 3 - Basic Guide','Vue 4 - The Mystery']
})
但是这种计算写在 template 里是真的不好理解,个人感觉在结构上 View 里不能有逻辑,所以尽量不要这么写。
所以我们可以用 computed(),这样
<script setup>
import { reactive, computed } from 'vue'const author = reactive({name: 'John Doe',books: ['Vue 2 - Advanced Guide','Vue 3 - Basic Guide','Vue 4 - The Mystery']
})// 一个计算属性 ref
const publishedBooksMessage = computed(() => {return author.books.length > 0 ? 'Yes' : 'No'
})
</script><template><p>Has published books:</p><span>{{ publishedBooksMessage }}</span>
</template>
它和 method() 最大区别在于,它是只有在响应式对象更新时才会重新被调用和计算,否则就会直接返回缓存值,即 books 不变,重渲染(比如页面刷新,更新)时 computed() 不会被调用,而 method() 则会。插嘴一句 method(),重渲染时总会被调用。
Lifecycle and Template Refs
手动用 JavaScript 操作 DOM 是一件苦差事,所以我们用 vue 来帮忙,但是有时我们不得不操作 DOM,这个时候我们就得使用模板引用(template ref)
这个时候就要使用 ref attribute
<p ref="pElementRef">hello</p>
如果要访问这个 ref,我们需要声明(declare)ref 并初始化
const pElementRef = ref(null)
注意我们使用给 ref 的 argument 为 null,这是因为<script setup> 执行时,DOM 还没有初始化,template ref 只能在挂在(mount)后访问,所以我们可以使用生命周期钩子(lifecycle hook)比如 onMounted(),关于 lifecycle 请看生命周期图示
例子:
<script setup>
import { ref, onMounted } from 'vue'const pElementRef = ref(null)onMounted(() => {pElementRef.value.textContent = 'mounted!'
})
</script><template><p ref="pElementRef">hello</p>
</template>
watch()
watch() 可以监察一个 ref,并触发一个 callback function,比如下面的例子就是监察 todoId,触发 fetchData
<script setup>
import { ref, watch } from 'vue'const todoId = ref(1)
const todoData = ref(null)async function fetchData() {todoData.value = nullconst 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++" :disabled="!todoData">Fetch next todo</button><p v-if="!todoData">Loading...</p><pre v-else>{{ todoData }}</pre>
</template>
Component
Vue application 常常是多个 component 嵌套创建,所以就有 parent component 包含 child component
如果要使用 child component,就需要导入它
import ChildComp from './ChildComp.vue'
使用 child component
<ChildComp />
例子:
<!--App.vue--><script setup>
import ChildComp from './ChildComp.vue'
</script><template><ChildComp />
</template>
Props
child component 可以通过 props 从 parent component 获取动态数据
<!--ChildComp.vue-->
<script setup>
const props = defineProps({msg: String
})
</script>
注意,
defineProps()是一个 runtime marcro,不需要导入。
这样,msg 就可以在 child component 的 <template> 中使用
<template><h2>{{ msg || 'No props passed yet' }}</h2>
</template>
而 parent component 则可以用 v-bind 传递数据
<!--App.vue-->
<ChildComp :msg="greeting" />
例子:
<!--App.vue-->
<script setup>
import { ref } from 'vue'
import ChildComp from './ChildComp.vue'const greeting = ref('Hello from parent')
</script><template><ChildComp :msg="greeting" />
</template>
<!--ChildComp.vue-->
<script setup>
const props = defineProps({msg: String
})
</script><template><h2>{{ msg || 'No props passed yet' }}</h2>
</template>
child component 中采用的 “runtime declaration”,还有一种是如果你用 typescript,需要采用 “type-based declaration”,具体看官方文档。
Emits
child component 可以向 parent component 传 event,emit() 中,第一个 argument 是 event name,其他的会传给 event listener。
parent component 可以通过 v-on 监听 child-emitted event,并且可以将额外的 argument 赋值给 local state
<!--App.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>
<!--ChildComp.vue-->
<script setup>
const emit = defineEmits(['response'])emit('response', 'hello from child')
</script><template><h2>Child component</h2>
</template>
Solots
除了 props,parent component 可以将 template 片段传给 child component,而在 child component,则可以使用 <slot> 来显示片段的内容。
<!--App.vue-->
<script setup>
import { ref } from 'vue'
import ChildComp from './ChildComp.vue'const msg = ref('from parent')
</script><template><ChildComp>Message: {{ msg }}</ChildComp>
</template>
<template><slot>Fallback content</slot>
</template>
以上 parent component 中,<ChildComp> 的内容会传给 child component 中的 <slot>,最后渲染在 parent component 上。

Essential
Create application
application instance and root component
Vue application 通常是通过 createApp 来创建一个 application instance
而 createApp 的参数则被称为 root component,而且其他 component 则作为 root 的 child component,所以 vue application 是由 root component 和 child component 组成的。
一般这种创建代码都在 <project-name>/src/main.js
<!--main.js-->
import { createApp } from 'vue'
// 导入一个单组件
import App from './App.vue'
// 将这个单组件作为根组件
const app = createApp(App)
一个 Todo application 的例子
App (root component)
├─ TodoList
│ └─ TodoItem
│ ├─ TodoDeleteButton
│ └─ TodoEditButton
└─ TodoFooter├─ TodoClearButton└─ TodoStatistics
mount application
application instance 必须调用 mount() 才能渲染,而必须的 argument 则为 DOM 的 element 或者 CSS selector
在 vue project 中一般在 <project-name>/index.html
<div id="app"></div>
注意
mount()应该始终在应用配置完成后调用,简单点儿说就是最后调用。
Applicaiton configuration
application instance 会提供一个 config object,这样就可以配置 vue app,比如 app-level option,capture error
app.config.errorHandler = (err) => {/* 处理错误 */
}
或者 component registration
比如 global registration
app.component('TodoDeleteButton', TodoDeleteButton)
其他细节清参考 vue 文档。
Component registration
如果要使用 component,则必须是 registered
Global registration
使用 .component() method:
import { createApp } from 'vue'const app = createApp({})app.component(// the registered name'MyComponent',// the implementation{/* ... */}
)
如果使用 SFC,则
import MyComponent from './App.vue'app.component('MyComponent', MyComponent)
Local registration
使用 component option
import ComponentA from './ComponentA.js'export default {components: {ComponentA},setup() {// ...}
}
使用 SFC
<script setup>
import ComponentA from './ComponentA.vue'
</script><template><ComponentA />
</template>
Toolchain
当你创建一个 vue project 时,手动新建目录和文件是很麻烦的事情,所有我们有项目脚手架(Project Scaffolding)来自动创建 project 基本的目录和文件。
Vite
尤雨溪开发的 build tool,支持 SFC,通过 Vite 创建项目:
npm create vue@latest
Vue CLI
基于 webpack 的 build tool,但现在是维护状态,建议使用 Vite。
相关文章:
【Vue】Vue 快速教程
Vue tutorial 参考:教程 | Vue.js (vuejs.org) 该教程需要前置知识:HTML, CSS, JavaScript 学习前置知识,你可以去 MDN Vue framework 是一个 JavaScript framework,以下简称 Vue,下面是它的特点 声明式渲染ÿ…...
SQLite数据库介绍
文章目录 SQLite常用接口 使用示例测试 SQLite SQLite是一个本地化的数据库,不需要客户端服务端什么的配置,主打就是轻量化方便化 他也不是一个独立的进程,而是可以根据应用程序的需求,可以进行静态或者动态的连接 而且他是直接存储在磁盘文件的,提供了简单易用的API接口 需…...
点击label 按钮起作用
要使点击 标签时能够触发与之关联的表单控件(如输入框、复选框或单选按钮)的作用,你需要正确地设置 标签的 for 属性,并确保该属性值与表单控件的 id 属性值相匹配。这样,当用户点击 标签时,与之关联的表…...
JPA、Hibernate、MyBatis三种ORM框架怎么选择
JPA(Java Persistence API)、Hibernate和MyBatis都是Java开发中常用的ORM(Object-Relational Mapping,对象关系映射)框架,它们提供了不同的方式来处理数据库交互。在选择这些框架时,需要考虑项目…...
【C++】map详解
📢博客主页:https://blog.csdn.net/2301_779549673 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📢本文由 JohnKi 原创,首发于 CSDN🙉 📢未来很长&#…...
力扣206.反转链表
题目链接:206. 反转链表 - 力扣(LeetCode) 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5]输出:[5,4,3,2,1] 示例 2: …...
如何查看服务器的带宽linux服务器
speedtest-cli ubuntu # 安装speedtest-cli sudo apt install speedtest-cli # 执行测试 speedtest --secure # 在其他博客可以看到使用以下的命令,但是我试了没用 speedtest-cli参考: https://ubuntu-mate.community/t/speedtest-cli-error/25722/2…...
云原生化 - 工具镜像(完整版)
在微服务和云原生环境中,容器化的目标之一是尽可能保持镜像小型化以提高启动速度和减少安全风险。然而,在实际操作中,有时候需要临时引入一些工具来进行调试、监控或问题排查。Kubernetes提供了临时容器(ephemeral containers)的功能,允许在不改变原始容器镜像的情况下,…...
leetcode68:文本左右对齐
给定一个单词数组 words 和一个长度 maxWidth ,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。 你应该使用 “贪心算法” 来放置给定的单词;也就是说,尽可能多地往每行中放置单词。必要时可…...
Linux驱动学习——内核编译
1、从官网下载适合板子的Linux内核版本 选择什么版本的内核需要根据所使用的硬件平台而定,最好使用硬件厂商推荐使用的版本 https://www.kernel.org/pub/linux/kernel/ 2、将压缩包复制到Ubuntu内进行解压 sudo tar -xvf linux-2.6.32.2-mini2440-20150709.tgz 然…...
MES系统:制造业的智能大脑
引言 在当今快速变化的制造业环境中,企业面临着激烈的市场竞争和不断变化的客户需求。为了保持竞争力,制造企业必须提高生产效率、降低成本、缩短产品上市时间,并确保产品质量。MES(制造执行系统)作为一种先进的生产管…...
忘记 MySQL 密码怎么办:破解 root 账户密码
忘记 MySQL 密码怎么办:破解 root 账户密码 目录 忘记 MySQL 密码怎么办:破解 root 账户密码1、修改 MySQL 配置文件2、不使用密码登录 MySQL3、重置 root 用户密码4、修改 MySQL 配置文件并重启 MySQL 服务5、使用新密码登录 MySQL 如果忘记密码导致无法…...
【LeetCode每日一题】——17.电话号码的字母组合
文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 回溯 二【题目难度】 中等 三【题目编号】 17.电话号码的字母组合 四【题目描述】 给定一个…...
Git管理远程仓库
添加远程仓库 要新增远程,请在终端上存储存储库的目录中使用 git remote add 命令。 git remote add 命令采用两个参数: 远程名称(例如 origin)远程 URL(例如 https://github.com/OWNER/REPOSITORY.git)…...
在 /var/cache/apt/archives/ 上没有足够的可用空间的解决方法
问题 apt-get upgrade 更新软件包时,提示没有足够的空间。 分析 一般来说,除非下载的文件过于大,整个服务器的内存都不够用,否则可以改变默认的下载路径进行下载。 解决方法 找一个空间足够的目录,新建一个单独的…...
FastAdmin Apache下设置伪静态
FastAdmin Apache下设置伪静态 一、引言 FastAdmin 是一个基于ThinkPHP和Bootstrap框架开发的快速后台开发框架,它以其简洁、高效、易于扩展的特点,广受开发者的喜爱。在部署FastAdmin项目时,为了提高访问速度和用户体验,我们通…...
MPI程序实例:自适应数值积分(主从模式)
目录 一、主从模式的自适应梯形公式 二、串行程序 三、基于非阻塞通信的并行程序 四、基于散发/收集通信的并行程序 上一节我们介绍了采用梯形公式结合自适应局部区间加密,计算一个函数在给定区间上的定积分达到指定精度。 MPI程序实例:自适应数值积分-CSDN博客…...
蓝桥杯—STM32G431RBT6(IIC通信--EEPROM(AT24C02)存储器进行通信)
一、什么是IIC?24C02存储器有什么用? IIC (IIC 是半双工通信总线。半双工意味着数据在某一时刻只能沿一个方向传输,即发送数据的时候不能接收数据,接收数据的时候不能发送数据)即集成电路总线(…...
【重学 MySQL】六十二、非空约束的使用
【重学 MySQL】六十二、非空约束的使用 定义目的关键字特点作用创建非空约束删除非空约束注意事项 在MySQL中,非空约束(NOT NULL Constraint)是一种用于确保表中某列不允许为空值的数据库约束。 定义 非空约束(NOT NULL Constra…...
Python获取json返回的字符串获取方法大全
1、使用 json.loads() 解析JSON字符串 import jsonjson_string {"name": "Alice", "age": 25, "city": "Beijing"} data json.loads(json_string)# 获取字符串值 name data[name] print("Name:", name) # 输…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7
在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤: 第一步: 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为: // 改为 v…...
Vue 3 + WebSocket 实战:公司通知实时推送功能详解
📢 Vue 3 WebSocket 实战:公司通知实时推送功能详解 📌 收藏 点赞 关注,项目中要用到推送功能时就不怕找不到了! 实时通知是企业系统中常见的功能,比如:管理员发布通知后,所有用户…...
数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)
目录 🔍 若用递归计算每一项,会发生什么? Horners Rule(霍纳法则) 第一步:我们从最原始的泰勒公式出发 第二步:从形式上重新观察展开式 🌟 第三步:引出霍纳法则&…...


