本文使用的是Vue2.6.14
C:\Users\z004abwh>node -v
v16.14.2
C:\Users\z004abwh>npm -v
8.5.0
IDE
调试工具
vue devtools
两种安装方式:
第一种:github下载zip包,
https://github.com/vuejs/devtools#vue-devtools
最新版本的调试工具要用yarn命令
npm install -g yarn
解压从github上下载的vue-devtools,进入目录
执行:yarn install
执行:yarn run build
最后把打包的结果导入到浏览器的扩展程序中
第二种:直接在一个空目录中使用npm i vue-devtools(亲测可用)
在vue-devtools文件夹下:shells>chrome>manifest.json,将配置里的persistent的值修改为true;
打开chrome,进入扩展程序管理界面(chrome://extensions/),加载已解压的扩展程序。选择vue-devtools>shells>chrome。加载完成就会出现以下的Vue.js devtools扩展程序。然后重启浏览器,再打开vue项目页面就可以在chrome的Devtools(就是console的那一栏,一般都排在最后面的。)找到Vue面板了。
项目的目录结构:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YzZauMtX-1663494649201)(D:\markdown\Vue速成手册.assets\image-20220720104855387.png)]
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
{{ message }}
div>
<script src="./vue.js">script>
<script>
<!-- 实例化一个Vue对象-->
const vm = new Vue({
// 挂在一个容器
el: "#app",
// 创建组件内的数据
data: {
message: "Hello Vue 2.6.14"
}
})
script>
body>
html>
浏览器调试窗口预留:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1EJGdfUx-1663494649202)(D:\markdown\Vue速成手册.assets\image-20220720104954011.png)]
vue中的模板语法分为两大类
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-bind数据绑定title>
head>
<body>
<div id="app">
<input type="text" v-bind:value="message"> <br><br>
<input type="text" :value="message">
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: "#app",
data: {
message: "数据绑定"
}
})
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-bind数据绑定title>
head>
<body>
<div id="app">
<input type="text" v-model:value="message"> <br><br>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: "#app",
data: {
message: "数据绑定"
}
})
script>
body>
html>
第一种写法:el做为Vue构造函数的参数对象中的一个key,其值是一个符合css选择器的一个容器
const vm = new Vue({
el: '#app'
})
第二种写法:先创建Vue实例,最后通过vm.$mount(‘#app’) 挂载对象
const vm = new Vue({})
vm.$mount('#app')
对象形式
const vm = new Vue({
el: '#app',
data: {
message: "hello"
}
})
函数形式(在组件中必须是函数形式的)
const vm = new Vue({
el: '#app',
// 正常写法
data: function(){
return {
message: "hello world"
}
}
// 简写形式
data(){
return {
message: "hello world"
}
}
// 错误写法
data: ()=>{
console.log(this) # 这个this指向的是Window
return{message: 'Hello'}
}
})
由Vue管理的函数,一定不要写箭头函数,否则this指向就不再是Vue实例了

M-Model 指data中的数据
V-View 指模板
VM-ViewModel 视图模型,Vue实例
vm对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-knIl6gzX-1663494649202)(D:\markdown\Vue速成手册.assets\image-20220720120634191.png)]
vm对象里面的属性和其原型对象上面的属性都可以在模板中直接使用。
Object对象是原型链的尽头,也可以说是所有对象的超类,在Object对象上有一个defineProperty方法。下面看下这个方法的具体使用流程:
// 定义一个临时变量,初始化为空
let temp = ''
// 定义一个对象,设置两个属性分别是name和age
let obj = {
name: '张三',
age: 18
}
// 调用Object的defineProperty方法
// 1 参数1: 是需要监听的对象
// 2 参数2: 是需要监听的对象里面的某一个属性
// 3 参数3: 用于定制get方法和set方法,get方法的返回值是obj.xxx的结果值,set方法接收一个参数,这个参数是obj.xxx = yyy 中的yyy
Object.defineProperty(obj, 'name', {
get(){
console.log('obj的name属性被读取了')
return '小乌龟'
},
set(value){
console.log('obj的name属性被改写了')
temp = value
}
})
// 改变name属性的值
obj.name = '张无忌' // 输出: obj的name属性被改写了
// 临时变量被赋值
console.log(temp) // 输出: 张无忌
// 获取对象属性值方法一
console.log(obj['name']) // 输出: obj的name属性被读取了 小乌龟
// 获取对象属性值方法二
console.log(obj.name) // 输出: obj的name属性被读取了 小乌龟
let obj1 = {
name: '张三',
age: 19
}
let obj2 = {
name: '里斯',
age: 24
}
Object.defineProperty(obj1, 'name', {
get(){
return obj2.name
},
set(value){
obj2.name = value
}
})
Object.defineProperty(obj1, 'age', {
get(){
return obj2.age
},
set(value){
obj2.age = value
}
})
/*
测试代码
obj1.name
'里斯'
obj1.age
24
*/
vue中的数据代理是通过vm对象来代理data对象中属性的操作
使用vm对象代理data对象的好处是更方便,在模板中可以直接操作data中的数据,在vm实例中可以通过this.xxx直接获取到xxx属性。
new Vue({…})创建vm实例成功后,会把data中的值赋值到vm的_data属性下,vm.xxx本质上会调用vm._ _ data.xxx,_ data.xxx又会调用defineProperty的get()方法,进行实现使用vm对象代理data对象的行为。

