Vue笔记
Vue简介
官网
- 英文官网: https://vuejs/
- 中文官网: https://cn.vuejs/
介绍与描述
- 动态构建用户界面的渐进式 JavaScript 框架
- 作者: 尤雨溪
Vue的特点
- 遵循MVVM模式
- 编码简介,体积小,运行效率高,适合移动/PC端开发
- 它只关注UI,也可以引入其他啊大三方库开发项目
与其他JS框架的关联
- 借鉴了Angular的模板和数据绑定技术
- 借鉴了React的组件化和虚拟DOM技术
. Vue 周边库
-
vue-cli: vue 脚手架
-
vue-resource
-
axios
-
vue-router: 路由
-
vuex: 状态管理
-
element-ui: 基于 vue 的 UI 组件库
…
初始Vue
<!-- 准备好一个容器 -->
<div id="demo">
<h1>Hello,{{name.toUpperCase()}},{{address}}</h1>
</div>
<script type="text/javascript" >
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
//创建Vue实例
new Vue({
el:'#demo', //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串。
data:{ //data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象。
name:'atguigu',
address:'北京'
}
})
</script>
总结:
- 想让Vue工作就必须创建一个Vue实例,且要传入一个配置对象;
- root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法;
- root容器里的代码被称为【Vue模板】;
- Vue实例和容器是一一对应的关系;
- 真实开发中只有一个Vue实例,并且会配合着组件一起使用
- {{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性;
- 一旦data中的数据发生改变,那么页面中用到数据的地方也会自动更新;
注意区分:js表达式和js代码(语句)
表达式:一个表达式会产生一个值,可以放在任何一个需要值得地方:
(1). a
(2). a+b
(3). demo(1)
(4). x === y ? ‘a’ : ‘b’
- js代码(语句)
(1). if(){}
(2). for(){}
模板语法
<!-- 准备好一个容器-->
<div id="root">
<h1>插值语法</h1>
<h3>你好,{{name}}</h3>
<hr/>
<h1>指令语法</h1>
<a v-bind:href="school.url.toUpperCase()" x="hello">点我去{{school.name}}学习1</a>
<a :href="school.url" x="hello">点我去{{school.name}}学习2</a>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
data:{
name:'jack',
school:{
name:'尚硅谷',
url:'http://www.atguigu',
}
}
})
</script>
总结:
- 插值语法
功能:用于解析标签体内容
写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性
- 指令语法:
功能:用于解析标签(包括:标签属性、标签体内容、绑定事件)
举例:v-bind:href=“xxx” 或 简写为 :href=“xxx”,xxx同样要写js表达式,
且可以直接读取到data中的所有属性。
备注:Vue中有很多的指令,且形式都是:v-???,此处我们只是拿v-bind举个例子。
数据绑定
Vue中有2中数据绑定的方式
单项数据绑定(v-bind):数据只能从data流向页面
双向绑定(v-model):数据不仅能从data流向页面。还可以从页面流向data
备注:
- 双向绑定一般都应用在表单元素上(如input、select) v-bind简写为
冒号 :
- v-model:value可以简写为 v-model,因为v-model默认收集的就是value值
<!-- 准备好一个容器-->
<div id="root">
<!-- 普通写法 -->
<!-- 单向数据绑定:<input type="text" v-bind:value="name"><br/>
双向数据绑定:<input type="text" v-model:value="name"><br/> -->
<!-- 简写 -->
单向数据绑定:<input type="text" :value="name"><br/>
双向数据绑定:<input type="text" v-model="name"><br/>
<!-- 如下代码是错误的,因为v-model只能应用在表单类元素(输入类元素)上 -->
<!-- <h2 v-model:x="name">你好啊</h2> -->
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
data:{
name:'尚硅谷'
}
})
</script>
data与el的2种写法
el有2中写法
- new Vue时候配置el属性
- 先创建Vue实例,随后在通过vm. m o u n t ( ′ mount(' mount(′root’)指定el的值
data有2种写法:
对象式
函数式
如何选择:目前写那种都可以,但是在组件中data必须使用函数式。否则报错
由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了
<script type="text/javascript">
//el的两种写法
/* const v = new Vue({
//el:'#root', //第一种写法
data:{
name:'尚硅谷'
}
})
console.log(v)
v.$mount('#root') //第二种写法 */
//data的两种写法
new Vue({
el:'#root',
//data的第一种写法:对象式
/* data:{
name:'尚硅谷'
} */
//data的第二种写法:函数式
data(){
console.log('@@@',this) //此处的this是Vue实例对象
return{
name:'尚硅谷'
}
}
})
</script>
MVVM模型
1、M:模型(Model):对应data中数据
2、V:视图(View):模板代码
3、VM:视图模型(ViewModel):Vue实例对象
观察发现:
1.data中所有的属性,最后都出现在了vm身上。
2.vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接使用。
数据代理
<script type="text/javascript" >
let number = 18
let person = {
name:'张三',
sex:'男',
}
Object.defineProperty(person,'age',{
// value:18,
// enumerable:true, //控制属性是否可以枚举,默认值是false
// writable:true, //控制属性是否可以被修改,默认值是false
// configurable:true //控制属性是否可以被删除,默认值是false
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
get(){
console.log('有人读取age属性了')
return number
},
//当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
set(value){
console.log('有人修改了age属性,且值是',value)
number = value
}
})
</script>
数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)
<script type="text/javascript" >
let obj = {x:100}
let obj2 = {y:200}
Object.defineProperty(obj2,'x',{
get(){
return obj.x
},
set(value){
obj.x = value
}
})
</script>
总结:
- Vue中的数据代理:通过vm对象来代理对象中属性的操作(读写)
- Vue中数据代理的好处:更加方便的操作data中的数据
- 基本原理:通过Object.defineProperty()把data对象中所有属性添加到vm。为每一个添加vm上的属性,都指定一个getter/setter。在getter/setter内部去操作(读/写)data中对应的属性
事件处理
事件的基本使用
<div id="root">
<h2>欢迎来到{{name}}学习</h2>
<!-- <button v-on:click="showInfo">点我提示信息</button> -->
<button @click="showInfo1">点我提示信息1(不传参)</button>
<button @click="showInfo2($event,66)">点我提示信息2(传参)</button>
</div>
</body>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
name:'尚硅谷',
},
methods:{
showInfo1(event){
// console.log(event.target.innerText)
// console.log(this) //此处的this是vm
alert('同学你好!')
},
showInfo2(event,number){
console.log(event,number)
// console.log(event.target.innerText)
// console.log(this) //此处的this是vm
alert('同学你好!!')
}
}
})
事件的基本使用:
- 使用v-on:xxx或@xxx绑定事件,其中xxx是事件名
- 事件的回调需要配置在methods对象,最终会在vm上
- methods中配置的函数,不要用箭头函数!否则this不是vm
- methods中的配置的函数,都是Vue所管理的函数,this的指向是vm或实例对象;
- @click=“demo” 和 @click=“demo($event)” 效果一致 但是后者可以传参
事件修饰
Vue中事件修饰符:
- prevent:阻止默认行为(常用)
- stop:阻止事件冒泡(常用)
- once:事件只触发一次(常用)
- capture:使用事件的捕获模式
- self:只有event.target是当前操作的元素是才触发事件
- passive:事件的默认行为立即执行,无需等待事件回调执行完毕
<div id="root">
<h2>欢迎来到{{name}}学习</h2>
<!-- 阻止默认事件(常用) -->
<a href="http://www.atguigu" @click.prevent="showInfo">点我提示信息</a>
<!-- 阻止事件冒泡(常用) -->
<div class="demo1" @click="showInfo">
<button @click.stop="showInfo">点我提示信息</button>
<!-- 修饰符可以连续写 -->
<!-- <a href="http://www.atguigu" @click.prevent.stop="showInfo">点我提示信息</a> -->
</div>
<!-- 事件只触发一次(常用) -->
<button @click.once="showInfo">点我提示信息</button>
<!-- 使用事件的捕获模式 -->
<div class="box1" @click.capture="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">
div2
</div>
</div>
<!-- 只有event.target是当前操作的元素时才触发事件; -->
<div class="demo1" @click.self="showInfo">
<button @click="showInfo">点我提示信息</button>
</div>
<!-- 事件的默认行为立即执行,无需等待事件回调执行完毕; -->
<ul @wheel.passive="demo" class="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
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>
键盘事件
- Vue中常用的按键别名:
- 回车 enter
- 删除 delete (捕获删除和退格删除)
- 退出 esc
- 空格 space
- 换行 tab (特殊,必须培训keydown)去使用
- 上 up
- 下 down
- 左 left
- 右 right
- Vue提供别名的按键,可以使用按键原始的key值去绑定,但注意转为kebab-case(短横线命名)
- 系统修饰键(用法特殊):ctrl 、alt、shift、meta
- 配合keyup使用:按下休时间的同时,同时在按下其他键,随后释放其他键,事件才被触发
- 配合keydown使用:正常触发
- 也可以使用keyCode去指定具体的按键(不推荐)
- Vue.config.keyCodes.自定义键名 = 键码 可以去定制按键别名
<!-- 准备好一个容器-->
<div id="root">
<h2>欢迎来到{{name}}学习</h2>
<input type="text" placeholder="按下回车提示输入" @keydown.huiche="showInfo">
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
Vue.config.keyCodes.huiche = 13 //定义了一个别名按键
new Vue({
el:'#root',
data:{
name:'尚硅谷'
},
methods: {
showInfo(e){
// console.log(e.key,e.keyCode)
console.log(e.target.value)
}
},
})
计算属性与watch监听
计算属性:
- 定义:要用的属性不存在,要通过已有的属性得来
- 原理:底层借助了Object.defineProperty()方法来提供getter/setter
- get函数什么时候执行?
- 初次读取会执行一次。
- 当一来的数据发生改变时会被再次调用
- 优势:与method实现相比,内部有一个缓存机制(复用),效率高,调式方便
- 备注:
- 计算属性最终会出现在vm上,直接读取使用即可
- 如果计算属性要被修改,那么必须set函数去响应修改,且set中要引起计算时用来的数据法还是能改变
<div id="root">
姓:<input type="text" v-model="firstName"> <br/><br/>
名:<input type="text" v-model="lastName"> <br/><br/>
测试:<input type="text" v-model="x"> <br/><br/>
全名:<span>{{fullName}}</span> <br/><br/>
全名:<span>{{fullName}}</span> <br/><br/>
全名:<span>{{fullName}}</span> <br/><br/>
全名:<span>{{fullName}}</span> <br/><br/>
//虽然上面写了四个fullName 但是fullName的get只调用了一次 因为有一个缓存的效果
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三',
x:'你好'
},
methods: {
demo(){
}
},
computed:{
fullName:{
//get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
//get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
get(){
console.log('get被调用了')
// console.log(this) //此处的this是vm
return this.firstName + '-' + this.lastName
},
//set什么时候调用? 当fullName被修改时。
set(value){
console.log('set',value)
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
},
computed:{
//完整写法
/* fullName:{
get(){
console.log('get被调用了')
return this.firstName + '-' + this.lastName
},
set(value){
console.log('set',value)
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
} */
//简写
fullName(){
console.log('get被调用了')
return this.firstName + '-' + this.lastName
}
}
})
}
})
</script>
watch监听
天气案例普通方法
<div id="root">
<h2>今天天气很{{info}}</h2>
<!-- 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句 -->
<!-- <button @click="isHot = !isHot">切换天气</button> -->
<button @click="changeWeather">切换天气</button>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
isHot:true,
},
computed:{
info(){
return this.isHot ? '炎热' : '凉爽'
}
},
methods: {
changeWeather(){
this.isHot = !this.isHot
}
},
})
天气案例watch监听和深度 监听
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click="changeWeather">切换天气</button>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
isHot:true,
},
computed:{
info(){
return this.isHot ? '炎热' : '凉爽'
}
},
methods: {
changeWeather(){
this.isHot = !this.isHot
}
},
/* watch:{
isHot:{
immediate:true, //初始化时让handler调用一下
//handler什么时候调用?当isHot发生改变时。
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
}
} */
})
vm.$watch('isHot',{
#加上deep:true 可以实现深度监听
deep:true
immediate:true, //初始化时让handler调用一下
//handler什么时候调用?当isHot发生改变时。
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
})
watch:{
//正常写法
/* isHot:{
// immediate:true, //初始化时让handler调用一下
// deep:true,//深度监视
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
}, */
//简写
/* isHot(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue,this)
} */
}
})
//正常写法
/* vm.$watch('isHot',{
immediate:true, //初始化时让handler调用一下
deep:true,//深度监视
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
}) */
//简写
/* vm.$watch('isHot',(newValue,oldValue)=>{
console.log('isHot被修改了',newValue,oldValue,this)
}) */
监视属性watch:
- 当被监视的属性变化时,回调函数自动调用,进行相关的操作
- 监视的属性必须存在,才能进行监视
- 监视的两种方法:
- new Vue时传入watch配置
- 通过vm.$watch监视
深度监视:
- Vue中的watch默认不检测对象内布值的改变(一层)
- 配置deep:true可以监测独享内部值得改变(多层)
备注:
- Vue自身可以监测对象内布值的改变,但Vue提供的watch方法,默认不监测数据的改变
- 使用watch时根据数据的具体结构,决定是否采用深度监视
watch和computed的区别
watch和computed之间的区别:
- computed能完成的功能,watch都可以完成
- watch能完成的功能,computed不一定能完成,例如watch可以进行异步操作
两个重要的小原则:
- 所有Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象
- 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数、Promise的回调函数), 最好写成箭头函数,这样this的指向才是vm或组件实例对象
绑定样式
<!-- 准备好一个容器-->
<div id="root">
<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
<div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/><br/>
<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
<div class="basic" :class="classArr">{{name}}</div> <br/><br/>
<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
<div class="basic" :class="classObj">{{name}}</div> <br/><br/>
<!-- 绑定style样式--对象写法 -->
<div class="basic" :style="styleObj">{{name}}</div> <br/><br/>
<!-- 绑定style样式--数组写法 -->
<div class="basic" :style="styleArr">{{name}}</div>
</div>
</body>
<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]
}
},
绑定样式:
- class样式
- 写法 :class=“xxx” xxx可以使字符串、对象、数组
- 字符串写法适用于:类名不确定,要动态获取
- 对象写法适用于:要绑定等多个样式,个数不确定,名字也不确定
- 数组写法使用,要绑定多个样式,个数确定,名字也确定,但不确定用不用
- style样式
- :style ="{fontSize:xxx}"其中xxx是动态值
- :style = "[a,b]"其中是样式对象
条件渲染
条件渲染:
v-if
v-if=“表达式”
v-else-if =“表达式”
v-else =“表达式”
适用于:切换频率较低的场景
特点:不展示的DOM元素直接被移除
注意:v-if可以和 v-else-if、v-else一起使用,但要求结构不能被打断
v-show
写法:v-show=“表达式”
适用于:切换频率较高的场景
特点:不展示的DOM元素未被移除,仅仅是使用display隐藏掉
备注
使用v-if的时候,元素可能无法获取到,而是用v-show一定可以获取到
<!-- 准备好一个容器-->
<div id="root">
<h2>当前的n值是:{{n}}</h2>
<button @click="n++">点我n+1</button>
<!-- 使用v-show做条件渲染 -->
<!-- <h2 v-show="false">欢迎来到{{name}}</h2> -->
<!-- <h2 v-show="1 === 1">欢迎来到{{name}}</h2> -->
<!-- 使用v-if做条件渲染 -->
<!-- <h2 v-if="false">欢迎来到{{name}}</h2> -->
<!-- <h2 v-if="1 === 1">欢迎来到{{name}}</h2> -->
<!-- v-else和v-else-if -->
<!-- <div v-if="n === 1">Angular</div>
<div v-else-if="n === 2">React</div>
<div v-else-if="n === 3">Vue</div>
<div v-else>哈哈</div> -->
<!-- v-if与template的配合使用 -->
<template v-if="n === 1">
<h2>你好</h2>
<h2>尚硅谷</h2>
<h2>北京</h2>
</template>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el:'#root',
data:{
name:'尚硅谷',
n:0
}
})
列表渲染
基础列表渲染
v-for指令:
- 用于展示列表数据
- 语法:v-for=“(item,index) in xxx” :key=“yyy”
- 可遍历:数组、对象、字符串、指定次数
<!-- 准备好一个容器-->
<div id="root">
<!-- 遍历数组 -->
<h2>人员列表(遍历数组)</h2>
<ul>
<li v-for="(p,index) of persons" :key="index">
{{p.name}}-{{p.age}}
</li>
</ul>
<!-- 遍历对象 -->
<h2>汽车信息(遍历对象)</h2>
<ul>
<li v-for="(value,k) of car" :key="k">
{{k}}-{{value}}
</li>
</ul>
<!-- 遍历字符串 -->
<h2>测试遍历字符串(用得少)</h2>
<ul>
<li v-for="(char,index) of str" :key="index">
{{char}}-{{index}}
</li>
</ul>
<!-- 遍历指定次数 -->
<h2>测试遍历指定次数(用得少)</h2>
<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>
key的作用
react、Vue中的key有什么作用?
- 虚拟DOM中key的作用:
key是虚拟DOM对象的标识
,当数据发生变化的时候,Vue会根据新数据生成新的虚拟DOM,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,对比规则如下
- 对比规则
- 旧虚拟DOM中找到了新虚拟DOM相同的key
- 若虚拟DOM中内容没有改变,直接使用之前的真实DOM
- 若虚拟DOM中内容变了,则生成新的真实DOM
- 旧虚拟DOM未找到与新虚拟DOM相同的key
- 创建新的真是DOM,随后渲染到页面。
- 用index作为key可能引发的问题
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作
- 会产生没有没必要的的真实DOM更新 界面效果没问题 但效率低
- 如果结构中还包含输入类的DOM:
- 会产生错误的DOM更新 界面有问题
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作
- 开发中如何选择key?:
- 最好使用每一条数据的唯一标识作为key,比如id、手机号、学号等唯一值
- 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表展示,使用index作为key是没有问题的。
- 当没有key是,默认是以index 做为虚拟DOM的表示
- 旧虚拟DOM中找到了新虚拟DOM相同的key
<div id="root">
<!-- 遍历数组 -->
<h2>人员列表(遍历数组)</h2>
<button @click.once="add">添加一个老刘</button>
<ul>
<li v-for="(p,index) of persons" :key="index">
{{p.name}}-{{p.age}}
<input type="text">
</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}
]
},
methods: {
add(){
const p = {id:'004',name:'老 刘',age:40}
this.persons.unshift(p)
}
},
})
</script>
Vue监视数据的原理:
- vue会监视data中所有层次的数据
- 如何监测对象中的数据?
- 通过setter实现监视,且要在new Vue时就传入要监测的数据
- 对象中后追加的属性,Vue默认不坐响应式处理
- 如需给狗添加的属性做响应式,请使用一下API:
- Vue.set*(target,propertyName/index,index) 或者 vm$set(target,propertyName/index,value)
- 如何监测数据中的数据
- 通过包裹数组更新元素的方法实现,本质就是做了两家事情:
- 调用原生对应的方法对数组进行更新
- 重新解析模板,进而跟心页面
- 在Vue修改数据中的某一个元素一定要用如下的方法:
- 使用这些API:push()、 pop() shift() unshift() splice() sort() reverse()
- Vue.set() 或 vm.$set()
特别注意:
Vue.set() 和vm.$set() 不能给vm或vm的根对象添加属性!!!
收集表单数据
收集表单数据:
若:,则v-model收集的是value值,用户输入的就是value值
若:,则v-model收集的是value值,且标签配置value值
若:
- 没有配置input的value属性,name收集的就是checked(勾选 or 未勾选,就是布尔值)
- 配置input的value属性
- v-model的初始值是非数组,name收集的就是checked(勾选 or 未勾选 是布尔值)
- v-model的初始值是数组,name收集的就是value组成的数组
v-model的三个修饰符:
- lazy:失去焦点再收集数据
- number:数组的字符串转化为有效的数字
- trim:去除空格
<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="http://www.atguigu">《用户协议》</a>
<button>提交</button>
</form>
</div>
</body>
<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>
过滤器
过滤器定义:
对要显示的数据进行格式化以后再显示(时候用一些简单的逻辑)
语法:
- 注册过滤器:Vue.filter(name,callback) 或 new Vue{filter:{}}
- 使用过滤器:{{xxx | 过滤器}} 或 v-bind:属性 = “xxx | 过滤器的名”
备注:
- 过滤器也可以接收额外的参数,多个过滤器也可以串联
- 并没有改变原本的数据,是产生的对应的数据
内置指令
-
v-bind:单向绑定解析表达式,可简写为:xxx
-
v-model:双向数据绑定
-
v-for:遍历数组/对象、字符串
-
v-on: 绑定事件事件
-
v-if:条件渲染(动态控制节点是否存在)
-
v-else:条件渲染(恫恐控制节点是否存在)
-
v-show:条件渲染(动态控制节点是否展示)
-
v-text: 向所在的节点渲染文本内容
-
v-html:向指定接地那渲染包含html结构的内容
(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
(2).v-html可以识别html结构。
严重注意:v-html有安全性问题!!!!
(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
v-cloak指令(没有值):
本质上是一个特殊的属性,Vue实例创建完毕接管容器后,会删掉v-cloak属性。 使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
v-once指令:
1.v-once所在节点初次动态渲染后,就是为静态内容了。
2.以后数据的改变不会引起v-once所在的更新,可以用于优化性能
v-pre指令:
跳过所在节点的编译过程可以利用它跳过:没有使用指令语法、没有插值语法的节点,会加快编译速度
自定义指令
自定义指令总结:
一、定义语法:
(1).局部指令:
new Vue({ new Vue({
directives:{指令名:配置对象}
或directives{指令名:回调函数}
}) })
(2).全局指令:
Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数)
二、配置对象中常用的3个回调:
(1).bind:指令与元素成功绑定时调用。
(2).inserted:指令所在元素被插入页面时调用。
(3).update:指令所在模板结构被重新解析时调用。
三、备注:
1.指令定义时不加v-,但使用时要加v-;
2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
<!-- 准备好一个容器-->
<div id="root">
<h2>{{name}}</h2>
<h2>当前的n值是:<span v-text="n"></span> </h2>
<!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2> -->
<h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
<button @click="n++">点我n+1</button>
<hr/>
<input type="text" v-fbind:value="n">
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
//定义全局指令
/* Vue.directive('fbind',{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
}) */
new Vue({
el:'#root',
data:{
name:'尚硅谷',
n:1
},
directives:{
//big函数何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。
/* 'big-number'(element,binding){
// console.log('big')
element.innerText = binding.value * 10
}, */
big(element,binding){
console.log('big',this) //注意此处的this是window
// console.log('big')
element.innerText = binding.value * 10
},
fbind:{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
}
}
})
声明周期钩子函数
生命周期:
- 又名:生命周期回调函数、生命周期函数、声明周期钩子
- 是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数
- 生命周期函数的名字不可更改,但函数的具体内容是程序根据需求编写的
- 生命周期函数中的this指向是vm或组件实例对象
常用的声明周期钩子函数:
- mounted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
- beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】
关于销毁Vue实例
- 销毁后借助Vue开放工具看不到任何信息。
- 销毁后自定义事件会失效,但原生DOM事件依然有效
- 一般不会在beforeDestory操作数据,因为即便操作数据,也不会触发更新流程
非单文件组件
Vue中使用组件的三大步骤:
一、定义组件(创建组件)
二、注册组件
三、使用组件(写组件标签)
一、如何定义一个组件?适应Vue.extend(options)创建,其中options时传入的那个options传入的那个options集合一样,但也优点区别;
区别去下:
- 不要写el,最终所有的组件要经过一个vm的管理,由vm的决定服务哪个容器
- data必须写成函数,避免组件被复用时,数据存在引用关系
备注:使用template可以配置组件结构
二、如何注册侧组件
- 局部注册?靠new Vue的时候传入components选项
- 去哪聚注册:靠Vue。component(‘组件名’,组件)
三、编写组件标签:
几个注意点:
1.关于组件名:
一个单词组成:
第一种写法(首字母小写):school
第二种写法(首字母大写):School
多个单词组成:
第一种写法(keyba-case命名):my-school
第二种写法(CamelCase命名):MyScool(需要Vue脚手架支持)
备注:
(1).组件名尽可能回避HTML中已有的元素名称,例如: h2、H2都不行
(2).可以使用name配置项指定组件在开发工具呈现的名字。
2.关于组件标签:
第一种写法:
第二种写法:
备注:不用使用脚手架,会导致后续组件不能渲染
3.一个简写方式:
const school = Vue.extend(options) 可简写为:const school = options
关于VueConent:
- school组件本质是一个名为VueCoponent的构造函数,且不是程序员定义的,是Vue.extend生成的
- 我们只需要写或者,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(oprions).
- 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!
- 关于this指向:
- 组件配置中:
- data函数、methods中的函数、watch中的函数computed中的函数 他们的this均是【VueComponent实例对象】。
- newVue(options)配置中的:
- data函数、methods中的函数、watch中的函数、computed中的函数 他们的this均是【Vue实例对象】
- VueComponent的实例对象,以后简称vc(以后简称为:组件实例对象) Vue的实例对象 简称vm
一个重要的内置关系
1.一个重要的内置关系:VueComponent.prototype.proto === Vue.prototype
2.为什么要有这个关系:让组件实例对象(vc)可以访问到 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
- vue.js与与vue.runtime.xxxjs的区别
- vue.js是完整版的Vue,包含核心功能+模板解析器
- vue.runtime.xxx.js是运行班的Vue,只包含:核心功能;没有模板解析器
- 因为vue.runtime.xxx.js没有模板解析器,所以不能使用template这个配置,需要使用render函数接收到的createElement函数去指定具体内容。
vue.config.js配置文件
- 使用vue insect > output.js 乐意查看Vue脚手架ode默认配置
- 使用vue.config可以对脚手架进行个性化定制,详情见:https://cli.vuejs/zh
ref属性
- 被用来给元素或子组件注册引用信息(id的替代者)
- 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象
- 使用方式
- 打表示:
<h1 ref="xxx">。。。。</h1>
- 获取:this.$ref.xxx
- 打表示:
组件传参(父传子props)
- 功能:让组件接收外部传过来的数据
- 传递数据:
- 接收数据:
- 第一种方式(只接受):props:[‘name’]
- 第二种方式(限制类型):props:[name:String]
- 第三种方式(限制类型、限制必要性、指定默认值):
props:{
name:{
type:String, //类型
required:true, //必要性
default:'老王' //默认值
}
}
备注:props是制度的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,name请赋值props的内容到data中一份,然后修改data中的数据
mixin(混入:又叫抽封)
-
功能:可以吧多个组件公用的配置提取成一个混入对象
-
使用方式:
第一步定义混合:
单独写一个js文件,写好数据,导出 export const hunhe = { methods: { showName(){ alert(this.name) } }, mounted() { console.log('你好啊!') }, } export const hunhe2 = { data() { return { x:100, y:200 } }, }
插件
-
功能:用于增强Vue
-
本质上:包含install方法的一个对象,install的第一个参数是Vue,第二个参数是插件使用者传递的数据。
-
定义插件:
//定义一个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('你好啊')} } }
总结TodoLIst案例
- 组件化编流程:
- 拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突
- 实现动态组件:考虑好数据的存放的位置,数据是一个组件在用,还是一些组件在用:
- 一个组件在用:放在组件自身即可
- 一些组件在用:放在他们共同的父组件上(状态提升)
- 实现交互:从绑定事件开始。
- props使用于:
- 父组件---->子组件 通信
- 子组件---->父组件 通信(要求先给子组件一个函数)
- 使用v-model时要切记:v-model绑定的值不能是props穿过的值,因为props是不可以更改的
- props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但是不推荐这样做。
组件的自定义事件
-
一种组件间通信的方式,适用于:子组件–>父组件
-
适用场景:A是父组件,B是子组件,B想给A传数据,name就要在A中给B绑定自定义事件(事件的回调在A中)
-
绑定自定义事件:
第一种方式,父组件中:<Demo @atguigu=“test” /> 或 < Demo v-on:atgugu=“test”/>
第二种方式,在父组件中:
<Demo ref="demo"/> ...... mounted(){ this.$refs.xxx.$on('atguigu',this.test) }
弱项让自定义事件只能触发一次,可以使用once修饰符,或者$once方法
-
触发自定义事件:this.$emit(‘atghuigu’,“数据”)
-
解绑自定义事件 this.$off(‘atguigu’)
-
组件上也可以绑定原生DOM事件,需要native修饰符
-
注意:通过this. r e f s . x x x . refs.xxx. refs.xxx.on(‘atguigu’,‘回调’)绑定自定义事件时,回调要么配置在methods中,要么写成箭头函数,否则this执行那个会有问题
全局事件总线
-
一种组件通信的方式,适用于任意组件间通信
-
安装全局事件总线
new Vue({ ..... beforeCreate(){ //安装全局事件总线 $bus 就是当前应用的vm Vue.prottotype.$bus = this } ...... })
-
使用事件总线:
-
接收数据:A组件想接受数据,则A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
methods(){ demo(data){......} } ...... mounted() { this.$bus.$on('xxxx',this.demo) }
-
提供数据:this. b u s . bus. bus.emit(‘xxx’,数据)
-
-
最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。
消息定于与发布
-
一种组件间通信的方式,适用于任意组件间通信
-
使用步骤:
-
安装pubsub:
npm i pubsub-js
-
引入:
import pubsub from 'pubsub-js'
-
接收数据:A组件想接受数据,则A组件中订阅消息,定于的回调留在A组件自身
methods(){ demo(data){......} } ...... mounted() { this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息 }
-
提供数据:pubsub.publish)(‘xxx’,数据)
-
最好在beforeDestroy钩子中,用Pubsub.unsubscribe(pid)去取消订阅
-
nextTick
- 语法:
this.$nextTick(回调函数)
- 作用:在下一次 DOM 更新结束后执行其指定的回调。
- 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
Vue封装的过度与动画
-
作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。
-
写法:
-
准备好样式:
- 元素进入的样式:
- v-enter:进入的起点
- v-enter-active:进入过程中
- v-enter-to:进入的终点
- 元素离开的样式:
- v-leave:离开的起点
- v-leave-active:离开过程中
- v-leave-to:离开的终点
- 元素进入的样式:
-
使用
<transition>
包裹要过度的元素,并配置name属性:<transition name="hello"> <h1 v-show="isShow">你好啊!</h1> </transition>
-
备注:若有多个元素需要过度,则需要使用:
<transition-group>
,且每个元素都要指定key
值。
-
vue脚手架配置代理
方法一
在vue.config.js中添加如下配置:
devServer:{
proxy:"http://localhost:5000"
}
说明:
- 优点:配置简单,请求资源时直接发给前端(8080)即可。
- 缺点:不能配置多个代理,不能灵活的控制请求是否走代理。
- 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)
方法二
编写vue.config.js配置具体代理规则:
module.exports = {
devServer: {
proxy: {
'/api1': {// 匹配所有以 '/api1'开头的请求路径
target: 'http://localhost:5000',// 代理目标的基础路径
changeOrigin: true,
pathRewrite: {'^/api1': ''}
},
'/api2': {// 匹配所有以 '/api2'开头的请求路径
target: 'http://localhost:5001',// 代理目标的基础路径
changeOrigin: true,
pathRewrite: {'^/api2': ''}
}
}
}
}
/*
changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
changeOrigin默认值为true
*/
说明:
- 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
- 缺点:配置略微繁琐,请求资源时必须加前缀。
插槽
-
作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件 。
-
分类:默认插槽、具名插槽、作用域插槽
-
使用方式:
-
默认插槽:
父组件中: <Category> <div>html结构1</div> </Category> 子组件中: <template> <div> <!-- 定义插槽 --> <slot>插槽默认内容...</slot> </div> </template>
-
具名插槽:
父组件中: <Category> <template slot="center"> <div>html结构1</div> </template> <template v-slot:footer> <div>html结构2</div> </template> </Category> 子组件中: <template> <div> <!-- 定义插槽 --> <slot name="center">插槽默认内容...</slot> <slot name="footer">插槽默认内容...</slot> </div> </template>
-
作用域插槽:
-
理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)
-
具体编码:
父组件中: <Category> <template scope="scopeData"> <!-- 生成的是ul列表 --> <ul> <li v-for="g in scopeData.games" :key="g">{{g}}</li> </ul> </template> </Category> <Category> <template slot-scope="scopeData"> <!-- 生成的是h4标题 --> <h4 v-for="g in scopeData.games" :key="g">{{g}}</h4> </template> </Category> 子组件中: <template> <div> <slot :games="games"></slot> </div> </template> <script> export default { name:'Category', props:['title'], //数据在子组件自身 data() { return { games:['红色警戒','穿越火线','劲舞团','超级玛丽'] } }, } </script>
-
-
Vuex
概念
在Vue中实现集中式状态(数据)管理的Vue的一个Vue插件,对Vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间的通信方式,且使用于任意组件间通信。
何时使用?
多个组件需要共享数据时
搭建vuex环境
-
创建文件:
src/store/index.js
//引入Vue核心库 import Vue from 'vue' //引入Vuex import Vuex from 'vuex' //应用Vuex插件 Vue.use(Vuex) //准备actions对象——响应组件中用户的动作 const actions = {} //准备mutations对象——修改state中的数据 const mutations = {} //准备state对象——保存具体的数据 const state = {} //创建并暴露store export default new Vuex.Store({ actions, mutations, state })
-
在main.js 中创建vm传入store配置项
...... //引入store import store from './store' ...... //创建vm new Vue({ el:'#app', render: h => h(App), store })
基本使用
-
初始化数据、配置actions、配置mutations。操作store.js文件
//引入Vue核心库 import Vue from 'vue' //引入Vuex import Vuex from 'vuex' //引用Vuex Vue.use(Vuex) const actions = { //响应组件中加的动作 jia(context,value){ // console.log('actions中的jia被调用了',miniStore,value) context.commit('JIA',value) }, } const mutations = { //执行加 JIA(state,value){ // console.log('mutations中的JIA被调用了',state,value) state.sum += value } } //初始化数据 const state = { sum:0 } //创建并暴露store export default new Vuex.Store({ actions, mutations, state, })
-
组件中读取vuex中的数据:$store.state.sum
-
组件中修改vuex中的数据: s t o r e . d i s p a t c c h ( ′ a c t i o n 中方法 名 ′ ,数据 ) 或者 store.dispatcch('action中方法名',数据) 或者 store.dispatcch(′action中方法名′,数据)或者storemit(‘mutaions中的方法名’,‘数据’)
备注:若没有网络请求或者其他业务逻辑,组件也可以越过actions,不写dispatch,直接编写commit
getters的使用
-
概念:当state中数据需要进过加工后在使用时,可以使用getters加工
-
在
store.js
中追加getters
配置...... const getters = { bigSum(state){ return state.sum * 10 } } //创建并暴露store export default new Vuex.Store({ ...... getters })
-
组件中读取数据:$storea.getters.bigSum
四个map方法
-
MapState方法:用于帮助我们映射state中的数据
computed: { //借助mapState生成计算属性:sum、school、subject(对象写法) ...mapState({sum:'sum',school:'school',subject:'subject'}), //借助mapState生成计算属性:sum、school、subject(数组写法) ...mapState(['sum','school','subject']), },
-
mapGetters方法:用于帮助我们映射getters中的数据为计算属性
computed: { //借助mapGetters生成计算属性:bigSum(对象写法) ...mapGetters({bigSum:'bigSum'}), //借助mapGetters生成计算属性:bigSum(数组写法) ...mapGetters(['bigSum']) },
-
mapActions方法: 用于帮助我们生成actions对话的方法,即:包含
$store.dispath(xxxx)的函數
methods:{ //靠mapActions生成:incrementOdd、incrementWait(对象形式) ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'}) //靠mapActions生成:incrementOdd、incrementWait(数组形式) ...mapActions(['jiaOdd','jiaWait']) }
-
mapMutions方法: 用于帮我们生成mutaions对话的方法,即:包含
$storemit(xxx)的函数
methods:{ //靠mapActions生成:increment、decrement(对象形式) ...mapMutations({increment:'JIA',decrement:'JIAN'}), //靠mapMutations生成:JIA、JIAN(对象形式) ...mapMutations(['JIA','JIAN']), }
备注:mapActions与mapMutaions使用时,若要传递参数时,在模板中绑定事件时传递好参数,否则是事件对象
模块化+命名空间
-
目的:让代码更好维护,让多种数据分类更加明确。
-
修改store.js
const countAbout = { namespaced:true,//开启命名空间 state:{x:1}, mutations: { ... }, actions: { ... }, getters: { bigSum(state){ return state.sum * 10 } } } const personAbout = { namespaced:true,//开启命名空间 state:{ ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { countAbout, personAbout } })
-
开启命名空间后,组件中读取state数据:
//方式一:自己直接读取 this.$store.state.personAbout.list //方式二:借助mapState读取: ...mapState('countAbout',['sum','school','subject']),
-
开启命名空间后,组件中读取getters数据:
//方式一:自己直接读取 this.$store.getters['personAbout/firstPersonName'] //方式二:借助mapGetters读取: ...mapGetters('countAbout',['bigSum'])
-
开启命名空间后,组件中调用dispatch
//方式一:自己直接dispatch this.$store.dispatch('personAbout/addPersonWang',person) //方式二:借助mapActions: ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
-
开启命名空间后,组件中调用commit
//方式一:自己直接commit this.$store.commit('personAbout/ADD_PERSON',person) //方式二:借助mapMutations: ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
-
路由
- 理解:一个路由(route)就是一组映射关系(key-value),多个路由器需要路由器进行管理。
- 前端路由:key是路径,value是组件
基本使用
-
安装vue-router, 命令:
npm i vue-router@3
-
应用插件:
Vue.use(VueRouter)
-
编写router配置项:
//引入VueRouter import VueRouter from 'vue-router' //引入路由组件 import About from '../components/About' import Home from '../components/Home' //创建router 实例对象 去管理一组 路由规则 const router = new Vuerouter({ routers:[ { path:'/about', component:About }, { path:'/home', component:Home } ] }) // 暴露 touter export default router
-
实现切换(active-class可配置高亮显示)
<router-link active-class="active" to='/about'></router-link>
-
指定展示位置
<router-view></router-view>
几个注意点
- 路由组件通常存放在
pages
文件中,一般 组件通常存放在components
文件夹。 - 通过切换,“隐藏”了的路由组件,默认是被销毁的,需要的时候再去挂载。
- 每一个组件都有一个自己的
$route
属性,里面存储着自己的路由信息 - 整个应用只有一个router,可以通过组件的
$router
属性获取到
多级路由(嵌套路由)
-
配置路由规则,使用childer配置项:
routers:[ { path:'/about', component:About, }, { path:'/home', component:Home, children:[//通过children配置子级路由 //通过children配置子级路由 { path:'nes', //此处一定不要写:/news compoinent:News }, { path:'message', component:Message//此处一定不要写:/message }, } ] } ]
-
跳转(要写完整的路径)
<router-link to='/home/news'>News</router-link>
路由的query参数
-
传递参数
<router-link :to="/home/message/detail?id=666&title=你好" >跳转</router-link> //跳转并携带query出纳参数,to的对象写法 <router-link :to="{ path:'/home/message/detail', query:{ id:666, title:'你好' } }" >跳转</router-link>
-
接收参数:
$router.query.id $router.query.title
命名路由
-
作用:可以简化路由的跳转
-
如何使用
-
给路由命名
{ path:'/demo', component:Demo, children:[ { path:'test', component:Test, children:[ { name:'hello' //给路由命名 path:'welcome', component:Hello } ] } ] }
-
简化路由跳转
//简化前 需要写完整路径 <router-link to="/demo/test/welcome">跳转</router-link> //简化后 直接通过name跳转 <router-link :to="{name:'hello'}">跳转</router-link> //简化写法配合传递参数 <router-link :to="{ name:'hello', query:{ id:666, title:'你好' } }">跳转</router-link>
-
路由的params参数
-
配置路由,声明接收的参数
{ path:'/home', component:Home, children:[ { path:'news', component:News }, { component:Message, children:[ { name:'xiangqing', path:'detail/:id/:title', //使用占位符声明接收params参数 component:Detail } ] } ] }
-
传递参数
<!-- 跳转并携带params参数,to的字符串写法 --> <router-link :to="/home/message/detail/666/你好">跳转</router-link> <!-- 跳转并携带params参数,to的对象写法 --> <router-link :to="{ name:'xiangqing', params:{ id:666, title:'你好' } }" >跳转</router-link> #特别注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!
-
接收参数
$route.params.id $route.params.title
路由的props的配置
作用:让路由更方便的接收到参数
{
name:'xiangqing',
path:'detail/:id',
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
}
}
}
<router-link>
的replace属性
- 作用:控制路由跳转时操作浏览器历史记录的模式
- 浏览器的历史记录有两种方式:分别为
push
和replace
是追加历史记录,replace
是替换当前记录。路由跳转时候默认任务是push - 如何开启
replace
模式:<router-link replace .......>News</router-link>
编程式路由导航
-
作用:不借助
<router-link>
实现路由跳转,让路由跳转更加灵活 -
具体编码
//$router的两个API this.$router.push({ name:'xiangqing', params:{ id:xxx, title:xxx } }) this.$router.replace({ name:'xiangqing', params:{ id:xxx, title:xxx } }) this.$router.forward() //前进 this.$router.back() //后退 this.$router.go() //可前进也可后退
缓存路由组件
-
作用:不展示的路由组件保持挂载,不被销毁。
-
具体编码:
<keep-alive include="News"> <router-view></router-view> </keep-alive>
连个新的声明周期钩子
- 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
- 具体名字:
activated
路由组件被激活事触发deactivated
路由组件失活时触发。
路由守卫
-
作用:对路由进行权限控制
-
分类:全局守卫(
beforEach、beforeafter
)、独享守卫(beforeEnter
)、组件内守卫(beforeRouteEnter、beforeRouteLeave
) -
全局守卫
//全局前置守卫:初始化时执行、每次路由切换前执行 router.beforeEach((to,from,next)=>{ console.log('beforeEach',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则 next() //放行 }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() //放行 } }) //全局后置守卫:初始化时执行、每次路由切换后执行 router.afterEach((to,from)=>{ console.log('afterEach',to,from) if(to.meta.title){ document.title = to.meta.title //修改网页的title }else{ document.title = 'vue_test' } })
-
独享守卫
beforeEnter(to,from,next){ console.log('beforeEnter',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'atguigu'){ next() }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() } }
-
组件内守卫
//进入守卫:通过路由规则,进入该组件时被调用 beforeRouteEnter (to, from, next) { }, //离开守卫:通过路由规则,离开该组件时被调用 beforeRouteLeave (to, from, next) { }
路由器的两种工作模式
-
对于一个url来说,什么是hash值? #及其后面的内容就是hash值
-
hash值不会包含在HTTP请求中,即:hash值不会带给服务器。
-
hash模式:
- 地址永远带着#,不美观
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址被标记不合法
- 兼容性比较好
4。history模式:
- 地址干净,美观 。
- 兼容性和hash模式相比略差。
- 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。
r-link replace …>News```
编程式路由导航
-
作用:不借助
<router-link>
实现路由跳转,让路由跳转更加灵活 -
具体编码
//$router的两个API this.$router.push({ name:'xiangqing', params:{ id:xxx, title:xxx } }) this.$router.replace({ name:'xiangqing', params:{ id:xxx, title:xxx } }) this.$router.forward() //前进 this.$router.back() //后退 this.$router.go() //可前进也可后退
缓存路由组件
-
作用:不展示的路由组件保持挂载,不被销毁。
-
具体编码:
<keep-alive include="News"> <router-view></router-view> </keep-alive>
连个新的声明周期钩子
- 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
- 具体名字:
activated
路由组件被激活事触发deactivated
路由组件失活时触发。
路由守卫
-
作用:对路由进行权限控制
-
分类:全局守卫(
beforEach、beforeafter
)、独享守卫(beforeEnter
)、组件内守卫(beforeRouteEnter、beforeRouteLeave
) -
全局守卫
//全局前置守卫:初始化时执行、每次路由切换前执行 router.beforeEach((to,from,next)=>{ console.log('beforeEach',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则 next() //放行 }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() //放行 } }) //全局后置守卫:初始化时执行、每次路由切换后执行 router.afterEach((to,from)=>{ console.log('afterEach',to,from) if(to.meta.title){ document.title = to.meta.title //修改网页的title }else{ document.title = 'vue_test' } })
-
独享守卫
beforeEnter(to,from,next){ console.log('beforeEnter',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'atguigu'){ next() }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() } }
-
组件内守卫
//进入守卫:通过路由规则,进入该组件时被调用 beforeRouteEnter (to, from, next) { }, //离开守卫:通过路由规则,离开该组件时被调用 beforeRouteLeave (to, from, next) { }
路由器的两种工作模式
-
对于一个url来说,什么是hash值? #及其后面的内容就是hash值
-
hash值不会包含在HTTP请求中,即:hash值不会带给服务器。
-
hash模式:
- 地址永远带着#,不美观
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址被标记不合法
- 兼容性比较好
4。history模式:
- 地址干净,美观 。
- 兼容性和hash模式相比略差。
- 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。
更多推荐
Vue笔记-尚硅谷-Alex
发布评论