什么是Vue
Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,高效地开发用户界面。
Vue 的两个核心功能:
- 声明式渲染:Vue 基于标准 HTML 拓展了一套模板语法,使得我们可以声明式地描述最终输出的 HTML 和 JavaScript 状态之间的关系。
- 响应性:Vue 会自动跟踪 JavaScript 状态并在其发生变化时响应式地更新 DOM。
Vue 是渐进式框架,可以自底向上逐层的应用。
基础语法
模板语法
插值语法
{{xxxx}}
,其中xxxx会作为js表达式运行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue_test01</title>
</head>
<body>
<!-- vue 操作此dom 此元素里面的后代元素全部可以被vue操作控制 -->
<div id="root">
<!-- 插值表达式语法:{{js表达式}} 表达式中的变量来自于data函数的返回值 -->
<h1>你好{{name}}</h1>
<h1>1+1={{1+20}}</h1>
</div>
<!-- CDN引入方式 -->
<!-- <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> -->
<!-- 引入本地vue.js文件 -->
<script src="./vue.js"></script>
<script>
// 初始化 vue 对象
const app = Vue.createApp({
data(){ // 这里存放页面需要引用的数据,通过return返回对象
// data这里定义数据
return {
name:'AiLynn',
}
}
})
app.mount('#root') // 挂载到id=root的元素上,开始操控此元素
</script>
</body>
</html>
指令语法
v-
开头
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue_test01</title>
</head>
<body>
<!-- vue 操作此dom 此元素里面的后代元素全部可以被vue操作控制 -->
<div id="root">
<!-- 插值表达式语法:{{js表达式}} 表达式中的变量来自于data函数的返回值 -->
<h1>你好{{name}}</h1>
<h1>1+1={{1+20}}</h1>
<!-- 指令语法 v-指令 -->
<a v-bind:href="vue3link">点我跳转到vue官网</a>
</div>
<!-- CDN引入方式 -->
<!-- <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> -->
<!-- 引入本地vue.js文件 -->
<script src="./vue.js"></script>
<script>
// 初始化 vue 对象
const app = Vue.createApp({
data(){ // 这里存放页面需要引用的数据,通过return返回对象
// data这里定义数据
return {
name:'AiLynn',
vue3link:'https://cn.vuejs.org/'
}
}
})
app.mount('#root') // 挂载到id=root的元素上,开始操控此元素
</script>
</body>
</html>

数据绑定
单向绑定
v-bind 单向数据绑定
- 语法:
v-bind:herf="xxx"
或简写为:href
- 特点:数据只能从js流向html
双向绑定
v-model 双向数据绑定
- 语法:
v-model="xxxx"
- 特点:数据不仅能从js流向html,还能从html流向js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue_test02</title>
</head>
<body>
<div id="root">
<!-- v-bind:待绑定的属性="data返回的变量" -->
<!-- 单向绑定,数据只能从js流向html -->
<input type="text" placeholder="请输入姓名" v-bind:value="name">
<!-- 上面的v-bind:value="name"可以简写为 :value="name" -->
<!-- v-model="值" 自动绑定元素对应的属性(文本框、下拉框等) -->
<!-- 双向绑定,数据可以从js流向html,也可以从html流向js -->
<!-- <input type="text" placeholder="请输入年龄" v-model="age"> -->
<!-- v-model的lazy模式,当脱离焦点后再进行同步 -->
<input type="text" placeholder="请输入年龄" v-model.lazy="age">
<h3>姓名:{{name}}</h3>
<h3>年龄:{{age}}</h3>
</div>
<script src="./vue.js"></script>
<script>
Vue.createApp({
data(){
return{
name:"AiLynn",
age:18
}
}
}).mount("#root")
</script>
</body>
</html>