以点击事件为例演示Vue中如何绑定事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>绑定事件练习</title>
</head>
<body>
<div id="app">
<!-- v-on普通写法-->
<button v-on:click="test">绑定事件练习</button>
<!-- v-on简单写法-->
<button @click="test">绑定事件简单写法</button>
<!-- 参数传递@click="sendParams"等价于@click="sendParams($event)" $event保存着绑定的事件-->
<button @click="sendParams">绑定事件默认传参</button>
<!-- 如果有多个参数-->
<button @click="sendMultiParams($event, 123)">绑定事件传递多个参数</button>
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: 'hello'
},
methods: {
test() {
alert(this.msg)
},
sendParams(e) {
console.log(e) // 输出点击事件
},
sendMultiParams(e, x) {
console.log(e) // 输出点击事件
console.log(x) // 输出123
}
}
})
</script>
</body>
</html>
简单总结一下:
绑定事件的正常写法: v-on:event = “callback”; 绑定事件的简单写法:@event = “callback”
@click=“callback” 等价于 @click=“callback($event)” ,如果回调不需要传其他参数那么前面的两种写法都可以
如果回调需要用到事件对象和其他参数,那必须这样写:@click=“callback($event, args)”
回调函数定义在methods上
methods函数中的this指向问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>methods中this的指向问题</title>
</head>
<body>
<div id="app">
<button @click="getMsg">获取data中的msg</button>
<button @click="getMsg2" style="background-color: red">获取data中的msg</button>
</div>
<script src="./vue.js"></script>
<script>
msg = '全局我最大'
const vm = new Vue({
el: '#app',
data: {
msg: '嘻嘻哈哈好开心'
},
methods: {
getMsg: function () {
console.log(this) // 输出 : Vue实例对象 也就是vm
console.log(this.msg) // 输出 : 嘻嘻哈哈好开心
},
getMsg2: () => {
console.log(this) // 输出:Window 全局对象
console.log(this.msg) // 输出: 全局我最大
}
}
})
</script>
</body>
</html>
事件描述符可以连续写
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>事件修饰符title>
<script type="text/javascript" src="../js/vue.js">script>
<style>
* {margin-top: 20px;}
.demo1 {height: 50px;background-color: skyblue;}
.box1 {padding: 5px;background-color: skyblue;}
.box2 {padding: 5px;background-color: white;}
.list {width: 200px;height: 200px;background-color: skyblue;overflow: auto;}
li {height: 100px;}
style>
head>
<body>
<div id="root">
<h2>欢迎来到{{ name }}学习h2>
<a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息a>
<div class="demo1" @click="showInfo">
<button @click.stop="showInfo">点我提示信息button>
div>
<button @click.once="showInfo">点我提示信息button>
<div class="box1" @click.capture="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">
div2
div>
div>
<div class="demo1" @click.self="showInfo">
<button @click="showInfo">点我提示信息button>
div>
<ul @wheel.passive="demo" class="list">
<li>1li>
<li>2li>
<li>3li>
<li>4li>
ul>
div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
name: '尚硅谷'
},
methods: {
showInfo(e) {
alert('同学你好!')
// console.log(e.target)
},
showMsg(msg) {
console.log(msg)
},
demo() {
for (let i = 0; i < 100000; i++) {
console.log('#')
}
console.log('累坏了')
}
}
})
script>
body>
html>
Vue定制的常用按键别名
自定义按键别名
Vue.config.KeyCodes.自定义键名 = 键码
案例
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>键盘事件title>
<script type="text/javascript" src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>欢迎打开{{name}}笔记h2>
<input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo"><br/>
<input type="text" placeholder="按下tab提示输入" @keydown.tab="showInfo"><br/>
<input type="text" placeholder="按下回车提示输入" @keydown.huiche="showInfo"><br/>
div>
<script type="text/javascript">
Vue.config.productionTip = false // 阻止 vue 在启动时生成生产提示。
Vue.config.keyCodes.huiche = 13 // 定义了一个别名按键
new Vue({
el: '#root',
data: {
name: 'cess'
},
methods: {
showInfo(e) {
// console.log(e.key,e.keyCode)
console.log(e.target.value)
}
},
})
script>
body>
html>
使用插值表达式实现:
计算属性引入小例子
first name:
last name:
full name: {{ firstName + '-' + lastName }}
使用methods实现:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性引入小例子title>
head>
<body>
<div id="app">
first name: <input type="text" v-model:value="firstName"/> <br>
last name: <input type="text" v-model:value="lastName"/>
<h3 style="color: red">full name: {{ getFullName() }}h3>
div>
<script src="./vue.js">script>
<script>
Vue.config.productionTip = false
const vm = new Vue({
el: '#app',
data: {
firstName: '张',
lastName: '三',
},
methods: {
getFullName() {
console.log('@getFullName被执行了。。。')
return this.firstName + this.lastName
},
}
})
script>
body>
html>
使用计算属性写法
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性引入小例子title>
head>
<body>
<div id="app">
first name: <input type="text" v-model:value="firstName"/> <br>
last name: <input type="text" v-model:value="lastName"/>
<h3 style="color: green">full name: {{ fullName }}h3>
div>
<script src="./vue.js">script>
<script>
Vue.config.productionTip = false
const vm = new Vue({
el: '#app',
data: {
firstName: '张',
lastName: '三',
},
computed: {
// 完整写法
fullName: {
get() {
return this.firstName + '-' + this.lastName
},
set(value) {
let arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
// 如果只是获取数据,那么可以直接使用简写方式
fullName(){
return this.firstName + '-' + this.lastName
}
}
})
script>
body>
html>
计算属性一般用于通过已知属性计算获取到的值,例如上面的例子。姓名都是已经的属性。连接起来获取全名
计算属性的原理也是利用Object.defineProperty()方法提供的getter和setter
get函数初次读取时执行一次,数据变化时执行一次
与methods相比,计算属性有缓存机制,数据不变化就不会更新
计算属性会出现在vm实例对象上,可以直接在模板中像data中的数据一样使用
如果需要改变计算属性,并响应式的更新页面,那么需要设计set方法,如果不需要修改计算属性和其相关的属性,那么使用简写格式是最好用的。
watch监视属性用于监视属性的变化,当属性发生变化时,回调函数自动被调用。
监视的属性必须存在才能被监视,可以是data里面的属性也可以是计算属性
监视属性同样具有两种写法:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch用法title>
head>
<body>
<div id="app">
<h3>好好 {{ msg }}h3>
<button @click="changeStatus">切换状态button>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
flag: true,
msg: ''
},
methods: {
changeStatus() {
this.flag ? this.msg = '学习' : this.msg = '玩耍'
this.flag = !this.flag
}
},
// 监视属性,key必须是watch,vue中已经写死,value是一个对象
watch: {
// 监视的属性,可以是data也可以是计算属性,当被监视的属性发生变化时,handler函数会被调用
msg: {
// 内部钩子函数,接收两个值,分别是修改后的值和修改前的值
handler(newVal, oldVal) {
console.log('msg被修改了', newVal, oldVal)
}
}
}
})
script>
body>
html>
计算属性的简写方式
/*前面省略*/
watch: {
msg(newVal, oldVal){
console.log('msg被修改了', newVal, oldVal)
}
}
/*后面省略*/
如果想加载时就执行一次,那么需要配置immediate属性
/*前面省略*/
watch: {
msg: {
immediate: true, //加载完成就触发一次
handler(newVal, oldVal) {
console.log('msg被修改了', newVal, oldVal)
}
}
}
/*后面省略*/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HFuLA8wM-1663494649203)(D:\markdown\Vue速成手册.assets\image-20220721110751321.png)]
加载时候就执行了一次监听属性的回调函数,这时候未修改时候的值是undefined。
在js中对象和数组属于复杂对象,复杂对象的值是一个指针,指向的是堆中的地址,修改复杂对象内部的值并不会改变对象本身,所以也就不会触发监视属性。
监视复杂对象的错误写法
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch深度监视案例title>
head>
<body>
<div id="app">
<h1>个人信息h1>
<input type="text" :value="person.name">
<input type="text" :value="person.age"/>
<button @click="changeName">修改姓名button>
<button @click="changeAge">修改年龄button>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
person: {
name: '张三',
age: 12
}
},
methods: {
changeName() {
this.person.name = 'lisi'
},
changeAge() {
this.person.age = 99
},
},
watch: {
person: {
handler(newValue, oldValue) {
console.log('person被修改了' + '新值是:' + newValue + '老值是:' + oldValue)
}
}
}
})
script>
body>
html>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ju1c6FXJ-1663494649204)(D:\markdown\Vue速成手册.assets\image-20220721112249335.png)]
无论怎么点击按钮,handler回调都不会执行。
监视复杂对象的正确写法1
watch: {
'person.name': {
handler(newValue, oldValue) {
console.log('person.name被修改了' + '新值是:' + newValue + '老值是:' + oldValue)
}
},
'person.age': {
handler(newValue, oldValue) {
console.log('person.age被修改了' + '新值是:' + newValue + '老值是:' + oldValue)
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o2Pn9EES-1663494649204)(D:\markdown\Vue速成手册.assets\image-20220721112442174.png)]
监视复杂对象的正确写法2
watch: {
person: {
deep: true,
handler(newValue, oldValue) {
console.log('person.name被修改了' + '新值是:' + newValue.name + '老值是:' + oldValue.name)
console.log('person.age被修改了' + '新值是:' + newValue.age + '老值是:' + oldValue.age)
}
},
deep属性可以监听到复杂对象内部的数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ffnji6u6-1663494649204)(D:\markdown\Vue速成手册.assets\image-20220721114031722.png)]
使用计算属性实现:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性与侦听属性的用法比对title>
head>
<body>
<div id="app">
<input type="text" v-model:value="firstName"> <br>
<input type="text" v-model:value="lastName">
<h3>{{ fullName }}h3>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
firstName: '张',
lastName: '三'
},
computed: {
fullName(){
return this.firstName + '-' + this.lastName
}
}
})
script>
body>
html>
这里的代码不做过多的解释,很基础的实现过程。
使用侦听属性实现:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性与侦听属性的用法比对title>
head>
<body>
<div id="app">
<input type="text" v-model:value="firstName"> <br>
<input type="text" v-model:value="lastName">
<h3>{{ fullName }}h3>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
firstName: '张',
lastName: '三',
fullName: '张-三'
},
// computed: {
// fullName(){
// return this.firstName + '-' + this.lastName
// }
// }
watch: {
firstName(newVal){
this.fullName = newVal + this.lastName
},
lastName(newVal){
this.fullName = this.firstName + newVal
}
}
})
script>
body>
html>
我现在的需求是,如果名字更新那么全名立即更新,如果是姓更新了,等一秒钟再更新全名,更新需求后发现用计算属性很难实现了
用侦听属性实现:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性与侦听属性的用法比对title>
head>
<body>
<div id="app">
<input type="text" v-model:value="firstName"> <br>
<input type="text" v-model:value="lastName">
<h3>{{ fullName }}h3>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
firstName: '张',
lastName: '三',
fullName: '张-三'
},
// computed: {
// fullName(){
// return this.firstName + '-' + this.lastName
// }
// }
watch: {
firstName(newVal) {
setTimeout(() => {
this.fullName = newVal + this.lastName
}, 1000)
},
lastName(newVal) {
this.fullName = this.firstName + newVal
}
}
})
script>
body>
html>
计算属性和侦听属性的对比
计算属性
计算属性能完成的功能,侦听属性都可以完成
侦听属性
侦听属性能够完成的功能,计算属性不一定能完成,比如实现一些异步操作,在一个属性修改1s后执行一个动作。
关于this指向的小总结,极其重要
通过v-bind绑定任意dom元素的class属性,通过对class属性赋值
绑定样式的写法:
:class = 'xxx' // xxx可以是字符串、数组、对象
也可以直接绑定dom元素的style属性
:style="[a,b]" // 其中a,b是样式对象
:style="{fontSize: xxx}" 其中xxx是动态值
示例代码:
<style>
.basic {width: 300px;height: 50px;border: 1px solid black;}
.happy {border: 3px solid red;background-color: rgba(255, 255, 0, 0.644);
background: linear-gradient(30deg, yellow, pink, orange, yellow);}
.sad {border: 4px dashed rgb(2, 197, 2);background-color: skyblue;}
.normal {background-color: #bfa;}
.atguigu1 {background-color: yellowgreen;}
.atguigu2 {font-size: 20px;text-shadow: 2px 2px 10px red;}
.atguigu3 {border-radius: 20px;}
style>
<div id="root">
<div class="basic" :class="mood" @click="changeMood">{{name}}div><br/><br/>
<div class="basic" :class="classArr">{{name}}div><br/><br/>
<div class="basic" :class="classObj">{{name}}div><br/><br/>
<div class="basic" :style="styleObj">{{name}}div><br/><br/>
<div class="basic" :style="styleArr">{{name}}div>
div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el: '#root',
data: {
name: '尚硅谷',
mood: 'normal',
classArr: ['atguigu1', 'atguigu2', 'atguigu3'],
classObj: {
atguigu1: false,
atguigu2: false,
},
styleObj: {
fontSize: '40px',
color: 'red',
},
styleObj2: {
backgroundColor: 'orange'
},
styleArr: [
{
fontSize: '40px',
color: 'blue',
},
{
backgroundColor: 'gray'
}
]
},
methods: {
changeMood() {
const arr = ['happy', 'sad', 'normal']
const index = Math.floor(Math.random() * 3)
this.mood = arr[index]
}
},
})
script>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>条件渲染title>
head>
<body>
<div id="app">
<h1>打分系统h1>
<label for="number">分数:label>
<input type="text" v-model:value="number" id="number">
<button @click="getRandomNumber">获取分数button>
<br>
<hr>
<p>等级:p>
<p v-if="number>=80">Ap>
<p v-else-if="number<80 && number>=60">Bp>
<p v-else-if="number<60 && number>=40">Cp>
<p v-else>Dp>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
number: 0,
},
methods: {
getRandomNumber() {
this.number = Math.round(Math.random(1, 100) * 100)
}
}
})
script>
body>
html>
小结
写法
v-if = "表达式"
v-else-if = "表达式"
v-else
v-if 与v-show的区别
v-if 会直接操作dom元素,直接删除dom元素,v-if用于切换不频繁的场景
v-show 不会直接操作dom元素,v-show操作的是display属性,不会直接操作dom元素,用于频繁切换的场景
如果需要使用template标签对整块结构进行操作,那么只支持v-if,不支持v-show
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-if与v-showtitle>
head>
<body>
<div id="app">
<template v-if="isShow">
<p>静夜思p>
<br>
<p>窗前明月光p>
<p>疑是地上霜p>
<p>举头望明月p>
<p>低头思故乡p>
template>
<button @click="show"> 显示/隐藏 button>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
isShow: true
},
methods: {
show(){
this.isShow = !this.isShow
}
}
})
script>
body>
html>
v-for用于遍历数组、对象、字符串
语法:
<li v-for=(item, index) of items :key="index">li>
示例代码
<title>基本列表title>
<script type="text/javascript" src="../js/vue.js">script>
<div id="root">
<h3>人员列表(遍历数组)h3>
<ul>
<li v-for="(p,index) of persons" :key="index">{{ p.name }}-{{ p.age }}li>
ul>
<h3>汽车信息(遍历对象)h3>
<ul>e
<li v-for="(value,k) of car" :key="k">{{ k }}-{{ value }}li>
ul>
<h3>测试遍历字符串(用得少)h3>
<ul>
<li v-for="(char,index) of str" :key="index">{{ char }}-{{ index }}li>
ul>
<h3>测试遍历指定次数(用得少)h3>
<ul>
<li v-for="(number,index) of 5" :key="index">{{ index }}-{{ number }}li>
ul>
div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
persons: [
{ id: '001', name: '张三', age: 18 },
{ id: '002', name: '李四', age: 19 },
{ id: '003', name: '王五', age: 20 }
],
car: {
name: '奥迪A8',
price: '70万',
color: '黑色'
},
str: 'hello'
}
})
script>

