一、 vue 有多少个生命周期,每个作用是什么?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<link rel="stylesheet" href="">
<script src="https://cdn.bootcss.com/vue/2.2.1/vue.min.js"></script>
</head>
<body>
<div id="app">
<template>
<div>
<p>{{ total }}</p>
<button-counter v-on:increment="incrementTotal"></button-counter>
<button-counter v-on:increment="incrementTotal"></button-counter>
<hr>
<button onclick="vm.$destroy()">此按钮用来销毁实例</button>
</div>
</template>
</div>
<script>
Vue.component('button-counter', {
template: '<button @click="increment">我是按钮{{ counter }}</button>',
data: function() {
return {
counter: 0
}
},
methods: {
increment(){
this.counter ++;
this.$emit('increment')
}
}
})
var vm = new Vue({
el: "#app",
data() {
return {
total: 0
}
},
methods: {
incrementTotal(){
this.total ++;
}
},
// 组件生命周期
beforeCreate() { // 在实例创建之后,在数据初始化之前被调用
console.log('beforeCreated-1')
},
created() { // 在数据初始化之后被调用,如果你的页面进来的时候就调用接口,那么created是第一选择
console.log('created-2')
},
beforeMount() { // 在数据渲染之前被调用
console.log('beforeMount-3')
},
mounted() { // 实例创建完成、数据初始化、渲染页面数据后,才被调用
console.log('mounted-4')
},
beforeUpdate() { // 在数据改变时被调用
console.log('beforeUpdate-5')
},
updated() { // 数据被更新之后
console.log('updated-6')
},
//keep-alive生命周期有两个 (activated , deactivated)
activated() { // keep-alive 组件激活时调用,也就是说在路由切换时被调用,注意要配合keep-alive使用才会被调用, <keep-alive>
// 可以看下别人写的 https://www.cnblogs.com/sysuhanyf/p/7454530.html
},
deactivated(){// keep-alive 组件停用时调用,也可以理解成在路由切换的会自动停用组件,
// 可以看下别人写的 https://www.cnblogs.com/sysuhanyf/p/7454530.html
},
beforeDestroy() { // 实例销毁前被调用
console.log('beroreDestroy-9')
},
destroyed() { //实例销毁后被调用
console.log('destroyed-10')
}
})
</script>
</body>
</html>
|
二、 vue路由有多少个钩子,每个作用是什么?
1. beforeEach 全局路由钩子,只要页面路由改变就会执行,钩子有是三个参数 to 、from 、next
export default {
name: 'app',
data() {
return {
}
},
mounted() {
this.$router.beforeEach((to, from, next) => {
console.log(to, from)
next()
})
}
}
to 要去哪个页面 返回信息如下图
from 是我从哪个页面过来的,和to参数格式一样,只不过path不同
next 是一个执行的参数 必须要加上next(),不然路由不会跳转
2. afterEach 全局路由钩子 有两个参数 to 、from
这两个参数和beforeEach相同,唯一的区别是afterEach钩子是路由跳转之后才被执行
this.$router.afterEach((to, from) => {
console.log(to, from)
})
3. beforeEnter 这个一般情况下用不到,在路由页面配置 beforeEnter,在进入这个路由后执行
routes: [{
path: '/Hello',
name: 'Hello',
component: Hello
},
{
path: '/index',
component: index,
children: [
{ path: 'world', component: world ,
beforeEnter: (to, from, next) => {
// 执行逻辑
next()
}
},
{ path: 'world_childen', component: world_childen },
]
}
]
4. beforeRouteEnter 组件私有钩子
组件私有的钩子,组件被调用事执行,在beforeRouteEnter这个钩子里面没有this
因为在这个钩子执行的时候组件的实例还没有创建,所以打印this是undefined
在next里面使用vm.name可以代替 this。
to 返回的信息是当前页面路由信息
from 返回的是从哪里过来的,和beforeEach 有点差异
export default {
data() {
return {
name: 'web_珂珂'
}
},
beforeRouteEnter(to, from, next){
console.log(this) // undefined
next(vm => {
console.log(vm.name) // web_珂珂
});
}
}
5. beforeRouteUpdate 组件私有钩子,只有在组件被多次调用并且路由有变的的时候才会执行
比如: A页面调用了当前组件,B页面也调用了当前组件,但是他们的路由变化了,beforeRouteUpdate就会被执行
beforeRouteUpdate this是指向实例的
html:
// 类似于这样 两个router-link都调用world组件,但是参数不同,就会被执行
<router-link to="/index/world">导航二</router-link>
<router-link to="/index/world?name=web_keke">测试beforeRouteUpdate钩子</router-link>
<script>
export default {
data() {
return {
name: 'web_珂珂'
}
},
beforeRouteUpdate(to, from, next){
console.log(this.name) // web_珂珂
console.log(to,from)
next()
}
}
</script>
6. beforeRouteLeave 从当前组件的跳转别的路由页面执行,就是离开的时候执行
export default {
data() {
},
beforeRouteLeave (to, from, next) {
console.log(to, from)
next()
}
}
三、computed计算属性与methods方法的区别?
computed 在数据没有更新的情况下,computed缓存数据,下次进来还是读取缓存的数据。
而methods方法会每次都会执行,不会走缓存,举个例子:
<template>
<div>
<!-- computed -->
我是computed 只要数据没有更新,我会读取缓存,不会重新计算
<p>
数量:{{ computedCount }}
</p>
<p>
数量:{{ computedCount }}
</p>
<p>
数量:{{ computedCount }}
</p>
<hr>
<!-- 方法 -->
我是methods方法,每次都会重新调用methodsCount()函数
<p>
数量:{{ methodsCount() }}
</p>
<p>
数量:{{ methodsCount() }}
</p>
</div>
</template>
<script>
export default {
data() {
return {
count: 1
}
},
// 计算
computed: {
computedCount(){
return this.count + 100
}
},
// 方法
methods: {
methodsCount(){
return this.count + 100
}
}
}
</script>
四、自定义指令 directive
vue 有他们自己内置的指令如v-model, 还可以自己定义一些指令(directive),自定义指令可以写成局部的,也可以写成全局的,下面有个回车搜索的案例(这个还是我之前的一个朋友教我的-_-"),用于多个页面搜索框输入直接回车就可以调用方法
钩子函数 和 钩子函数参数
1. 全局指令
全局的写法我在main.js里面写的,在任何组件都可以用
Vue.directive('keyup-enter',{
inserted(el, binding) {
let $inputs = el.getElementsByTagName('input')
Array.from($inputs).forEach( $item => {
$item.addEventListener('keydown', event => {
let e = event || window.event
if (e.keyCode === 13) {
if (binding.value) {
setTimeout(() => {
binding.value()
}, 100)
}
}
})
})
}
})
然后在组件中调用keyup-enter指令,
把指令绑定到最外层的div上面 如,然后在输入框输入文本按回车
<template>
<!-- 这里绑定指令 v-keyup-enter -->
<div v-keyup-enter="getName">
名称:
<input type="text" v-model="name">
年龄:
<input type="text" v-model="age">
</div>
</template>
<script>
export default {
data() {
return {
name: '珂珂',
age: '26'
}
},
methods: {
getName() {
console.log(this.name) // 珂珂
console.log(this.age) // 26
}
}
}
</script>
2. 局部指令
比如有个需求,要求页面一进来,就让某一样文本,添加一个颜色,并且让这个文字翻转,或者只有第一次需要添加颜色,这中情况使用指令是最合适的
v-reverse 就是自定义的指令名称
<template>
<div>
<p v-reverse>{{ message }}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: '"-_-我是菜鸟',
}
},
directives: {
reverse: {
inserted(el) {
el.innerHTML = el.innerHTML.split('').reverse().join(''); // 鸟菜是我-_-"
el.style.color = 'red';
console.log(el) // <p style="color: red;">鸟菜是我-_-"</p>
}
}
}
}
</script>
五、 keep-alive 缓存
详解 keep-alive
keep-alive有两个生命周期 activated和deactivated,activated是组件被缓存的时候执行,deactivated是离开缓存组件的时候执行。
keep-alive属性 如: <keep-alive include="Hello"> 缓存Hello组件
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例
在Hello中切换tab到内容二选项,然后在跳转的world组件后,在切回到Hello组件中,你会发现还是刚才的内容二的文本,他并没有显示初始化的内容一的文本,这样就实现了缓存,另外keep-alive属性include 设置的名称是你要缓存的组件中写的那个name名称,如果名字不统一,缓存则无效。
如果想缓存多个组件,可以以逗号分隔,如: <keep-alive include="Hello, world">
缓存方式一、
app.vue
<template>
<div id="app">
<div class="nav">
<ul>
<router-link
v-for="(item, index) in arr"
:key="index"
:to="item.routerPath">
{{item.routerName}}
<br><br><br>
</router-link>
</ul>
</div>
<div class="view-box">
// 这里缓存组件Hello
<keep-alive include="Hello">
<router-view></router-view>
</keep-alive>
</div>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
active: '/Hello',
arr: [
{
routerName: '我是hello组件',
routerPath: '/Hello'
},
{
routerName: '我是world组件',
routerPath: '/world'
}
]
}
}
}
</script>
Hello.vue
<template>
<div class="hello">
<ul>
<li v-for="(item, index) in navArr" :key="index">
<button
@click="tab(item.tab)"
:class="{ active : tabShow == item.tab }"
>
{{ item.name }}
</button>
</li>
</ul>
<div class="box">
<div :is="tabShow"></div>
</div>
</div>
</template>
<script>
let A = {
template:`<h3>我是内容一的信息11111</h3>`
}
let B = {
template:`<h3>我是内容二的信息22222222222</h3>`
}
export default {
name:'Hello', // 这个name要和 keep-alive中include 设置的名字统一,否则无效
data () {
return {
tabShow:'A',
navArr: [
{
name: '内容一',
tab: 'A'
},
{
name: '内容二',
tab: 'B'
}
]
}
},
components: {
'A': A,
'B': B
},
methods: {
tab(currentShowTab){
this.tabShow = currentShowTab;
}
},
activated(){ // 组件被缓存的时候执行
console.log('组件被缓存的时候执行')
},
deactivated(){ // 离开缓存组件的时候执行
console.log('离开缓存组件的时候执行')
}
}
</script>
缓存方式二、
配合router路由去动态缓存, 这种方式 keep-alive 就是根据路由配置里面来实现的
index.js (router下的index.js文件)
import Vue from 'vue'
import Router from 'vue-router'
import Hello from '../components/Hello'
import index from '../components/index'
import world from '../components/world'
Vue.use(Router)
export default new Router({
routes: [{
path: '/Hello',
name: 'Hello',
component: Hello,
meta: {
keepAlive: true // 设置为缓存
}
},
{
path: '/world',
name: 'world',
component: world,
meta:{
keepAlive: false //设置为不缓存
}
}
]
})
然后修改app.vue
<template>
<div id="app">
<div class="nav">
<ul>
<router-link v-for="(item, index) in arr" :key="index" :to="item.routerPath">
{{item.routerName}}
<br><br><br>
</router-link>
</ul>
</div>
<div class="view-box">
// 修改为根据路由配置来实现缓存某些页面
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</div>
</template>