1.内置指令
v-if
<div v-if="n === 1">Angular</div>
<div v-else-if="n === 2">React</div>
<div v-else>Vue</div>
v-for
<li v-for="(p,index) in persons" :key="index">
{{p.name}}-{{p.age}}
</li>
key的作用原理:
·
旧虚拟DOM中找到了与新虚拟DOM相同的key:
若虚拟DOM中内容没变, 直接使用之前的真实DOM
若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
旧虚拟DOM中未找到与新虚拟DOM相同的key:
创建新的真实DOM,随后渲染到到页面
其他内置指令
指令 | 例子 | 说明 |
---|---|---|
v-text | <div v-text="str"></div> | v-text会替换掉节点中的内容 |
v-html | <div v-html="str"></div> | v-html会替换掉节点中所有的内容,v-html可以识别html结构 |
v-cloak | 使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题 | |
v-once | <h2 v-once>n初始化的值是:{{n}}</h2> | v-once所在节点在初次动态渲染后,就视为静态内容了。以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能 |
v-pre | <h2 v-pre>Vue其实很简单</h2> | 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译 |
v-bind | 单向绑定解析表达式,可简写为: | |
v-model | 双向数据绑定 | |
v-on | 绑定事件监听,可简写为@ | |
v-show | 条件渲染 (动态控制节点是否展示),v-show是控制display属性来控制组件是否显示的 |
v-cloak例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>v-cloak指令</title>
<style>
[v-cloak]{
display:none;
}
</style>
</head>
<body>
<div id="root">
<h2 v-cloak>{{name}}</h2>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{
name:'尚硅谷'
}
})
</script>
</html>
2 过滤器
3自定义指令
4 watch监视属性和computed计算属性
5 ref
打标识:< h1 ref=“xxx”></ h1> 或 < School ref=“xxx”></ School>
获取:this.$refs.xxx
6 mixin
mixin混入对象和Vuex的区别?
vuex是所有组件共同管理一个状态,状态共享
mixin是定义公用的变量或方法,但是mixin中的数据是不共享的,也就是每个组件中的mixin实例都是不一样的,都是单独存在的个体,不存在相互影响的;
7 plugin插件
8 WebStorage
类型 | 说明 |
---|---|
sessionStorage | SessionStorage存储的内容会随着浏览器窗口关闭而消失 |
localStorage | LocalStorage存储的内容,需要手动清除才会消失 |
LocalStorage为例
<body>
<h2>localStorage</h2>
<button onclick="saveDate()">点我保存数据</button><br/>
<button onclick="readDate()">点我读数据</button><br/>
<button onclick="deleteDate()">点我删除数据</button><br/>
<button onclick="deleteAllDate()">点我清空数据</button><br/>
<script>
let person = {name:"JOJO",age:20}
function saveDate(){
localStorage.setItem('msg','localStorage')
localStorage.setItem('person',JSON.stringify(person))
}
function readDate(){
console.log(localStorage.getItem('msg'))
const person = localStorage.getItem('person')
console.log(JSON.parse(person))
}
function deleteDate(){
localStorage.removeItem('msg')
localStorage.removeItem('person')
}
function deleteAllDate(){
localStorage.clear()
}
</script>
</body>
9 props(父子组件之间通信)
1.传递props参数 (父—>子)
<Student name='张三' sex='女' :age='18'/>
2.接收props参数
// 接收props方式1 简答接收
props: ['name', 'sex', 'age'],
// 接收props方式2 接收并预设数据类型
props: {
name: String,
sex: String,
age: Number
},
// 接收props方式3 接收并预设类型和必要性和默认值
props: {
name: { type: String, required: true },
sex: { type: String, required: true },
age: { type: Number, default: 99 },
array: { type: Number, default:()=>[1,2,3]},
array: { type: Object, default:()=>{name:'tom'}}
}
3.使用props参数
<h2>学生的名称:{{name}}</h2>
<h2>学生的年龄:{{age+1}}</h2>
<h2>学生的性别:{{sex}}</h2>
1.props是只读的:
Vue底层会监测你对props的修改,如果进行了修改,就会发出警告。
若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据
2.props不能用key,ref等内置名称作为参数名
4.使用props传递函数 (子—>父)
<School :getSchoolName='getSchoolName'/>
methods: {
getSchoolName (name) {
console.log('app收到了学校名:', name)
}
}
5 使用props接收函数
props: ['getSchoolName'],
6 使用props调用函数
methods: {
// 调用props函数
sendSchoolName () {
this.getSchoolName(this.name)
}
},
10 自定义事件(父子组件之间的通信)
通过绑定自定义事件实现子---->父数据传递
1.1绑定自定义事件(方式1)
1.使用 @ 符来绑定自定义事件
2.如果只想让事件触发一次,可以使用:@getStudentName.once="getStudentName"
<Student @getStudentName="getStudentName"/><hr>
getStudentName (name,x,y,z) {
console.log('app收到了学生名:', name,x,y,z)
}
1.2绑定自定义事件(方式2)
1.使用 ref + $on 来绑定自定义事件
2.这种方法的灵活性更强(绑定自定义事件的时间可以自己来定,例如挂载实例后等3秒再绑定事件)
3.如果只想让事件触发一次,可以将 $on 换为 $once
<Student ref="student"/><hr>
mounted () {
setTimeout(() => {
this.$refs.student.$on('getStudentName', this.getStudentName)
}, 3000)
}
2.调用自定义事件
<button @click="sendStudentName()">把学生名字传给app</button>
sendStudentName () {
// 触发student实例身上的getStudentName事件
this.$emit('getStudentName', this.name,this.x,this.y,this.z)
}
3 解绑自定义事件
给谁绑定的就在谁身上解绑
解绑一个自定义事件
unbind () {
this.$off('getStudentName')
}
解绑多个自定义事件
unbind () {
this.$off(['getStudentName','demo'])
}
解绑所有自定义事件
unbind () {
this.$off()
}
4 补充说明
1.组件销毁后自定义事件失效。但原生绑定的事件还有效果
2.可以在组件上声明原生事件<School @click.native="alert(111)"/>
要用native修饰,否则就会被当做自定义事件来处理
11 全局事件总线(任意组件之间通信)
实现任意组件组件的数据沟通
使用on注册事件,off撤销事件,emit调用事件
1.安装全局事件总线
school组件(绑定事件)
mounted () {
console.log('Scholl', this.x)
this.$bus.$on('hello', (data) => {
alert(`我是school组件,我收到了数据${data}`)
})
},
//解绑
beforeDestroy () {
this.$bus.off('hello')
}
student组件(调用事件)
<button @click="sendStudentName">把学生的名字给school</button>
methods: {
sendStudentName () {
this.$bus.$emit('hello', this.name)
}
}
12 消息订阅与发布(任意组件之间通信)
订阅消息:需要消息的订阅消息
发布消息:提供消息的发布消息
下载需要的库:npm i pubsub-js
1.School组件(收数据)
import pubsub from 'pubsub-js'
mounted () {
// 订阅消息
this.pubId = pubsub.subscribe('hello', (messageName, data) => {
console.log('有人发布了hello消息', data)
})
},
beforeDestroy () {
// 取消订阅消息
pubsub.unsubscribe(this.pubId)
}
2.Student组件 (发数据)
<button @click="sendHelloMessage()">发布消息</button>
import pubsub from 'pubsub-js'
// 发布消息
// 参数1:消息的主键 参数2:消息
sendHelloMessage () {
pubsub.publish('hello', 666)
}
13 &nextTick
页面修改顺序:vue修改某属性后----接着执行函数中的其他语句----函数执行完毕后再重新渲染页面
·
需要立即修改的时候使用nextTick
·
nextTick作用:在下一次dom更新结束后执行回调函数。
<template>
<div class="Student">
<div v-if="!showInput">{{msg}}</div>
<input type="text" name="" id="" v-model="msg" v-else @blur="showtext()" ref="theInput">
<button @click="toshowInput()">编辑</button>
</div>
</template>
<script>
export default {
name: 'Student',
data () {
return {
msg: '我是一个尚硅谷的学生',
showInput: false
}
},
methods: {
// 编辑
toshowInput () {
this.showInput = true
// nextTick所指定的回调会在dom节点更新后执行
this.$nextTick(() => {
this.$refs.theInput.focus()
})
},
showtext () {
this.showInput = false
}
}
}
</script>
14 过渡与动画
14.1 动画
步骤 :
- 定义动画
- 将需要动画的dom用transition包裹
- vue会根据标签的显示、隐藏自动的为需要动画的标签添加样式类名
<template>
<div class="Test">
<button @click="isShow=!isShow">显示隐藏</button>
//用transition来包裹需要展示动画的标签
//name=>动画的类名
//:appear="true"是否在刚进入的时候展示动画
<transition name="textshow" :appear="true">
<h1 class="msg" v-show="isShow">{{msg}}</h1>
</transition>
</div>
</template>
<script>
export default {
name: 'Student',
data () {
return {
msg: '我是一个尚硅谷的学生',
isShow: true
}
},
methods: {
// 编辑
toshowInput () {
this.showInput = true
// nextTick所指定的回调会在dom节点更新后执行
this.$nextTick(() => {
this.$refs.theInput.focus()
})
},
showtext () {
this.showInput = false
}
}
}
</script>
<style scoped>
.msg{
background-color: rgb(222, 168, 226);
padding: 10px;
width: 600px;
}
//进入时播放的动画 textshow=>自定义的动画类名 linear=>匀速
.textshow-enter-active{
animation: textshow 1s linear;
}
//离开时播放的动画 reverse=>翻转(动画反着播放) textshow=>自定义的动画类名
.textshow-leave-active{
animation: textshow 1s linear reverse;
}
//定义动画
@keyframes textshow {
from{//从哪里来
transform: translateX(-100%);
}
to{//到哪里
transform: translateX(0px);
}
}
</style>
14.2 过渡
<template>
<!-- 过渡 -->
<div class="Test">
<button @click="isShow=!isShow">显示隐藏</button>
<transition name="textshow" :appear="true">
<h1 class="msg" v-show="isShow">{{msg}}</h1>
</transition>
</div>
</template>
<script>
export default {
name: 'Student',
data () {
return {
msg: '我是一个尚硅谷的学生',
isShow: true
}
},
methods: {
// 编辑
toshowInput () {
this.showInput = true
// nextTick所指定的回调会在dom节点更新后执行
this.$nextTick(() => {
this.$refs.theInput.focus()
})
},
showtext () {
this.showInput = false
}
}
}
</script>
<style scoped>
.msg{
background-color: rgb(222, 168, 226);
padding: 10px;
width: 600px;
}
/* 整个动画 linear=>匀速*/
.textshow-enter-active,.textshow-leave-active{
transition: 1s linear;
}
/* 进入的起点 */
.textshow-enter{
transform: translateX(-100%);
}
/* 进入的终点 */
.textshow-enter-to{
transform: translateX(0);
}
/* 离开的起点 */
.textshow-leave{
transform: translateX(0);
}
/* 离开的终点 */
.textshow-leave-to{
transform: translateX(-100%);
}
</style>
14.3 多个元素过渡
transition标签:只能包含一个dom元素
transition group标签:可以包含多个元素
<transition-group name="textshow" :appear="true">
<h2 class="msg" v-show="isShow" key="1">{{msg}}</h2>
<h2 class="msg" v-show="!isShow" key="2">{{msg}}</h2>
</transition-group>
14.4 结合第三方动画库
下载依赖的库:npm install animate.css
15 配置代理
下载依赖的库:npm i axios
什么是跨域? 违背了同源策略
什么是同源策略? 协议名,主机名,端口号一致
如何解决跨域?
- 使用cors:后端人员特殊配置,但是会导致所有人都可以请求
- 使用jsonp:利用script标签的src属性不受同源策略控制的属性来发送请求,但是只能处理get请求,并且需要前端后端配合,麻烦
- 配置代理:代理服务器,服务器和服务器之间交流无需ajax
开启代理服务器 方法1
借助vue脚手架开启代理服务器
vue.config.js:配置代理服务器
module.exports={
pages:{
index:{
//入口
entry:'src/main.js'
}
},
//开启代理服务器
devServer:{
proxy:'http://localhost:5000'
}
}
发送请求:
注意这里是用8080来进行请求
getStuednts () {
axios.get('http://localhost:8080/students').then(
res => { console.log(res.data) },
error => { console.log(error.message) }
)
}
注意:当8080端口下存在对应的内容时,就不会走代理服务器了,而是请求已有的。
注意2:8080端口就相当于public文件夹下的内容
注意3:这种配置的方式只能配置一个端口的跨域
开启代理服务器 方法2
vue.config.js:配置代理服务器
module.exports={
pages:{
index:{
//入口
entry:'src/main.js'
}
},
devServe:{
proxy:{
'/api':{
target:'http://localhost:5000',
pathRewrite:{'^/api':''},
ws:true, //用于支持websocket
changeOrigin:true //用于控制请求头中的host字段
},
'/foo':{
target:'http://localhost:5001',
pathRewrite:{'^/foo':''},
ws:true,
changeOrigin:true
}
}
}
}
发送请求:
getStuednts () {
axios.get('http://localhost:8080/api/student').then(
res => { console.log(res.data) },
error => { console.log(error.message) }
)
}
16 插槽
16.1 默认插槽
定义插槽
在组件中定义插槽
<template>
<div class="category">
<h3 class="title">{{title}}</h3>
<!-- 定义一个插槽 等着组件的使用者进行填充 -->
<slot>
我是默认值,使用者没有传结构的时候出现
</slot>
</div>
</template>
<script>
export default {
name: 'Category',
props: ['title']
}
</script>
使用插槽
调用组件时使用插槽
<template>
<div id="app" class="mian-content">
<Category :listDate='foods' title="美食">
<img src="./assets/food.jpg" alt="" class="img">
</Category>
<Category :listDate='games' title="游戏">
<ul>
<li v-for="(item,index) in games" :key="index">{{item}}</li>
</ul>
</Category>
<Category :listDate='films' title="电影">
</Category>
</div>
</template>
<script>
import Category from './components/Category.vue'
export default {
name: 'App',
components: {Category},
data () {
return {
games: ['游戏1', '游戏2', '游戏3', '游戏4']
}
}
}
</script>
效果
16.2 具名插槽
定义具名插槽
<template>
<div class="category">
<h3 class="title">{{title}}</h3>
<!-- 定义一个插槽 等着组件的使用者进行填充 -->
<slot name="center"> 我是插槽1,我是默认值,使用者没有传结构的时候出现 </slot>
<slot name="footer"> 我是插槽2,我是默认值,使用者没有传结构的时候出现 </slot>
</div>
</template>
调用具名插槽
<Category :listDate='foods' title="美食">
<div slot="center">
<img src="./assets/food.jpg" alt="" class="img">
</div>
<!-- 写多个 相当于追加 -->
<div slot="footer">
<a href="">其他美食</a>
</div>
<div slot="footer">
<a href="">其他美食</a>
</div>
</Category>
优化:使用template来包裹
template可以忽略最外层没有作用的结构
最新的写法: v-slot:center,只能用在template结构上
<Category :listDate='foods' title="美食">
<template v-slot:center>
<img src="./assets/food.jpg" alt="" class="img">
</template>
<!-- 写多个 相当于追加 -->
<template v-slot:footer>
<a href="">其他美食</a>
<a href="">其他美食</a>
</template>
</Category>
效果图
16.3 作用域插槽
定义作用域插槽
<template>
<div class="category">
<h3 class="title">{{title}}</h3>
<!-- 将games传递给了插槽的使用者 -->
<slot :gamesList="games"> 我是默认值,使用者没有传结构的时候出现 </slot>
</div>
</template>
<script>
export default {
name: 'Category',
props: ['title'],
data () {
return {
games: ['游戏1', '游戏2', '游戏3', '游戏4']
}
}
}
</script>
调用作用域插槽
<template>
<div id="app" class="mian-content">
<Category title="游戏">
<template slot-scope="listData">
<ul>
<li v-for="(item,index) in listData.gamesList" :key="index">{{item}}</li>
</ul>
</template>
</Category>
<Category title="游戏">
<template slot-scope="listData">
<ol>
<li v-for="(item,index) in listData.gamesList" :key="index">{{item}}</li>
</ol>
</template>
</Category>
<Category title="游戏">
<template slot-scope="listData">
<h3 v-for="(item,index) in listData.gamesList" :key="index">{{item}}</h3>
</template>
</Category>
</div>
</template>
优化:使用解构赋值来提取数据
<Category title="游戏">
<template slot-scope="{gamesList}">
<h3 v-for="(item,index) in gamesList" :key="index">{{item}}</h3>
</template>
</Category>
16.4 v-slot
在vue2.6中。上述的API被软废弃(3.0正式废弃),取而代之的是内置指令v-slot,可以缩写为【#】
一般用法:
子组件用法保持不变,父组件中
- slot属性弃用,具名插槽通过指令参数
v-slot:插槽名
的形式传入,可以简化为#插槽名
- slot-scope属性弃用,作用域插槽通过
v-slot:xxx="slotProps"
的slotProps
来获取子组件传出的属性 - v-slot属性只能在template上使用,但在
只有默认插槽
时可以在组件标签上使用
//Parent
<template>
<child>
<!--默认插槽-->
<template v-slot>
<div>默认插槽</div>
</template>
<!--具名插槽-->
<template #header>
<div>具名插槽</div>
</template>
<!--作用域插槽-->
<template #footer="slotProps">
<div>
{{slotProps.testProps}}
</div>
</template>
<child>
</template>
扩展用法:
- 同样可以通过解构获取v-slot={user},还可以重命名
v-slot="{user:newName}"
和定义默认值v-slot=“{user = ‘默认值’}” 例:v-slot:title="{ item }
- 插槽名可以是动态变化的
v-slot:[slotName]
注意:
- 默认插槽名为default,
可以省略default直接写v-slot
,缩写为#时不能不写参数,写成#default
(这点所有指令都一样,v-bind、v-on) - 多个插槽混用时,v-slot不能省略default
17 路由
17.1 创建路由器
1.路由就是一组
key-value
的对应关系
2.多个路由需要通过路由器(router)
的管理
下载依赖包:
npm i vue-router@3
在main.js中引入:
// 引入
import VueRouter from 'vue-router'
// 调用
Vue.use(VueRouter)
mian.js
router.js
import VueRouter from 'vue-router'
// 引入组件
import Abbout from '../components/Abbout.vue'
import Home from '../components/Home.vue'
export default new VueRouter({
routes: [
{
path: '/about',
component: Abbout
},
{
path: '/home',
component: Home
}
]
})
17.2 路由的基本使用
router-link:切换路由
router-view: 指定路由组件的呈现位置
17.2 路由需要注意的几个点
路由组件:放在
pages
文件夹中
一般组件:放在components
文件夹中
切换走的路由组件实质上是被 销毁 了,切换组件实质上就是组件销毁和挂载的过程
每个组件都有自己的r
$route
属性,里面存储了自己的路由相信。
整个应用都只有一个router可以通过组件的
$router
属性获取到
17.3 嵌套(多级)路由
注册子路由
{
path: '/home',
component: Home,
children: [
{
path: 'message',
component: Message
},
{
path: 'news',
component: News
}
]
}
使用子路由进行路由跳转
<div class="list-group">
<router-link class="list-group-item" active-class="active" to="/home/message">message</router-link>
<router-link class="list-group-item" active-class="active" to="/home/news">news</router-link>
</div>
<div>
<router-view/>
</div>
17.4 路由命名
简化路由跳转
路由命名
使用路由名称进行组件切换
<div class="list-group">
<router-link class="list-group-item" active-class="active" :to="{name:'message'}">message</router-link>
<router-link class="list-group-item" active-class="active" :to="{name:'news'}">news</router-link>
</div>
<div>
<router-view/>
</div>
17.5 路由传递query参数
传递query参数
<li v-for="item in messageList" :key="item.id">
<!-- 写法2:to的字符串写法 -->
<router-link :to="`/home/message/detail?id=${item.id}&title=${item.title}`">{{ item.title }}</router-link>
<!-- 写法2:to的对象写法【推荐】 -->
<router-link :to="{ path:'/home/message/detail', query:{ id:item.id, title:item.title } }">
{{ item.title }}
</router-link>
</li>
接收query参数
this.$route.query.id
<ul>
<li>消息编号:{{this.$route.query.id}}</li>
<li>消息标题:{{this.$route.query.title}}</li>
</ul>
17.6 路由传递params参数
传递params参数
<li v-for="item in messageList" :key="item.id">
<!-- 写法2:to的字符串写法 -->
<router-link :to="`/home/message/detail/${item.id}/${item.title}`">{{ item.title }}</router-link>
<!-- 写法2:to的对象写法 -->
<router-link :to="{ name:'detail', params:{ id:item.id, title:item.title } }">
{{ item.title }}
</router-link>
</li>
注意:
使用to的对象写法,只能用name来设置路由
声明接收params参数
children: [
{
name: 'detail',
path: 'detail/:id/:title',
component: Detail
}
]
接收params参数
<ul>
<li>消息编号:{{this.$route.params.id}}</li>
<li>消息标题:{{this.$route.params.title}}</li>
</ul>
17.7 路由的props配置
17.7.1 props的对象形式
props的对象写法:该对象的所有参数都会以props的形式传给detail组件
配置props
children: [
{
name: 'detail',
path: 'detail',
component: Detail,
props: {a: 1, b: 'hello'}
}
]
接收props参数
<template>
<div>
<h3>detail</h3>
<ul>
<li>a:{{a}}</li>
<li>b:{{b}}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Detail',
props: ['a', 'b']
}
</script>
17.7.2 props的布尔值写法
true:把该路由组件收到的params参数以props的形式传递给detail组件
配置props
children: [
{
name: 'detail',
path: 'detail/:id/:title',
component: Detail,
props: true
}
]
传递params参数
<router-link :to="{ name:'detail', params:{ id:item.id, title:item.title } }">
{{ item.title }}
</router-link>
以props形式接收params参数
<template>
<div>
<h3>detail</h3>
<ul>
<li>id:{{id}}</li>
<li>title:{{title}}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Detail',
props: ['id', 'title']
}
</script>
17.7.2 props的函数写法
可以把该路由组件收到的各类参数以props的形式传递给detail组件
配置props
children: [
{
name: 'detail',
path: 'detail',
component: Detail,
props ($route) {
return {id: $route.query.id, title: $route.query.title}
}
}
]
例子:传递query参数
<router-link :to="{ name:'detail', query:{ id:item.id, title:item.title } }">
{{ item.title }}
</router-link>
以props形式接收query参数
<template>
<div>
<h3>detail</h3>
<ul>
<li>id:{{id}}</li>
<li>title:{{title}}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Detail',
props: ['id', 'title']
}
</script>
17.8 route_link的replace属性
将路由的切换形式改为replace(替换路由)
17.9 编程式路由导航
作用: 不借助router_link实现路由的跳转
<button @click="pushShow(item)">push查看</button>
<button @click="replaceShow(item)">replace查看</button>
<button @click="forward">前进</button>
<button @click="back">后退</button>
<button @click="go">前进一个路由</button>
// push查看
pushShow (item) {
this.$router.push({
name: 'detail',
params: { id: item.id, title: item.title }
})
},
// replace查看
replaceShow (item) {
this.$router.replace({
name: 'detail',
query: { id: item.id, title: item.title }
})
},
// 前进
forward () {
this.$router.forward()
},
// 后退
back () {
this.$router.back()
},
// go:传入数组 正数前进,负数后退
go () {
this.$router.go(1)
}
17.10 缓存路由组件
让不展示的组件保持挂载,不被销毁
include里面写的是组件名
<!-- include里面写的是组件名 -->
<keep-alive include="News">
<router-view/>
</keep-alive>
include="News"
:include=["News","Message"]
出现问题:当要keep-alive的组件需要在beforeDestory中执行某些操作的时候,无法执行beforeDestory生命周期。
17.10.1两个新的生命周期函数
<template>
<div>
<ul>
<li :style="{opacity}">欢迎学习vue</li>
<li>news001<input/></li>
<li>news002<input/></li>
<li>news003<input/></li>
</ul>
</div>
</template>
<script>
export default {
name: 'News',
data () {
return {
opacity: 1,
timer: null
}
},
mounted () {
this.timer = setInterval(() => {
this.opacity -= 0.02
if (this.opacity <= 0) this.opacity = 1
}, 100)
},
activated () {
console.log('组件被激活了')
},
deactivated () {
console.log('组件失活了')
clearInterval(this.timer)
}
// beforeDestroy () {
// clearInterval(this.timer)
// }
}
</script>
17.11 路由守卫
17.11.1 全局-前置路由守卫
router.beforeEach
import VueRouter from 'vue-router'
// 引入组件
import Abbout from '../pages/Abbout.vue'
import Home from '../pages/Home.vue'
import Message from '../pages/Message.vue'
import News from '../pages/News.vue'
import Detail from '../pages/Detail.vue'
const router = new VueRouter({
routes: [
{
name: 'about',
path: '/about',
component: Abbout
},
{
name: 'home',
path: '/home',
component: Home,
children: [
{
name: 'message',
path: 'message',
component: Message,
},
{
name: 'news',
path: 'news',
component: News
}
]
}
]
})
// 全局前置路由守卫 每次路由切换之前和初始化的时候调用
router.beforeEach((to, from, next) => {
if (to.path === '/home/news' || to.path === '/home/message') {
if (localStorage.getItem('school') === 'atguigu') {
next()
} else {
alert('学校名称不对,无权查看')
}
} else {
next()
}
})
export default router
可以在路由配置中插入
路由元信息
,用于决定路由是否需要走路由守卫
import VueRouter from 'vue-router'
// 引入组件
import Abbout from '../pages/Abbout.vue'
import Home from '../pages/Home.vue'
import Message from '../pages/Message.vue'
import News from '../pages/News.vue'
import Detail from '../pages/Detail.vue'
const router = new VueRouter({
routes: [
{
name: 'about',
path: '/about',
component: Abbout
},
{
name: 'home',
path: '/home',
component: Home,
children: [
{
name: 'message',
path: 'message',
component: Message,
meta: {isAuth: true}
},
{
name: 'news',
path: 'news',
component: News,
meta: {isAuth: true}
}
]
}
]
})
// 全局前置路由守卫 每次路由切换之前和初始化的时候调用
router.beforeEach((to, from, next) => {
if (to.meta.isAuth) {
if (localStorage.getItem('school') === 'atguigu') {
next()
} else {
alert('学校名称不对,无权查看')
}
} else {
next()
}
})
export default router
17.11.2 全局-后置路由守卫
import VueRouter from 'vue-router'
// 引入组件
import Abbout from '../pages/Abbout.vue'
import Home from '../pages/Home.vue'
import Message from '../pages/Message.vue'
import News from '../pages/News.vue'
import Detail from '../pages/Detail.vue'
const router = new VueRouter({
routes: [
{
name: 'about',
path: '/about',
component: Abbout,
meta: {title: '关于'}
},
{
name: 'home',
path: '/home',
component: Home,
meta: {title: '主页'},
children: [
{
name: 'message',
path: 'message',
component: Message,
meta: {title: '消息', isAuth: true},
children: [
{
name: 'detail',
path: 'detail',
meta: {title: '详情', isAuth: true},
component: Detail,
},
{
name: 'news',
path: 'news',
component: News,
meta: {title: '新闻', isAuth: true}
}
]
}
]
})
// 全局前置路由守卫 每次路由切换之前和初始化的时候调用
router.beforeEach((to, from, next) => {
if (to.meta.isAuth) {
if (localStorage.getItem('school') === 'atguigu') {
next()
} else {
alert('学校名称不对,无权查看')
}
} else {
next()
}
})
// 全局后置路由守卫 每次路由切换之后和初始化的时候调用
router.afterEach((to, from) => {
document.title = to.meta.title || '硅谷系统'
})
export default router
17.11.3 独享路由守卫
独享的路由守卫只有前置没有后置
{
name: 'news',
path: 'news',
component: News,
meta: {title: '新闻', isAuth: true},
beforeEnter: (to, from, next) => {
if (to.meta.isAuth) {
if (localStorage.getItem('school') === 'atguigu') {
next()
} else {
alert('学校名称不对,无权查看')
}
} else {
next()
}
}
}
17.11.4 组件内路由守卫
<template>
<div>
<h2>about</h2>
</div>
</template>
<script>
export default {
name: 'Abbout',
// 通过路由规则进入该组件时被调用
beforeRouteEnter (to, from, next) {
console.log('app------beforeRouteEnter')
next()
},
// 通过路由规则离开该组件时被调用
beforeRouteLeave (to, from, next) {
console.log('app------beforeRouteLeave')
next()
}
}
</script>
17.12 history模式和hash模式
模式 | 说明 | 特点 | 兼容性 |
---|---|---|---|
hash【默认】 | 带#号,#后面的东西是hash值 | hash值不会随http请求发送给服务器 | 兼容性好 |
history | 不带#号 | hash值不会随http请求发送给服务器 | 兼容性略差 |
切换模式
18 项目打包
npm run build
19 vue前端请求接口封装
19.1 utils文件
在src目录下新建 utils:实用程序 文件夹
创建request.js来作为axios封装文件
//request.js
import axios from 'axios'
const request = axios.create({
baseURL: 'http://localhost:3000',
timeout: 5000
})
export default request
19.1 api文件
在src目录下新建 api 文件夹
创建xxxx.js 用于封装请求
创建index.js用于批量暴露请求
//实例:produce.js
import request from '../utils/request'
export function getProduce (params) {
return request({
method: 'GET',
url: '/produce',
params
})
}
export function getProduceInfo (params) {
return request({
method: 'POST',
url: '/produceInfo',
params
})
}
//index.js
import * as produce from './produce'
const apiObj = {
produce
}
const install = function (Vue) {
if (install.installed) return
install.installed = true
Object.defineProperties(Vue.prototype, {
$api: {
get () {
return apiObj
}
}
})
}
export default {
install
}
19.3 使用封装过后的axios进行请求
1.在main.js中引入index.js
2.在pages中使用
19.4 vue前端请求、相应拦截器
20 全局变量
1. 新建global.js文件
global.js文件内容
export default{
// nowSystemName:'四川省卫生健康信息中心线上培训信息系统',
nowSystemName:'电子科大科园商学院',
}
1. 在main.js中引入并使用
import global from './components/common/global'
Vue.prototype.$global = global
3. 在组件中使用
this.$global.nowSystemName