待补充
表单类型
v-model 修饰符
收集表单示例
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用v-model收集表单数据title>
head>
<body>
<div id="root">
<form @submit.prevent="demo">
账号:<input type="text" v-model.trim="userInfo.account"> <br/><br/>
密码:<input type="password" v-model="userInfo.password"> <br/><br/>
年龄:<input type="number" v-model.number="userInfo.age"> <br/><br/>
性别:
男<input type="radio" name="sex" v-model="userInfo.sex" value="male">
女<input type="radio" name="sex" v-model="userInfo.sex" value="female"> <br/><br/>
爱好:
学习<input type="checkbox" v-model="userInfo.hobby" value="study">
打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
<br/><br/>
所属校区
<select v-model="userInfo.city">
<option value="">请选择校区option>
<option value="beijing">北京option>
<option value="shanghai">上海option>
<option value="shenzhen">深圳option>
<option value="wuhan">成都option>
select>
<br/><br/>
其他信息:
<textarea v-model.lazy="userInfo.other">textarea> <br/><br/>
<input type="checkbox" v-model="userInfo.agree">阅读并接受
<a href="https://www.yuque.com/cessstudy">《用户协议》a>
<button>提交button>
form>
div>
<script src="./vue.js">script>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
userInfo: {
account: '',
password: '',
age: 18,
sex: 'female',
hobby: [],
city: 'beijing',
other: '',
agree: ''
}
},
methods: {
demo() {
console.log(JSON.stringify(this.userInfo))
}
}
})
script>
body>
html>
对需要再模板中显示的数据进行特定格式化后再显示,适合做一些简单的逻辑
注册过滤器
全局过滤器
Vue.filter(name, callback) 全局过滤器
局部过滤器
new Vue({
filters: {
name: callback
}
})
使用过滤器
{{ xxx | 过滤器名 }}
v-bind:属性名 = ”xxx | 过滤器名“
过滤器可以接收额外参数,多个过滤器可以串联
并不是改变源数据,而是产生新的数据用于模板的展示
代码示例
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>过滤器title>
<script type="text/javascript" src="./vue.js">script>
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js">script>
head>
<body>
<div id="root">
<h2>时间h2>
<h3>当前时间戳:{{time}}h3>
<h3>转换后时间:{{time | timeFormater()}}h3>
<h3>转换后时间:{{time | timeFormater('YYYY-MM-DD HH:mm:ss')}}h3>
<h3>截取年月日:{{time | timeFormater() | mySlice}}h3>
div>
body>
<script type="text/javascript">
Vue.config.productionTip = false
// 全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,11)
})
new Vue({
el:'#root',
data:{
time:1626750147901,
},
// 局部过滤器
filters:{
timeFormater(value, str="YYYY年MM月DD日 HH:mm:ss"){
return dayjs(value).format(str)
}
}
})
script>
html>
v-bind
v-model
v-for
v-on
v-show
v-if
v-else-if
v-else
v-text
v-html
v-cloak
使用css配和v-cloak可以解决网速慢时页面展示出{{ xxx }} 的问题
示例代码
<title>v-cloak指令title>
<style>
[v-cloak] {
display:none;
}
style>
<div id="root">
<h2 v-cloak>{{ name }}h2>
div>
// 够延迟5秒收到vue.js
<script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js">script>
<script type="text/javascript">
console.log(1)
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{name:'cess'}
})
script>
v-once
v-pre
待补充
这是vue基础的最后一个内容,也是vue中最重要的内容。

