【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) # 输…...

FreeBSD14.1 rm命令的疑惑
在/tmp目录发现有很多目录和文件,准备把它们都删除,结果发现都删不掉 这些文件目录如图: /tmp % ls -la total 9143 drwxrwxrwt 421 root wheel 486 10月 8 11:58 . drwxr-xr-x 23 root wheel 32 10月 8 10:06 .. drwx----…...

LSTM模型变种
LSTM模型变种 一、GRU 1.什么是GRU GRU(Gated Recurrent Unit)是一种循环神经网络(RNN)的变体,它被设计用来解决传统RNN在处理长序列时可能遇到的梯度消失或梯度爆炸问题。GRU通过引入门控机制来控制信息的流动&…...

基于comsol模拟微穿孔板和卷曲通道的混合吸声器低频吸声
研究背景: 具有深亚波长厚度(5cm)的吸收器对低频声音(<500Hz)的衰减在噪声控制工程中引起了极大的兴趣。然而,由于低频声音的强穿透性和普通材料的弱固有分散性,这是一项具有挑战性的任务。…...

Ajax ( 是什么、URL、axios、HTTP、快速收集表单 )Day01
AJAX 一、Ajax是什么1.1名词解释1.1.1 服务器1.1.2 同步与异步1. 同步(Synchronous)2. 异步(Asynchronous)3. 异步 vs 同步 场景4. 异步在 Web 开发中的常见应用: 1.2 URL 统一资源定位符1.2.1 URL - 查询参数1.2.2 ax…...

【Java 循环控制实例详解【While do... while】】
Java 循环控制详解【While & do… while】 在 Java 中,循环控制是程序设计中非常重要的部分,主要包括 while 循环和 do...while 循环。本文将详细介绍这两种循环的基本语法、执行流程及相关示例。 1. while 循环控制 基本语法 循环变量初始化; wh…...

10.2 Linux_进程_进程相关函数
创建子进程 函数声明如下: pid_t fork(void); 返回值:失败返回-1,成功返回两次,子进程获得0(系统分配),父进程获得子进程的pid 注意:fork创建子进程,实际上就是将父进程复制一遍作为子进程&…...

栈与队列面试题(Java数据结构)
前言: 这里举两个典型的例子,实际上该类型的面试题是不确定的! 用栈实现队列: 232. 用栈实现队列 - 力扣(LeetCode) 方法一:双栈 思路 将一个栈当作输入栈,用于压入 push 传入的数…...

手撕数据结构 —— 顺序表(C语言讲解)
目录 1.顺序表简介 什么是顺序表 顺序表的分类 2.顺序表的实现 SeqList.h中接口总览 具体实现 顺序表的定义 顺序表的初始化 顺序表的销毁 打印顺序表 编辑 检查顺序表的容量 尾插 尾删 编辑 头插 头删 查找 在pos位置插入元素 删除pos位置的值 …...

女友学习前端第二天-笔记
2024/10/8笔记 表格 table 表格 tr 行 td 单元格内容 th 表头 第一行相当于h1 alignleft /center /right 对齐方式 应在table边上 比如<table alignleft> border 代表边框 也应在table边上 比如<table alignleft border"1"> cellpadding 单元外框与…...

电脑手机下载小米xiaomi redmi刷机包太慢 解决办法
文章目录 修改前下载速度修改后下载速度修改方法(修改host) 修改前下载速度 一开始笔者以为是迅雷没开会员的问题,在淘宝上买了一个临时会员后下载速度依然最高才100KB/s 修改后下载速度 修改方法(修改host) host文…...