v-model的补充说明
v-model的lazy模式,当脱离焦点后再进行同步
<input type="text" placeholder="请输入年龄" v-model.lazy="age">
number修饰符,会将v-model绑定的数据转成number
<input type="text" placeholder="请输入年龄" v-model.number="age">
trim修饰符,可以自动过滤用户的首尾空白字符串
<input type="text" placeholder="请输入年龄" v-model.trim="age">
事件监听
语法:v-on:事件名
简写语法 @事件名,如@click
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue_test03</title>
</head>
<body>
<div id="root">
<!-- v-on:事件="js表达式" 简写为@事件="js表达式" -->
<button v-on:click="age++">点我加1岁</button>
<h3>年龄:{{age}}</h3>
<!-- 加法计数器 -->
<input type="text" placeholder="请输入第1个值" v-model.number="value1">
<input type="text" placeholder="请输入第2个值" v-model.number="value2">
<button @click="add">计算</button>
<h3>结果:{{res}}</h3>
<!-- 函数不加括号, vue会默认传递事件对象给函数 -->
<input type="text" placeholder="请输入用户名" v-model="username" @keyup.enter="checkName">
<!-- vue通过 $event 表示事件对象参数 -->
<input type="text" placeholder="请输入用户名" v-model="username" @keyup.enter="checkName1('AiLynn',$event)">
<h3>{{username}}</h3>
</div>
<script src="./vue.js"></script>
<script>
Vue.createApp({
// 选项式API
data(){
return{
name: "AiLynn",
age: 18,
value1: "",
value2: "",
res: "",
username: ""
}
},
methods:{ // 自定义定义方法
// data定义的数据会绑定到this
add(){
this.res = this.value1 + this.value2
},
checkName(){
console.log("触发了checkName")
console.log(event.target.tagName) // 事件对象目标元素的标签名
},
checkName1(name,event){
console.log('检查:',name)
console.log(event.target.tagName) // 事件对象目标元素的标签名
}
}
}).mount("#root")
</script>
</body>
</html>
条件渲染
v-if
,后面可以跟v-else
或v-else-if
形成多条件分支
v-show
,与v-if
用法相同,区别是v-if
销毁创建dom
,而v-show
只是更改display
样式。即v-if
的资源开销要比v-show
要大
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue_test04</title>
</head>
<body>
<div id="root">
<button @click="ate=!ate">开饭/消化</button>
<!-- v-if 用于控制元素是否显示 控制元素的生成和销毁-->
<!-- <h3 v-if="ate">吃过了</h3> -->
<!-- v-show 作用是控制了元素的样式 (v-if 性能开销比v-show小,在元素频繁切换的场景建议使用v-show)-->
<h3 v-show="ate">吃过了</h3>
<h3 v-else>饿了</h3>
<!-- v-if 后面紧跟着 v-else 或 v-else-if 可以实现分支效果 -->
</div>
<script src="./vue.js"></script>
<script>
Vue.createApp({
data(){
return{
ate: false,
}
},
methods:{
}
}).mount("#root")
</script>
</body>
</html>
列表渲染
v-for
,用于渲染列表。
语法:v-for="item in items"
用在需要多次渲染的元素上。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue_test05</title>
</head>
<body>
<div id="root">
<h3>待办事项:</h3>
<ul>
<!-- v-for 用于需要循环渲染的元素上,常用于列表元素 -->
<!-- v-for 语法 v-for="item in itemlist" -->
<li v-for="todo in todo_list">{{todo}}</li>
</ul>
</div>
<script src="./vue.js"></script>
<script>
Vue.createApp({
data(){
return{
todo_list: ["吃饭","睡觉","打豆豆"]
}
}
}).mount("#root")
</script>
</body>
</html>
MVVM模型
M Model:数据层,即data()返回的数据
V View:视图,data()挂载的html的内容
VM ViewModel:视图模型,主要用于Model和View之间的桥梁,包含DOM Listeners和Data Bindings,通过数据的双向绑定进行关联

响应式原理
什么是响应式?
响应式就是视图渲染时使用到了一个数据,当数据更新时,视图就会响应是否更新。
在 Vue2 中,Vue 是使用 Object.defineProperty 来实现响应式的。
在 Vue 3 中,数据是基于 JavaScript Proxy(代理) 实现响应式的。通过Proxy(代理)拦截对象中任意属性的变化,包括属性值的读写、属性的增加、属性的删除等;通过Reffect(反射)对源对象的属性进行操作。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue_test06</title>
</head>
<body>
<script>
// proxy 是ES6引入的API,作用是在目标对象之前拦截一层代理,可以通过操作代理实现操作对象。
const obj = {
addr:"北京"
}
// 创建代理obj
const p = new Proxy(obj,{
// 拦截取值动作
get: function(target,key){ // 目标对象,属性
console.log("拦截get操作--vue这里做了更复杂的操作")
// console.log(target)
// console.log(key)
// return target[key]
return Reflect.get(target,key) // 反射的方式取值
},
// 拦截设置值的动作
set: function(target,key,value){
console.log('拦截set操作--vue这里做了更复杂的操作')
target[key]=value
Reflect.set(target,key,value)
}
})
</script>
</body>
</html>

选项式API扩展知识
computed
computed 计算属性——用于简化模板里的逻辑
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue_test07</title>
</head>
<body>
<div id="root">
<h3>{{chilema}}</h3>
<button @click="ate=!ate">吃饭/消化</button>
</div>
<script src="./vue.js"></script>
<script>
const vm = Vue.createApp({
data(){
return{
ate: false
}
},
computed:{ // 计算属性——用于简化模板里的逻辑
chilema(){ // 定义方法——模板里面当做属性来用
return this.ate?"吃过了":"没吃呢"
}
}
// computed与methods的区别:
// computed会缓存结果(当操作的数据没有发生改变时),
// 而methods会立即执行,不缓存结果。
}).mount("#root")
</script>
</body>
</html>
watch
watch监听器,可以检测数据的变化,执行一些复杂逻辑
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue_test08</title>
</head>
<body>
<!-- 监听器的作用:可以检测数据的变化,执行一些复杂逻辑 -->
<div id="root">
<input type="text" placeholder="请输入用户名" v-model="username">
<h3>判断结果:{{result}}</h3>
<input type="password" placeholder="请输入密码" v-model="password">
<input type="password" placeholder="请再次输入密码" v-model="password_repeat">
<h3>{{res}}</h3>
</div>
<script src="./vue.js"></script>
<script>
Vue.createApp({
data(){
return{
username:'',
result:'',
password:'',
password_repeat:'',
res:''
}
},
watch:{
// 监听器语法
// 监听的变量名(new变量名,old变量名){判断,如果新变量名xxxx,就xxxx}
username(newname,oldname){
console.log('newname:',newname)
console.log('oldname:',oldname)
if(newname.length<8){
this.result='用户名不合法'
}else{
this.result="合法"
}
},
password_repeat(newvalue,oldvalue){
if(newvalue !=this.password){
this.res='两次密码输入不一致'
}else{
this.res=''
}
}
}
}).mount("#root")
</script>
</body>
</html>