需求是这样的,我想打开网页就能看到文字具有动态效果。
不使用vue周期函数的实现代码
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>练习生命周期title>
head>
<body>
<div id="app">
<h1 :style="{opacity: opacity}">欢迎就入魔鬼训练营h1>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
opacity: 1
},
})
setInterval(function () {
if (vm.opacity>0) {
vm.opacity -= 0.01
} else {
vm.opacity = 1
}
}, 16)
script>
body>
html>
使用vue钩子的实现代码
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>练习生命周期title>
head>
<body>
<div id="app">
<h1 :style="{opacity: opacity}">欢迎就入魔鬼训练营h1>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
opacity: 1
},
mounted(){
this.interval = setInterval(()=>{
if (vm.opacity > 0) {
vm.opacity -= 0.01
} else {
vm.opacity = 1
}
}, 16)
},
beforeDestroy(){
clearInterval(this.interval)
}
})
script>
body>
html>
常用的生命周期函数:
关于销毁Vue实例:
在没有类似vue这种前端框架之前,我们都是用模块化编写的前端项目的,模块化开发的缺点是依赖关系混乱,不好维护,代码复用性不高,具有很高的耦合性,代码冗余。

组件化编程具有低耦合,代码复用率高等特点:

定义
一个文件中包含有n个组件
定义
一个文件中只有1个组件
使用组件的三大步骤
1定义组件
2注册组件
3使用组件
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>创建组件title>
head>
<body>
<div id="app">
<h1>{{ title }}h1>
<person>person>
<hr>
<dog>dog>
div>
<template id="cdog">
<div>
<h1>狗详细信息h1>
<label for="dog-name">label>
<input type="text" v-model:value="name" id="dog-name"> <br>
<label for="dog-sex">label>
<input type="text" v-model:value="sex" id="dog-sex">
<button @click="showDogInfo">显示狗的信息button>
div>
template>
<script src="../js/vue.js">script>
<script>
// 第一步: 创建组件
const person = Vue.extend({
template: `
`,
data() {
return {
name: '张三',
age: 19
}
},
methods: {
showInfo() {
alert(this.name + '-' + this.age)
}
}
})
const dog = Vue.extend(
{
template: '#cdog',
data() {
return {
name: '大黄',
sex: '小公狗'
}
},
methods: {
showDogInfo() {
alert(this.name + '-' + this.sex)
}
}
}
)
// 第二步:注册组件,全局注册,对所有的vm都有效
Vue.component('person', person)
const vm = new Vue({
el: '#app',
data: {
title: '人员详细信息'
},
// 局部注册组件,只能在当前vm的容器内使用
components: {
dog,
}
})
script>
body>
html>
对上面的案例简单总结:
定义组件
普通写法
const component-name = Vue.extend({
data(){
return {
xxxx: 'yyyy'
}
}
})
简单写法
const component-name = {
data(){},
methods: {}
}
Vue.extend传入的配置项于new Vue() 传入的配置项基本相同,有两点需要注意:
Vue.extend中不能有el,因为所有的组件最终都会挂载到vm上面
Vue.extend中的data必须写成函数形式的,不可以写成对象形式的
注册组件
全局注册
Vue.component('组件名', 组件)
//例如:
Vue.component('person', person)
// 组件名是最终在模板中使用的标签名
局部注册
new Vue({
'''
components: {
组件名: 组件
}
})
// 一般组件名与组件都会定义成一样的名字,所以在局部注册的时候一般会使用简写形式
new Vue({
’‘’
components: {
组件,
}
})
使用组件
用法1
<组件名>组件名>
用法2 (需要脚手架支持,否则会有问题)
<组件名/>
注意事项
关于组件名
如果是一个单词组成
如果是多个单词组成
特别注意
组件名要尽可能回避html标签
可以在定义组件时候使用name配置项指定组件在开发者工具中呈现的名字
const cat = {
name: 'xiao-zhu-pei-qi',
template: '#ccat',
data(){
return {
msg: '我是一只小花猫'
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OyDDRgvZ-1663494649205)(D:\markdown\Vue速成手册.assets\image-20220722133451776.png)]
vm可以理解为所有组件的父组件,一个组件内部可以挂多个组件,组件是可以嵌套的,类似与数据结构中的树,vm类似于根节点

doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>组件嵌套title>
head>
<body>
<div id="app">
<app>app>
div>
<script src="../js/vue.js">script>
<script>
const student = {
name: 'student',
data() {
return {
name: '张三',
age: 11
}
},
template: `
学生信息展示
学生姓名: {{ name }}
学生年龄: {{ age }}
`,
}
const school = {
name: 'school',
data() {
return {
name: '家里蹲',
address: '蹲家里'
}
},
template: `
学校信息展示
学校名称:{{ name }}
学校地址:{{ address }}
`,
components: {
student,
}
}
const app = {
name: 'app',
template: `
{{ title }}
`,
data() {
return {
title: 'app标题'
}
},
components: {
school
}
}
const vm = new Vue({
el: '#app',
components: {
app
}
})
script>
body>
html>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o4aug9T0-1663494649206)(D:\markdown\Vue速成手册.assets\image-20220722142336299.png)]
通过const school = Vue.extend({options}),会定义一个组件,school本质上是一个VueComponent构造函数
当我们在模板中写 或者,Vue解析时会创建school的实例对象,Vue自动调用了new Component(options)
每次调用Vue.extend,都会返回一个全新的VueComponent,不同的组件是不同的对象
关于this指向:
组件配置中data函数、methods中的函数、watch中的函数、computed中的函数他们的this均是VueComponent实例对象
new Vue(options) 配置中:data函数或者对象、 methods中的函数、watch中的函数、computed中的函数他们的this均是Vue实例对象
VueComponent实例对象简称vc, Vue实例对象简称vm
组件实例对象vc可以访问到Vue原型上面的属性和方法
**VueComponent.prototype. _ _ proto _ _ === Vue.prototype **

_ _ proto _ _ 是对象特有的,负责对象的属性方法的查找,如果对象自身没有需要的属性或者方法,_ _ proto _ _会指向对象构造函数的原型对象, _ _ proto _ _的终点是null
prototype 是函数特有的,但是因为js中函数也是一种特殊的对象,所以在函数中也有 _ _ proto _ _ 这是js原型结构中很难理解的地方
单文件组件就是一个文件只有一个组件,一个文件只完成局部的功能和包装局部的静态资源,vue中单文件组件的文件后缀是.vue
定义vue中单文件组件的常规目录结构结构:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2022/7/22 14:49 114 app.vue
-a---- 2022/7/22 14:49 132 index.html
-a---- 2022/7/22 14:48 0 main.js
-a---- 2022/7/22 14:49 117 school.vue
-a---- 2022/7/22 14:49 118 student.vue
school.vue
学校名称:{{name}}
学校地址:{{address}}
student.vue
学生姓名:{{name}}
学生年龄:{{age}}
App.vue
main.js
import App from './App.vue'
new Vue({
template:` `,
el:'#root',
components:{App}
})
index.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>单文件组件练习title>
head>
<body>
<div id="root">div>
<script src="../../js/vue.js">script>
<script src="./main.js">script>
body>
html>
vue-cli(vue脚手架)是vue官方提供的标准化开发平台
目前最新 的版本是5.x
配置淘宝镜像cnpm (这一步不是必须的,主要为了安装扩展包时候加速的)
npm config set register http://registry.npm.taobao.org
全局安装@vue/cli
npm install -g @vue/cli
切换到需要创建项目的目录,创建一个空的vue项目
vue create xxx // xxx是项目名称
选择使用的vue版本
选择vue2,等待下载安装依赖包,这里需要联网
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DAbFV7wu-1663494649206)(D:\markdown\Vue速成手册.assets\image-20220722150357812.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ab37CKoo-1663494649207)(D:\markdown\Vue速成手册.assets\image-20220722150416187.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-slE6bzIt-1663494649207)(D:\markdown\Vue速成手册.assets\image-20220722150523086.png)]
表示成功创建了项目。
启动项目
npm run serve // 注意这里是serve 不是server
打包项目
npm run build // 用于生产环境的打包
停止运行的测试服务器
Ctrl+C
vue脚手架隐藏了所有webpack相关的配置,若想查看具体的webpack配置,请执行vue inspect > output.js
output.js只能用于查看配置项,在output.js中修改配置并不能改变vue的配置项
.文件目录
├── node_modules
├── public
│ ├── favicon.ico: 页签图标
│ └── index.html: 主页面
├── src
│ ├── assets: 存放静态资源
│ │ └── logo.png
│ │── component: 存放组件
│ │ └── HelloWorld.vue
│ │── App.vue: 汇总所有组件
│ └── main.js: 入口文件
├── .gitignore: git版本管制忽略的配置
├── babel.config.js: babel的配置文件
├── package.json: 应用包配置文件
├── README.md: 应用描述文件
└── package-lock.json: 包版本控制文件
使用vue.config.js 可以对脚手架进行个性化定制
module.exports = {
pages: {
index: {
entry: 'src/index/main.js' // 入口
}
},
lintOnSave: false // 关闭语法检查
}
配置参考链接:
https://cli.vuejs.org/zh/config/#devserver-proxy
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
选择runtime版本的vue的目的是为了减少生产环境的空间,提高效率
默认情况下,vue脚手架使用的vue是runtime版本
vue.js与vue.runtime.xxx.js的区别
vue.js是完整的Vue,包含核心功能+模板解析器
vue.runtime.xxx.js,只包含核心功能,没有模板解析器
vue.runtime.xxx.js中没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去执行具体内容
// render函数的完整形式:
render(createElement){
return createElement(App)
}
ref用来给元素或子组件注册引用信息,类似于id
将ref应用在html标签上获取的是真实的DOM元素;应用在组件标签上获取的是组件实例对象vc
设置ref标识
<h1 ref="h1"> 组件间通讯 h1>
<School ref="school">School>
获取ref
this.$refs.xxx 获取ref
this.$refs 返回一个对象
App.vue
School.vue
学校信息
学校名称: {{ name }}
学校地址:{{ addr }}
props 让组件接收外部传来的数据
传递数据
<School name='清华大学' :age="122">school>
注意:这里的:age 是 v-bind:age的缩写,通过v-bind,122是一个整数类型
接收数据
方式一:
props: ['name', 'age']
方式二(限制接收到变量的类型):
props: {
name: String,
age: Number
}
方式三 (限制类型,限制必要性,设定默认值)
props:{
name: {
type: String, // 限制类型
required: true, // 必须传递
default: 'kobe' // 默认值
}
}
注意:
props是只读的,vue底层会监视props属性中的值,如果对其进行修改,不会报错,但是会提示,如果需要修改props中的值,请将props复制到data中进行修改。
demo
普通接收
<template>
<div>
<div class="first-menu">
<h1 ref="h1"> 组件间通讯 </h1>
<h3>props属性</h3>
<hr>
</div>
<div class="content">
<School ref="school" name="清华大学" addr="北京"></School>
<School ref="school" name="武汉大学" addr="武汉"></School>
<School ref="school" name="厦门大学" addr="厦门"></School>
</div>
</div>
</template>
<script>
import School from "@/components/School";
export default {
name: 'App',
components: {
School
},
}
</script>
<style>
.active {
background-color: cornflowerblue;
}
.content {
position: absolute;
left: 200px;
}
</style>
School.vue
学校信息
学校名称: {{ name }}
学校地址:{{ addr }}
限制变量类型接收
<template>
<div>
<h4 ref="info">学校信息</h4>
<p>学校名称: {{ name }}</p>
<p>学校地址:{{ addr }} </p>
<hr>
</div>
</template>
<script>
export default {
name: "School",
data() {
return {}
},
props: {
name: String,
addr: Number // 如果传递的不是数字型,报下方错误
}
}
</script>
<style scoped>
</style>
// Vue warn]: Invalid prop: type check failed for prop "addr". Expected Number with value NaN, got String with value "北京".
限制类型、必要性、默认值
<template>
<div>
<h4 ref="info">学校信息</h4>
<p>学校名称: {{ name }}</p>
<p>学校地址:{{ addr }} </p>
<hr>
</div>
</template>
<script>
export default {
name: "School",
data() {
return {}
},
props: {
name: {
type: String,
required: true,
default: '家里蹲大学'
},
addr: {
type: String,
required: true,
default: 'home'
}
}
}
</script>
<style scoped>
</style>
可以把多个组件共用的配置提取成一个混入mixin对象.
定义mixin
const xxx = {
// 公用数据
data(){....},
// 公用方法
methods: {},
// 钩子函数
created() {}
}
使用mixin
全局使用混入
Vue.mixin(xxx)
局部使用混入
mixins: ['xxx', ]
demo
src/mixin/index.js
const mixin = {
data() {
return {
'login': 'xxxx'
}
},
methods: {
Login() {
alert('登录视图')
},
Logout() {
alert('登出视图')
}
},
created() {
alert('mixin 创建组件钩子函数')
}
}
export default mixin
src/App.vue (局部导入)
登录用户: {{ login }}
src/main.js(全局导入)
import Vue from 'vue'
import App from './App.vue'
// 引入ElementUI
import ElementUI from 'element-ui'
// 引入ElementUI 全部样式
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI) // 全局使用ElementUI
Vue.config.productionTip = false
import mixin from '@/mixins'
Vue.mixin(mixin) // 全局导入
new Vue({
render: h => h(App),
}).$mount('#app')
用于提升、扩展Vue的功能
本质
包含install方法的一个对象,install的第一个参数是Vue,第二个的参数是插件使用者传递的数据
使用插件
Vue.use()
demo
src/plugin/index.js
export default {
install(Vue, x,y,z){
console.log(x,y,z)
// 全局过滤器
Vue.filter('myslice', function(value){return value.slice(0,4)})
// 定义全局指令
Vue.directive('fbind', {
// 指令与元素成功绑定时
bind(element, binding) {element.value = binding.value}
},
// 指令所在元素被插入页面时
inserted(element, binding){element.focus()}
// 指令所在的模板被重新解析时
update(element, binding){element.value = binding.value}
)
}
// 定义混入
Vue.mixin({
data(){
return {
x: 100, y:200
}
}
})
// 给Vue原型上添加一个方法(vm和vc可以用)
Vue.prototype.hello = ()=>{alert('hello plugins!')}
}
src/main.js
Vue.use(Vue, 1,2,3) // 应用插件
## 4.6 自定义事件
父组件传递数据到子组件,使用props
==**自定义事件是从子组件传递数据到父组件**==
子组件想要给父组件传递数据,要在父组件中给子组件定义自定义事件,事件回调在父组件中
- 语法
- 父组件
```vue
// 或者 v-on:customEvent="callback"
```
- 子组件
```vue
```
```js
this.$emit('customEvent') // 解绑一个自定义事件
this.$emit(['event1', 'event2']) // 解绑多个自定义事件
this.$destroy() // 销毁子组件,绑定其身上的自定义事件随着全部失效
```
- 父组件 方式2
```vue
```
- 父组件无论使用方式1还是方式2,子组件的使用方式均相同。
- 组件绑定原生事件
在原生事件后面加上==**.native**== 否则原生事件也会被当做是自定义事件。
```js
一种可以在任意组件之间通信的方式,不限于父子组件之间,本质上就是一个对象
定义全局事件总线
new Vue({
...
beforeCreate() {
Vue.prototype.$bus = this // 安装全局事件总线, $bus就是当前的vm
}
...
})
使用全局事件总线
接收数据
接收数据的组件,使用$bus.$on定义自定义数据,回调函数留在接收数据的组件中.
提供数据
提供数据的组件使用$bus.$emit()触发自定义事件
解绑当前组件中用到的所有事件,beforeDestroy()
Demo
接收数据的组件
发送数据的组件
全局事件总线相比较自定义事件总线更加灵活。
用的较少,先不展开,后面有时间在搞。
安装
npm i vuex@3 vuex目前最新版本是4版本,4版本必须使用vue3,如果使用vue2版本,必须安装vuex3,否则安装会报错
配置
在src文件下创建store目录,在目录内创建index.js
看图说话:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IludkSgi-1663494649207)(D:\markdown\Vue速成手册.assets\image-20220802231636436.png)]
// 导入Vue
import Vue from 'vue'
// 导入Vuex
import Vuex from 'vuex'
// 注册插件
Vue.use(Vuex)
const actions = { //
xxx(context, value) {
context.commit('ADD', value)
},
}
const mutations = {
ADD(state, value) {
state.sum += value
},
}
const state = {
sum: 10
}
export default new Vuex.Store({
actions,
mutations,
state
})
当前最新的vue-router版本是V4.x,V4.x版本的vue-router适用于vue3,如果使用vue2版本,请使用vue-router3.x版本
npm i vue-router@3
cnpm i vue-router@3 # 使用淘宝镜像安装,可以加速
src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import About from '../components/About'
import Home from '../components/Home'
Vue.use(VueRouter)
export default new VueRouter({
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home
}
]
})
src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router
}).$mount('#app')
src/components/App.vue
跳转标签
About
Home
组件内容展示区
src/components/About.vue
src/components/Home.vue
假设有一个图书管理系统,首页显示所有图书的列表,当点击每本图书后,显示图书的详细视图,点击不同的图书显示不同的详细视图,类似这种需求就需要给路由传参。
vue-router中路由传参有两种写法,分别是字符串写法和对象写法。
src/router/index.js
import Vue from "vue"
import VueRouter from 'vue-router'
import Detail from "@/components/Detail";
Vue.use(VueRouter)
export default new VueRouter({
routes: [
{
path: '/books',
component: Detail
}
]
})
src/App.vue
图书管理系统
ID
书名
出版社
{{ book.id }}
{{ book.name }}
{{ book.publish }}
src/components/Detail.vue
书籍详细信息
书籍名称:{{ $route.query.name }}
书籍出版社:{{ $route.query.publish }}
路由传参方式1:
<router-link :to="`/books?id=${id}&name=${name}&publish=${publish}`">跳转</router-link>
在组件中使用$route.query.name 等获取路由中传递的参数
路由传参方式2:
<router-link :to="{
path: '/books',
query: {
id: book.id,
name: book.name,
publish: book.publish
}
}">
{{ book.name }}
</router-link>
在组件中使用$route.query.name 等获取路由中传递的参数
为了简化多级路由的写法,可以在定义路由时添加一个name属性。
src/router/index.js
routes: [
{
name: 'detail',
path: '/books',
component: Detail
}
]
src/App.vue
不需要传参,to属性使用字符串拼接写法和对象写法都可以
字符串写法
<router-link :to="{name: 'detail'}">跳转</router-link>
对象写法
<router-link :to="{
name:'detail'}">
<router-link>
需要传参,to属性必须使用对象写法
<router-link :to="{
name:'detail',
query: {
id: '01',
name: '水浒传',
publish: '中国出版社'
}
}">
<router-link>
query传参是在跳转时传递参数,类似get请求传参,将参数通过?链接到url后面,通过&符号链接多个key-value.
http://127.0.0.1:8000/books?id=1&name=水浒传
id和name就会传递给/books路由对应组件的$router.query中。
params在定义路由的时候就要确定要传递的参数,在path中使用占位符声明接收params参数,如果使用params传参,to的对象写法不能使用path属性,必须使用name属性。
src/router/index.js
import Vue from "vue"
import VueRouter from 'vue-router'
import Detail from "@/components/Detail";
Vue.use(VueRouter)
export default new VueRouter({
routes: [
{
name: 'detail',
path: '/books/:id/:name/:publish', // 使用:占位符对需要传递的参数占位
component: Detail
}
]
})
src/App.vue
'''
{{ book.name }}
'''
再次重申,如果to使用对象写法,必须使用命名路由,不能使用path
'''
{{ book.name }}
'''
src/component/Detail.vue
使用$route.params.xxx接收路由中的params参数
书籍详细信息
书籍ID:{{ $route.params.id }}
书籍名称:{{ $route.params.name }}
书籍出版社:{{ $route.params.publish }}
props可以让路由更方便接收到参数:
{
name:'detail',
path:'books/:id/:name/:publish',
component:Detail,
//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
// props:{a:900}
//第二种写法:props值为布尔值,为true时,则把路由收到的所有params参数通过props传给Detail组件
// props:true
//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
props($route){
return {
id: $route.query.id,
title: $route.query.title
}
}
}
src/route/index.js
import Vue from "vue"
import VueRouter from 'vue-router'
import Detail from "@/components/Detail";
Vue.use(VueRouter)
export default new VueRouter({
routes: [
{
name: 'detail',
path: '/books/:id/:name/:publish',
component: Detail,
// 写法1:对象写法
// props: {
// hello: 'world'
// }
// 写法2: 布尔值
//props: true
// 写法3: 函数写法
props($route){
return {
xixi:$route.params.id,
haha:$route.params.name,
xxoo: $route.params.publish
}
}
}
]
})
/src/components/Detail.vue
书籍详细信息
书籍ID:{{ xixi }}
书籍名称:{{ haha }}
书籍出版社:{{ xxoo }}
{ hello }}-->
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JXxXgPPA-1663494649207)(D:\markdown\Vue速成手册.assets\image-20220917172112078.png)]
在浏览器左上角一般都会有两个箭头,分别表示“向前"和"向后".
浏览器的路由缓存类似于一个栈,有两种存储地址的方式:
replace 方式:
<router-link :replace=true>Name</router-link>
// 简写方式
<router-link replace>Name</router-link>
push方式(默认):
不借助实现路由跳转,让路由跳转更加灵活
this.$router.push({})
this.$router.replace({})
this.$router.forward() // 前进
this.$router.back() // 后退
this.$router.go(n) // 可前进也可后退,正数为前进,负数为后退
push和replace里面的参数和to相同:
this.$router.push({
name: 'router name'
})
Test push&replace
{{ book.title }}
图书详情信息
图书编号: {{ id }}
图书名称: {{ title }}
默认情况下:路由组件被切换后,会被vue销毁,所以在该组件中的数据都将被清除。
keep-alive 标签可以将组件缓存,不被销毁,所以在路由切换后能够保存组件中的数据。
缓存一个组件
include 属性中填写组件名
<keep-alive include="Python">
<router-view></router-view>
</keep-alive>
缓存多个组件
include属性中填写组件列表
注意:缓存一个组件的时候,include前面没有冒号:,缓存多个组件的时候,include前面有冒号:
<keep-alive :include="['Python', 'Java']">
<router-view></router-view>
</keep-alive>
缓存所有组件 不写include属性就代表缓存所有
activated
路由组件被激活时触发
deactivated
路由组件失活时触发
Python学科
人生苦短,我用Python
对路由权限进行控制
路由配置中通过:meta配置源信息
对所有组件都起作用
全局前置守卫:初始化时,每次路由切换前执行
router.beforeEach((to, from, next) => {
if (to.meta.requireAuth) {
let c = localStorage.getItem('class')
if (c === 'v') {
next()
} else {
alert('无权访问')
next(false)
}
} else {
next()
}
})
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dYvPKB9A-1663494649208)(D:\markdown\Vue速成手册.assets\image-20220918093757914.png)]
全局后置守卫:初始化时,每次路由切换后执行
router.afterEach((to, from)=>{
document.title = to.meta.title
})
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cyq5sdyx-1663494649208)(D:\markdown\Vue速成手册.assets\image-20220918093838110.png)]
小结
to,from,next三个参数都是必要的
to:即将要进入的目标 路由对象
from:当前导航正要离开的路由
next:一定要调用该方法来处理这个钩子,如果不写next()或者next(false),页面路由不会跳转,也就是页面被阻止在当前页面了
to,from是一个对象,就是 routes[] 数组里面配置的某个具体的路由对象,
比如:to.path, to,name, to.meta 或 from.path, from.name, from.meta 【path,name,meta】这些字段都是自己在路由里面定义的字段,这样就可以开始写逻辑了。
next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
对某个组件起作用,你可以在路由配置上直接定义 beforeEnter 守卫:
参数与全局前置守卫相同:
{
path: '/class',
name: 'class',
meta: {
requireAuth: true,
title: 'Class'
},
component: Class,
children: [
{
path: 'python',
name: 'python',
component: Python,
beforeEnter: (to, from, next)=>{
if (localStorage.getItem('class') === 'v1'){
next()
}else{
alert('无权访问')
next(false)
}
}
},
]
}
通过路由匹配后,进入路由组件时守卫
beforeRouteEnter((to, from, next)=>{})
离开路由组件时守卫
beforeRouteLeave((to, from, next)=>{})
hash
地址中有#号
地址中#号后面的值不会出现在http请求中
兼容性好
不美观
app检验严格的情况会被标记为不合法
history
地址干净、美观
兼容性比hash差
可能会出现404报错,因为路径中的数据会被发送到后端
设置模式
const router = new VueRouter({
mode: 'history' or 'hash'
})
cnpm i element-ui -S
src/main.js
import Vue from 'vue'
import App from './App.vue'
// 引入ElementUI
import ElementUI from 'element-ui'
// 引入ElementUI 全部样式
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI) // 全局使用ElementUI
new Vue({
render: h => h(App),
}).$mount('#app')
src/App.vue
npm i babel-plugin-component -D
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
["@babel/preset-env", { "modules": false }]
],
plugins: [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
src/main.js
import Vue from 'vue'
import App from './App.vue'
import { Button,Row } from 'element-ui' // 按需引入
Vue.config.productionTip = false
Vue.component(Button.name, Button);
Vue.component(Row.name, Row);
/* 或写为
* Vue.use(Button)
* Vue.use(Row)
*/
new Vue({
el:"#app",
render: h => h(App),
})
一般如果对性能要求不是太苛刻的话都会选择全局配置
setItem
localStorage.setItem('k1', 'v1')
getItem
localStorage.getItem('k1')
'v1'
length 属性
localStorage.length
1
getItem
localStorage.getItem('k2')
'v2'
clear 清楚所有存储
localStorage.clear()
localStorage.removeItem
localStorage.removeItem('k1')
API与localStorage相同
- setItem(key, value)
- getItem(key)
- removeItem(key)
- length
- clear() 清空所有的会话存储
解决方式1:
在vue.config.js中添加关闭语言检查功能
const {defineConfig} = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false /*关闭语法检查*/
})
解决方式2:
按照要求修改组件名
问题原因: 导出和导入模块的方式不对
正确的处理方式:
格式一 变量形式 --暴露
export default {
router
}
--接收
import {router} from './router'
格式二 直接暴露
export default router
接收
import router from './router'