Vue 基础语法
⼀、Vue 中应⽤和组件的概念
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue中应⽤和组件的概念</title>
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/vue@next"></script>
<script>
// createApp 表示创建⼀个 Vue 应⽤ ,存储到 app 变量中
// 传⼊的参数表示,这个应⽤最外层的组件,应该如何展示
// mvvm设计模式:m -> model数据,v ->view 视图 ,vm -> viewModel 视图数据连接层
const app = Vue.createApp({
data() {
return {
message: "hello world",
};
},
template: `<h2>{{message}}</h2>`,
});
// vm 代表的就是 Vue 应⽤的根组件,mount返回的根组件
const vm = app.mount("#app");
</script>
</body>
</html>
可以操作 vm
createApp 表示创建⼀个 Vue 应⽤,存储到 app 变量中
传⼊的参数表示,这个应⽤最外层的组件,应该如何展示
mvvm 设计模式
a. m->model 数据 data()
b. v->view 视图 template:
c. vm->viewModel 视图数据连接层 ( Vue 组件实现)
const vm = app.mount("#app"); //vm代表的就是Vue应⽤的根组件
在⽹⻚的 comsole 中可以通过
vm.$data.message = "bye";
来更改 Vue 组件中 data 的数值。
⼆、理解 Vue 的⽣命周期函数
Vue ⽣命周期函数: 在 ‘某⼀时刻’ 会 ‘⾃动执⾏’ 的函数
重要的四类、⼋个⽣命周期函数:
Vue 实例创建函数
beforeCreate(): 在创建 Vue 实例之前会⾃动执⾏的函数
created(): 在 Vue 实例⽣成之后会⾃动执⾏的函数
⻚⾯渲染函数
beforeMount(): 在组件内容被渲染到⻚⾯之前⽴即⾃动执⾏的函数
mounted(): 在组件内容被渲染到⻚⾯之后⾃定执⾏的函数
数据更新函数
beforeUpdate(): 当 data 中的数据发⽣变化时,会⾃动执⾏的函数
updated(): 当 data 中的数据发⽣变化,⻚⾯重新渲染后,会⾃动执⾏的函数
Vue 实例销毁函数
beforeUnmount(): 当 Vue 应⽤失效时/销毁时,⾃动执⾏的函数
unmounted(): 当 Vue 应⽤销毁时,且 DOM 完全销毁之后,⾃动执⾏的函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue中⽣命周期函数</title>
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/vue@next"></script>
<script>
// ⽣命周期函数:在某⼀时刻⾃动执⾏的函数
const app = Vue.createApp({
data() {
return {
message: "hello world",
};
},
//在 Vue 实例⽣成之前会⾃动执⾏的函数
beforeCreate() {
console.log("beforeCreate", this.message);
},
//在 Vue 实例⽣成之后会⾃动执⾏的函数
created() {
console.log(
"created",
document.getElementById("root").innerHTML,
this.message
);
},
//在组件内容被渲染到⻚⾯之前⾃动执⾏的函数
beforeMount() {
console.log(
"beforeMount",
document.getElementById("root").innerHTML,
this.message
);
},
//在组件内容被渲染到⻚⾯之后⾃动执⾏的函数
mounted() {
console.log(
"mounted",
document.getElementById("root").innerHTML,
this.message
);
},
// 当 data 中的数据发⽣变化时⾃动执⾏的函数 (可以在控制台 vm.$data.message = 'aaa')
beforeUpdate() {
console.log(
"beforeUpdate",
document.getElementById("root").innerHTML,
this.message
);
},
// 当 data中的数据发⽣变化,同时⻚⾯完成更新后,会⾃动执⾏的函数
updated() {
console.log(
"updated",
document.getElementById("root").innerHTML,
this.message
);
},
// 当 Vue 应⽤失效时⾃动执⾏的函数 (可以通过在控制台执⾏ app.unmount()模拟该操作)
beforeUnmount() {
console.log(
"beforeUnmount",
document.getElementById("root").innerHTML,
this.message
);
},
//当 Vue 应⽤失效且 DOM 完全销毁之后,⾃动执⾏的函数
unmounted() {
console.log(
"unmounted",
document.getElementById("root").innerHTML,
this.message
);
},
template: `<h2>{{message}}</h2>`,
});
const vm = app.mount("#app");
</script>
</body>
</html>
三、⻚⾯插值操作
1. 插值表达式 Mustache
插值表达式 {{ }}
的使⽤,是将模型数据插⼊到⻚⾯当中。 插值表达式为什么叫 Mustache (英⽂:⼋字须)呢?
看看 {{内容}}
的两个⼤括号像不像⼋字胡⼦呢。
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue插值表达式</title>
</head>
<body>
<div id="app">
<p>{{firstName}} {{lastName}} (⽤插值直接显示变量)</p>
<p>{{firstName.length}} (使⽤.访问变量的属性)</p>
<p>{{firstName + '-----' + lastName}} (字符串的拼接)</p>
<p>{{count * 2}} (简单的算术运算)</p>
<p>{{firstName === 'Stephen'? '真棒':'还好'}} (三⽬运算)</p>
<h2>
{{lastName.split('rr').reverse().join(',')}}(使⽤Javascript函数)
</h2>
<p>{{customMethod(lastName)}} (调⽤⾃定义函数)</p>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
firstName: "Stephen",
lastName: "Curry",
count: 10,
};
},
methods: {
customMethod(str) {
return str.split("").reverse().join(",");
},
},
});
const vm = app.mount("#app");
</script>
</body>
</html>
运⾏效果
由上⾯的例⼦可以看出:
- 插值表达式⽀持与其他的⽂字联合使⽤。
- 也⽀持三⽬运算和算术运算。
- 还可以使⽤ javascript 函数和⾃定义函数。
- lastName.split(‘rr’).reverse().join(‘,’) 的作⽤是将 lastName 字符串 ‘Curry’ ⽤ ‘rr’ 分割为数组 [‘Cu’, ‘y’] , 然后数组倒序,并⽤逗号为分隔符号合并 ( join ) 字符串数组。
- Vue 对象中的 methods 代码段是专⻔⽤于定义⾃定义函数的,我们⾃定义了函数 customMethod, 并在插值表达式中使⽤了它。
2. v-html 与 v-pre 指令的使⽤
1) v-html 指令
假如我们从服务器请求回来的是⼀个 HTML 的代码⽚段
- 如果我们想将 html 原样输出,就是⽤
{{ }}
就可以了。 * 如果我们希望浏览器解析 html 后展示,那就要使⽤到 v-html 了。
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>v-html指令</title>
</head>
<body>
<div id="app">
<ul>
<!-- 错误的做法 -->
<li>{{age}}</li>
<li>{{link}}</li>
<!-- 正确的做法 -->
<li v-html="age"></li>
<li v-html="link"></li>
</ul>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
age: "<strong>13</strong>",
link: '<a href="https://www.baidu.com">百度⼀下</a>',
};
},
});
const vm = app.mount("#app");
</script>
</body>
</html>
运⾏效果
2) v-pre 指令 如果我们想把下⾯的这段⽂字原样输出,怎么办?
Vue真有趣,特别是{{Mustache}}插值表达式
注意⽂本⾥⾯有⼀个{{Mustache}}
,Vue 会去找 Mustache 变量,找不到会报错。
即使我们定义了变量,也不满⾜我们的需求。
我们需要将 Mustache 原样输出,⽽不是交给浏览器做变量插值操作,这就需要⽤到 v-pre 指令。
代码示例:
<div id="app">
<h2 v-pre>Vue真有趣,特别是{{Mustache}}插值表达式</h2>
</div>
运⾏效果:
3. v-text 与 v-cloak 的使⽤
1)v-text 指令
我们⽤前⾯ Vue3 的快速起步练习,先来看⼀下 Mustache 的⼀个⼩ Bug 。
浏览器由于⽹速的问题,可能会在渲染 Mustache 数据的时候发⽣延迟,导致⼀瞬间会先显示 {{message}}
,⽽不是 Hello Vue3。
我们可以使⽤ Chrome 浏览器来模拟这个闪屏的问题:F12->NetWork->Slow 3G (慢速 3G ⽹络)。
可以使⽤ v-text 指令来解决闪屏的问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>v-text指令</title>
</head>
<body>
<div id="app">
<!-- 使⽤v-text解决闪屏现象 -->
<h2 v-text="message"></h2>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
message: "hello Vue",
};
},
});
const vm = app.mount("#app");
</script>
</body>
</html>
运⾏效果:
注意
<h2 v-text="message"></h2>
这⾥,我们使⽤ v-text 代替了{{message}}
,从⽽解决了闪屏的问题。但是要注意 v-text 并不支持这种写法
<h2 v-text="你好,message"></h2>
,这样写 Vue 会将你好,message 看作插值去 data 里面找数据属性定义,而我们只定义了 message。所以,再到一定程度上 v-text 失去了
{{ }}
使用语法的灵活性。 * 其他的使用方法 v-text 和{{ }}
是基本一致的。
2)v-cloak 指令
如果我们既想使用 <h2>你好,{{message}}</h2>
这种定义方式的灵活性,又想解决闪屏的问题,该怎么做呢?
可以使用 v-cloak 指令来解决
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>v-cloak指令</title>
<style>
/* v-cloak指令的样式:在DOM节点渲染完成之前不显示 */
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<h2 v-cloak>你好,{{message}}</h2>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
message: "Vue3",
};
},
});
const vm = app.mount("#app");
</script>
</body>
</html>
- 使⽤ v-cloak 指令并为该指令设置 display :none 的样式,⼆者结合使⽤表示在 h2 的 DOM 节点渲染完 成之前不显示你好,
{{message}}
,渲染完成之后显示 你好,Vue3。 - 注意:样式的定义要放在 head 标签⾥⾯,否则因为浏览器渲染顺序的差异,有可能不会⽣效。
- 注意:cloak 不是 clock ,cloak 英⽂是⽃篷、披⻛的意思。这⽐较形象,我先⽤⽃篷把⾃⼰盖起来, 等我化好妆了再出来⻅⼈。
四、⽤户操作事件监听
1. v-on 事件监听指令的基本⽤法
我们在开发过程中经常需要监听⽤户的输⼊,⽐如:⽤户的点击事件、拖拽事件、键盘事件等等。
这就需要⽤到 v-on 指令。
我们通过⼀个简单的计数器的例⼦,来学习 v-on 指令的使⽤。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>计数器</title>
<style>
[v-cloak] {
display: none;
}
button {
margin: 5px;
}
</style>
</head>
<body>
<div id="app">
<h2 v-cloak>counter:{{counter}}</h2>
<button @click="counter++">+</button>
<button @click="counter--">-</button>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
counter: 0,
};
},
});
const vm = app.mount("#app");
</script>
</body>
</html>
- 定义数据 counter,⽤于表示计数器数字,初始值设置为 0
- v-on:click 表示当发⽣点击事件的时候,触发等号⾥⾯的表达式或者函数
- 表达式 counter++ 和 counter– 分别实现计数器数值的加 1 和减 1 操作
- 语法糖:我们可以将 v-on:click 简写为 @click
- 点击加号数值加 1
- 点击减号数值减 1
表达式只适⽤于简单的数据操作场景。如果操作⽐较复杂,我们要使⽤函数的⽅式实现。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>计数器</title>
<style>
[v-cloak] {
display: none;
}
button {
margin: 5px;
}
</style>
</head>
<body>
<div id="app">
<h2 v-cloak>counter:{{counter}}</h2>
<button @click="incr()">+</button>
<button @click="desc()">-</button>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
counter: 0,
};
},
methods: {
incr() {
this.counter++;
},
desc() {
this.counter--;
},
},
});
const vm = app.mount("#app");
</script>
</body>
</html>
运⾏效果同前
附录:js 常⽤可监听事件列表
属性 | 事件何时触发 |
---|---|
abort | 图像的加载被中断。 |
blur | 元素失去焦点。 |
onchange | 域的内容被改变。 |
click | 当⽤户点击某个对象时调⽤的事件句柄。 |
dblclick | 当⽤户双击某个对象时调⽤的事件句柄。 |
error | 在加载⽂档或图像时发⽣错误。 |
focus | 元素获得焦点。 |
keydown | 某个键盘按键被按下。 |
keypress | 某个键盘按键被按下并松开。 |
keyup | 某个键盘按键被松开。 |
load | ⼀张⻚⾯或⼀幅图像完成加载。 |
mousedown | ⿏标按钮被按下。 |
mousemove | ⿏标被移动。 |
mouseout | ⿏标从某元素移开。 |
mouseover | ⿏标移到某元素之上。 |
mouseup | ⿏标按键被松开。 |
reset | 重置按钮被点击。 |
resize | 窗⼝或框架被重新调整⼤⼩。 |
select | ⽂本被选中。 |
submit | 确认按钮被点击。 |
unload | ⽤户退出⻚⾯。 |
2. v-on 事件监听⽅法传参
我们通过点击事件监听,实现了计数器的加⼀和减⼀的操作。
如果我们想更灵活⼀点,实现加 n 和减 n 的操作,我们就需要给⾃定义的函数传参数了。
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>传参计数器</title>
<style>
[v-cloak] {
display: none;
}
button {
margin: 5px;
}
</style>
</head>
<body>
<div id="app">
<h2 v-cloak>counter:{{counter}}</h2>
<button @click="incr(step)">+2</button>
<button @click="desc(step)">-2</button>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
counter: 0,
step: 2,
};
},
methods: {
incr(n) {
this.counter += n;
},
desc(n) {
this.counter -= n;
},
},
});
const vm = app.mount("#app");
</script>
</body>
</html>
- 我们定义了步⻓变量 step,默认值为 2,作为参数传递给 incr 和 decr ⽅法。
- incr 和 decr ⽅法接受参数,并分别做加 n 和 减 n 的操作。
- 如果我们想动态地实现加 n,减 n,就设置 app.step = n 就可以了。
运⾏效果
- 每点击⼀次加 2 按钮,counter 加 2;每点击⼀次减 2 按钮,counter 减 2
Vue 会默认给我们给我们⼀个参数 event ,这个参数的使⽤⽅法如下:
<button v-on:click="decr(step,$event)">-</button>
将 event 参数放在参数列表的的最后位置。注意:函数没有⾃定义参数也可以接收 event 参数。
desc(n, event) {
this.counter = this.counter - n
console.log(event)
}
我们将 event 参数打印出来,结果如下:
- PointerEvent 的类型为“ mouse ”,表示⼀个⿏标产⽣的事件
- 下图中可以看出,我们通过事件可以获取,事件产⽣的屏幕坐标、是否冒泡、事件类型 click 等信息
3. v-on 事件监听修饰符
在学习事件监听修饰符之前,我们有必要来复习⼀些基础知识。
1)什么是事件冒泡与事件捕获?
事件冒泡和事件捕获是 Dom 事件传播的两种模式,默认是冒泡模式。
- 事件冒泡:事件从事件⽬标( target )开始,往上冒泡直到⻚⾯的最上⼀级标签。对于上⾯的例⼦,当 我们点击 div#child 的时候,⽅法 childMethod 和 parentMethod 将先后被调⽤。
- 事件捕获:事件捕获模式与冒泡模式正好相反,事件从⽗元素向⼦元素传播。对于上⾯的例⼦,当 我们点击 div#parent 的时候,⽅法 parentMethod 和 childMethod 将先后被调⽤。
2)什么是 html 标签的默认⾏为?
- ⽐如:标签
<a>
的默认⾏为是实现跳转 - ⽐如:
<input type="submit">
默认⾏为是提交表单
3)事件监听的修饰符
.stop 修饰符
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>事件冒泡stop修饰符</title>
<style>
#parent {
width: 200px;
height: 200px;
background-color: rgb(74, 138, 197);
}
#child {
width: 100px;
height: 100px;
line-height: 100px;
background-color: rgb(212, 219, 115);
margin-left: 50px;
margin-top: 25px;
}
</style>
</head>
<body>
<div id="app">
<div id="parent" @click="parentMethod">
⽗元素
<div id="child" @click.stop="childMethod">⼦元素</div>
</div>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {};
},
methods: {
parentMethod() {
alert("⽗元素");
},
childMethod() {
alert("⼦元素");
},
},
});
const vm = app.mount("#app");
</script>
</body>
</html>
子元素加上 stop 修饰符号之后,点击⼦元素 div ,只有 childMethod ⽅法被触发,parentMethod ⽅法不会被触发。
.self 修饰符
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>事件冒泡self修饰符</title>
<style>
#parent {
width: 200px;
height: 200px;
background-color: rgb(74, 138, 197);
}
#child {
width: 100px;
height: 100px;
line-height: 100px;
background-color: rgb(212, 219, 115);
margin-left: 50px;
margin-top: 25px;
}
</style>
</head>
<body>
<div id="app">
<div id="parent" @click.self="parentMethod">
⽗元素
<div id="child" @click="childMethod">⼦元素</div>
</div>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {};
},
methods: {
parentMethod() {
alert("⽗元素");
},
childMethod() {
alert("⼦元素");
},
},
});
const vm = app.mount("#app");
</script>
</body>
</html>
⽗元素加上 self 修饰符之后,点击⼦元素 div,只有 childMethod ⽅法被触发,parentMethod ⽅法不会被触发。
运⾏效果同前。
.prevent 修饰符
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>阻⽌默认事件.prevent修饰符</title>
</head>
<body>
<div id="app">
<!-- ⽤.prevent修饰符阻⽌默认事件 -->
<a @click.prevent="doThis" href="#">点击</a>
<form action="/login" @submit.prevent="doThis" method="get">
<input type="submit" value="提交" />
</form>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {};
},
methods: {
doThis() {
alert(" ⽤.prevent修饰符阻⽌默认事件");
},
},
});
const vm = app.mount("#app");
</script>
</body>
</html>
加上 prevent 修饰符号之后,不会有 a 标签的默认跳转⾏为,也没有表单的提交⾏为,会调⽤ doThis() ⽅法。
注意:
修饰符号可以串联使⽤,.stop.prevent 表示先阻⽌冒泡⾏为,后阻⽌ a 标签的默认跳转⾏为。
4)事件监听修饰符总结
- stop 修饰符,可以阻⽌事件向上级标签的冒泡⾏为。
- self 修饰符,表示被该修饰符修饰的⽗元素不接收⼦元素的事件冒泡⾏为。
- prevent 修饰符,可以阻⽌⼀些 html 标签的默认⾏为,⽐如 a 标签。
- enter 修饰符(按键监听修饰符的⼀种),可以监听回⻋按键的操作。
- once 修饰符,表示事件只可以被触发监听⼀次,以后再操作则⽆效。
- capture 修饰符,表示开启事件传播的捕获模式,事件由⽗元素向⼦元素传播,较少⽤到。
5)按键监听修饰符
Vue 给我们定义好了⼀些常⽤的按键监听修饰符,如下:
- .enter 监听回⻋键
- .tab 监听 Tab 键
- .delete (监听“删除”和“退格”键)
- .esc 监听 ESC 键
- .space 监听空格键
- .up 监听”上”键
- .down 监听”下”键
- .left 监听”左”键
- .right 监听”右”键
如果觉得上⾯的键盘监听修饰符不够⽤,还可以⾃定义,⽐如定义监听 F1 按键。
// 可以使⽤ `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112;
F1 按键的键盘码是 112。