vue2语法
基础指令
1.v-bind
将标签属性值变成变量,动态改变标签属性
<a v-bind:href="xxx">去百度</a>
# 简写
<a :href="xxx">去百度</a>
标签属性不加v-bind
时它的值"xxx"
就是一个固定值,加了v-bind
它的值"xxx"
就变成了变量。
我们可以在data里新增一个xxx属性并为它赋值。
2.v-on
绑定事件
<button v-on:click="money++">增加余额</button>
<button v-on:click="add">增加余额</button>
# 简写
<button @click="money++">增加余额</button>
<button @click="add">增加余额</button>
绑定事件的值可以是简单的运算,比如累加或者三元运算符,也可以是一个方法。我们在
methods
这个对象中创建add(){}
这个方法并执行某些操作。
3.vue中获取事件对象e
- 没有传参,通过形参接收
- 传参了,通过
$event
指代对象e
<a href="http://www.taobao.com" @click="goTaobao">淘宝</a>
<a href="http://www.qq.com" @click="goQQ('张老三',$event)">QQ</a>
// 利用事件对象e阻止默认行为
goTaobao(e) {
e.preventDefault();
console.log("我阻止了淘宝页面跳转");
},
goQQ(preson, e) {
e.preventDefault();
console.log("我阻止了" + preson + "去QQ页面");
}
注意:不传参的情况下add()最好去掉括号,不然很可能拿不到e
4.事件修饰符阻止默认行为
<!--
事件修饰符 => 修饰事件
@事件名.prevent => e.preventDefault() 阻止默认行为
@事件名.stop => e.stopPropagation() 阻止冒泡
prevent 和 stop 可以嵌套使用前后书写顺序没有影响
-->
<a href="http://www.taobao.com" @click.prevent.stop="goTaobao()">淘宝</a>
<a href="http://www.qq.com" @click.stop.prevent="goQQ('张三',$event)">QQ</a>
5.按键修饰符
@keyup.enter 监听回车键
@keyup.esc 监听返回键
@keyup.up 监听上键
@keyup.down 监下键
@keyup.left 监左键
@keyup.right 监听右键
除一些常规的键盘事件,其他的可以用
e.key==="xxx"
的形式判断。
6.v-show
语法:v-show="布尔值" true显示 false隐藏
原理:控制css display:none
适用场景:频繁切换
7.v-if
语法:v-if="布尔值" true显示 false隐藏 (控制页面有无该节点)
原理:动态删除 或 创建元素
另外:v-if 是惰性的,如果 v-if="false",那么不会创建该节点!性能更高。
适用场景:要么显示要么隐藏,不太会频繁切换,隐藏时需要移除节点的场景
8.v-model
v-model配合 表单
使用
特点:双向数据绑定
原理:v-bind="value"
注意:v-model不能绑定解构值(详解见《vue中遇到的问题》1)
v-model只能绑属性或值,不能绑函数。
class属性绑定
绑定属性常用写法,true生效,false不生效。
v-bind:class="{ '样式类名': true/false, '样式类名': true/false }"
基本对象
🥀1.computed 计算属性
特点:
- 依赖(多个)旧值的到新值
- 有缓存,如果依赖的数据未改变,则从缓存中直接拿上次计算的结果。减轻计算量
- 当计算属性的值是双向数据绑定(v-model)时,要用完整写法(get,set)
- 页面刷新时执行一次,依赖数据改变执行一次
- 计算属性可以实现的功能,methods里的函数也能实现。只不过methods每次调用都执行性能不高。
使用场景:分数求和,求平均值
🥀2.watch 侦听器
特点:
- 只有watch允许异步操作
- 监听
某一个
旧值的改变,然后执行某些操作 - 无缓存
使用场景:银行卡余额改变,向后台发送请求,后台发短信提示。
🥀3.components 组件
注意:
-
组件名用大驼峰 XxxPage(建议) 或 xxx-page 形式
-
局部注册(
常用
)-
App.vue中
-
import XxxPage from '@/components/子组件名'
-
components:
-
-
-
-
全局注册:
-
main.js中
-
import XxxPage from '@/components/子组件名'
-
Vue.components('自定义组件名',XxxPage)
-
-
App.vue中
- <自定义组件名></自定义组件名>
-
props
特点:
-
单向向下
数据绑定,父组件数据改变,子组件数据更新。反之不可以。 -
只允许父组件修改数据
🥀父传子
思路:
- 父组件使用自定义属性,子组件用
props
接收
🥀子传父
思路:
- 子组件触发this.$emit('自定义事件名',参数1,参数2...)
- 父组件自定义事件,赋值一个方法
- 父组件给你方法写逻辑修改父组件中的数据
🥀1.v-model 组件绑定
实现子传父父传子
原理:我们将数据以 :value="数据"
的方式传给子组件,子组件通过 props:['value']
接收数据, 子组件定义一个事件(例如@click="xxx")。
methods:{xxx(){this.$emit('input',)}}
🥀2.ref 和 refs
作用:获取表单元素,和 document.querySelector('')效果一样。
区别:querySelector是在全局搜索标签,refs是在组件中搜索,性能更高
用法:
// ref注册标签
<h1 ref="dome_h1">我是文章的标题</h1>
// refs获取标签
console.log(this.$refs.dome_h1);
特点:父组件直接获取子组件的数据和方法
$nextTick
作用:实时获取数据更新后的视图层(主要获取视图层包括DOM)
原理:视图更新是异步的微任务,$nextTick也是异步微任务。
具体分析:DOM更新的顺序是子组件先更新,之后父组件更新。因此在子组件中获取的父组件的数据总是更新之前的旧数据,所以 $nextTick 应运而生。
动态组件
作用:根据组件名判断组件是否生效
核心:<component :is="componentId"></component>
原理:component标签内的 is 属性动态绑定子组件的名字,根据子组件的名字显示组件。
<template>
<div>
// 点击事件改变属性 componentId 的值,这个值必须为子组件名。
<button @click="componentId = 'UserAccount'">点我显示UserAccount</button>
<button @click="componentId = 'UserInfo'">点我显示UserInfo</button>
// 根据 componentId 的值显示组件
<component :is="componentId"></component>
</div>
</template>
<script>
import UserAccount from '@/components/07-UserAccount.vue'
import UserInfo from '@/components/07-UserInfo.vue'
export default {
components:{
UserAccount,
UserInfo
},
data() {
return {
// 给 componentId 一个默认值,这个值必须是组件名
componentId:'UserAccount'
}
},
};
</script>
使用场景:tap栏切换界面(不常使用),后面路由可以更好的解决。
自定义指令
https://v2.cn.vuejs.org/v2/guide/custom-directive.html
如果想注册局部指令,组件中也接受一个 directives
的选项:
directives: {
focus: {
//inserted DOM元素插入到页面节点触发
inserted: function (el) {
el.focus()
}
}
}
然后你可以在模板中任何元素上使用新的 v-focus
property,如下:
<input v-focus>
🥀钩子函数参数
el
:指令所绑定的元素,可以用来直接操作 DOM。
directive('pin', {
bind: function (el, binding, vnode) {
el.style.position = 'fixed'
el.style.top = binding.value + 'px'
}
})
<input v-pin>
自定义事件
.sync(vue3中被摒弃)
实现父子数据双向联动,修改任意一个另一个也会改变。
对于 Vue.js 2.x,.sync
实际上是一种语法糖,它简化了双向绑定的模式。下面是一个简单的示例来说明 .sync
语法糖的构造:
// 父组件中
<template>
<ChildComponent :foo.sync="bar" />
</template>
<script>
export default {
data(){
return {
bar:'你好啊'
}
};
</script>
// 子组件中
<template>
<input :value="foo" @input="$emit('update:foo', $event.target.value)" />
</template>
<script>
export default {
props: ['foo']
};
</script>
在父组件中,通过 :foo.sync="bar"
将 bar
传递给子组件的 foo
属性,并实现双向绑定。注意,.sync
修饰符实际上是通过 :value
和 @input
的组合来实现的。
在子组件中,使用 :value="foo"
将父组件传递的值绑定到输入框的 value
属性上。然后,在输入框的 input
事件中,通过 $emit
方法触发一个名为 update:foo
的自定义事件,并传递当前输入框的值。父组件监听到该事件后,将更新其绑定的属性 bar
。
总结一下,.sync
语法糖的构造实际上是通过使用 :value
和 @input
的组合,结合自定义事件和 $emit
方法来实现父子组件之间的双向绑定。
v-model(在vue3中构造发生改变)
通过v-mode语法糖实现单纯子传父功能
// 父组件
<template>
<div>
<ChildComponent v-model="childData" />
<p>Received data from child: {{ childData }}</p>
</div>
</template>
<script>
export default {
data(){
return {
childData:'你好啊'
}
};
</script>
// 子组件
<template>
<div>
<input v-model="internalData" />
</div>
</template>
<script>
export default {
data() {
return {
internalData: ''
};
},
watch: {
internalData(newValue) {
this.$emit('input', newValue);
}
}
};
</script>
在父组件中,我们使用 v-model="childData"
的语法糖将 childData
数据属性传递给子组件。子组件使用 v-model
中绑定的 input
事件来监听输入框的值变化,并将新值通过 $emit('input', newValue)
发送给父组件。
在子组件中,我们使用 v-model
绑定了输入框的值到子组件的 internalData
数据属性上。然后,我们使用 watch
监听 internalData
的变化,并在变化时触发 input
事件,将新值传递给父组件。
父组件通过 v-model
绑定的 childData
数据属性会自动接收子组件传递的值,并在父组件中更新。
通过这种方式,使用 v-model
语法糖可以更简洁地在子组件中向父组件传递数据,并实现双向绑定的效果。
事件&按键修饰符
.native修饰符
作用 : 对于组件,用于监听原生事件,而不是组件内部使用 vm.$emit
触发的事件
原理:在封装好的组件事件上加 事件.native
事件会加在组件内部的根元素上,和scss样式的 ::v-deep
相似
总结: 给组件绑定原生事件后, 如果没触发就加 .native
注意事项: 只有原生事件 (click mouseenter mouseleave...) 才需要加 .native
父组件:
<template>
<div>
<!-- <el-button></el-button> 内部触发了 click 事件 -->
<!-- <el-dropdown-item></el-dropdown-item> 内部没有触发 click 事件 -->
<son @click.native="sonClick" />
</div>
</template>
<script>
import son from './son.vue'
export default {
components: {
son
},
methods: {
sonClick() {
console.log('son 被点了')
}
}
}
</script>
子组件
<template>
<!-- 如果没有使用 native , 子组件内部使用 `vm.$emit` 才能触发事件 -->
<!-- <div @click="$emit('click')"> -->
<div>
我是 SON 组件
</div>
</template>
API
$attrs
在 Vue 中,$attrs
是一个特殊的属性,用于在子组件中接收父组件传递的非props属性。它是一个对象,包含了父组件中传递的所有非props属性。
注意:获取所有非props组件属性(
class
和style
除外)非props属性:没有在子组件中被props接收的属性
vueCopy code<template>
<div>
<p>子组件</p>
<p>属性A: {{ $attrs.attrA }}</p>
<p>属性B: {{ $attrs.attrB }}</p>
</div>
</template>
<script>
export default {
name: 'ChildComponent',
mounted() {
console.log(this.$attrs);
}
}
</script>
在上面的示例中,父组件可以像这样传递属性给子组件:
vueCopy code<template>
<div>
<p>父组件</p>
<ChildComponent attrA="Value A" attrB="Value B" />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
}
</script>
在子组件中,$attrs
将包含父组件传递的 attrA
和 attrB
属性。
$listeners
在 Vue 中,$listeners
是一个特殊的属性,用于在子组件中接收父组件传递的事件监听器。它是一个对象,包含了父组件中传递的所有事件监听器。
注意:包含了父作用域中的
v-on / @
事件监听器 (不含.native
修饰器的)
<template>
<div>
<p>子组件</p>
<button @click="$listeners.click">点击我</button>
<button @click="$listeners.changePage">点击我切换页面</button>
</div>
</template>
<script>
export default {
name: 'ChildComponent',
mounted() {
console.log(this.$listeners);
}
}
</script>
在上面的示例中,父组件可以像这样传递事件监听器给子组件:
<template>
<div>
<p>父组件</p>
<ChildComponent @click="handleClick" @changePage="changePage"/>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
handleClick() {
console.log('点击事件触发');
},
// 自定义的方法,传给子组件使用
changePage(){
console.log('页面改变了')
}
}
}
</script>
在子组件中,$listeners
将包含父组件传递的 click
事件监听器。子组件可以通过 @click="$listeners.click"
将该事件监听器绑定到按钮的点击事件上,使得点击按钮时触发父组件中定义的 handleClick
方法。
需要注意的是,$listeners
对象中的事件监听器只能通过 v-on
或 @
语法绑定到子组件的具体元素上。它不会自动应用到子组件根元素上。如果要将父组件的事件监听器应用到子组件的根元素上,可以使用 v-on="$listeners"
或 v-bind="$listeners"
来手动绑定。
插槽
🥀默认插槽
使用场景:一个子组件中一个或多个插槽插入相同内容的标签。
🥀具名插槽
使用场景:一个子组件中要用到多个插槽来插入不同的标签
🥀作用域插槽
在Vue.js中,"作用域插槽"(Scoped Slots)是一种特殊类型的插槽,允许组件在插槽中传递数据给父组件,使得父组件可以使用这些数据进行更复杂的处理或渲染。
使用作用域插槽时,您可以在组件中定义带有特殊属性的插槽,并将数据作为该属性的值传递给插槽内容。
下面是一个使用作用域插槽的示例:
<template>
<div>
<h1>组件标题</h1>
<slot :user="user" :list="list" :age="age">
<p>默认插槽的内容</p> //当父组件中未修改插槽时显示,否则被替换
</slot>
</div>
</template>
在上面的例子中,我们在<slot>
元素上使用v-bind
指令来绑定一系列的属性,他们被集合成一个对象{user:"user",list="list",age="age"}
。
在父组件中,可以使用带有特殊语法的<template>
元素来接收这个对象:
<template>
<div>
<my-component>
<template v-slot:obj="obj"> //v-slot可简写为#
<p>年龄,{{ obj.age }}!</p>
</template>
</my-component>
</div>
</template>
在这个例子中,我们使用v-slot
指令来接收名为user
的作用域插槽。通过特殊的语法"{ user }"
,我们将插槽中传递的数据解构为一个名为user
的变量,然后可以在插槽内容中使用这个变量进行渲染。
最终渲染的结果将是:
<div>
<h1>组件标题</h1>
<p>欢迎,John Doe!</p>
</div>
通过使用作用域插槽,您可以在组件中传递数据给父组件,并在父组件中使用这些数据进行更高级的渲染或处理操作。这使得组件的灵活性和可重用性更进一步提升。
生命周期钩子
八大生命周期钩子函数:
- 第一阶段,声明阶段 只能创建组件才触发
1.beforeCreate:data数据初始化之前,组件还没有数据
2.created: data数据初始化之后,可以获取到组件的数据和方法
3.beforeMount:DOM渲染之前,DOM还没渲染
4.mounted:DOM渲染之后,可以操作DOM了
- 第二阶段,运行阶段 数据更新->视图更新
5.beforeUpdate: 数据更新,DOM更新前
6.updated : 数据更新,DOM更新后
- 第三阶段,销毁阶段 组件销毁(v-if,动态组件,路由跳转)
7.beforeDestroy: 组件销毁前 //关闭定时器,全局事件(resize,scroll)
8.destroyed : 组件销毁后
- 用于处理组件被缓存时的激活和停用事件。
9.activated:组件激活时被调用
10.deactivated:组件失活时被调用(页面跳转、组件消失)
注意:
我们通常在created钩子执行时发送ajax请求,这样就避免了一次页面渲染,提高性能。
如果在mounted执行时发送ajax请求,它会先DOM渲染,由于没有发ajax所以渲染的是空数据。此时我们发送ajax获得数据,数据更新DOM又渲染一次造成不必要的性能浪费。
router路由
作用:以单页面实现页面跳转的效果,网页不会刷新。主要提高用户体验。
缺点:首次加载较慢
本质:路径与组件的映射关系,改变url地址后缀的hash值,不同的页面组件生效。
路由原生语法(了解)
两种:hash 模式和 history 模式
https://blog.csdn.net/qq_53061847/article/details/125018494
hash模式
vue2中最高版本的router是5.3.1,更高版本是给vue3使用的。
npm i vue-router@5.3.1
vue中默认的hash模式路由
#/xxx/ 的模式就是hash模式,url地址的hash值改变不会刷新页面
https://music.163.com/#/my/
原理:
①点a
②url地址改变 http://localhost:8080/#/xxx
③路由会检测到url地址改变,hashChange事件触发
④去路由表routes查复合path路径的对象
⑤去router-view去渲染 对象.component 保存的组件
用法:
1.在src下创建一个views文件夹,专门用来存储页面组件,配合路径使用
|__src
|__views 页面组件,配合路径使用
|__FindPage.vue
|__MyPage.vue
|__PartPage.vue
|__compontents 复用组件,展示数据,常用于复用
|__HeadPage.vue
|__BodyPage.vue
|__FootPage.vue
2.在src下创建一个router文件,在文件下生成一个index.js文件,专门用来统一管理所有路由。
App.vue文件
<template>
<div>
<div class="footer_wrap">
<!-- <a href="#/find">发现音乐</a>
<a href="#/my">我的音乐</a>
<a href="#/part">朋友</a>
-->
<!-- <router-link to="find"> 是路由自带的标签用于代替a标签,to相当于href可省略#。同时自带/-->
<router-link to="find">发现音乐</router-link>
<router-link to="my">我的音乐</router-link>
<router-link to="part">朋友</router-link>
</div>
<div class="top">
<!-- 将来我们需要指定路由出口的地方 -->
</div>
</div>
</template>
index.js文件
// ①引入路由
import VueRouter from 'vue-router'
import Vue from 'vue'
// ②注册路由组件
Vue.use(VueRouter)
// ③创建路由实例对象,配置路由规则
const router = new VueRouter({
routes: [
{ path: '/', redirect: '/find' },
{ path: '/find', component: ()=>import('@/view/FindPage.vue')},
{ path: '/my', component: ()=>import('@/view/MayPage.vue')},
{ path: '/part', component: ()=>import('@/view/PartPage.vue')},
{path: '/*', component: ()=>import('@/view/NoFindPage.vue')}
] //路由规则,url和组件的对应关系
})
// ④将配置好的路由对象暴露出去
export default router
3.在main.js中引入路由,可全局使用
// ⑤引入路由对象
import router from '@/router/index'
new Vue({
router, // ⑥注入router
render: h => h(App),
}).$mount('#app')
4.指定路由出口,通常写在App.vue文件中
<template>
<div>
<div class="footer_wrap">
<router-link to="find">发现音乐</router-link>
<router-link to="my">我的音乐</router-link>
<router-link to="part">朋友</router-link>
</div>
<div class="top">
<!-- ⑦指定路由出口,类似插槽的占位 -->
<router-view></router-view>
</div>
</div>
</template>
history 模式
特点:好看,没有#
核心:history.pushState() 给浏览器增加一条历史记录,用户切换历史记录不会刷新页面。
配置:new VueRouter({mode:'history'}),和路由表平级。
const router = new VueRouter({
mode:'history', //开启history模式
routes: [
{ path: '/', redirect: '/find' },
{ path: '/find', component: ()=>import('@/view/FindPage.vue')},
{ path: '/my', component: ()=>import('@/view/MayPage.vue')},
{ path: '/part/:name/:name1', component: ()=>import('@/view/PartPage.vue')},
{path: '/*', component: ()=>import('@/view/NoFindPage.vue')}
] //路由规则,url和组件的对应关系
})
如果采用history模式,用户在某个路由下刷新页面,浏览器会以这个路由地址请求数据。服务器没有路由对应的资源,返回404错误。
注意:需要后端配合,如果用户访问的是一个后端不存在的资源路径(在某个路由地址下刷新页面),后端返回index.html
路由懒加载
将组件的加载封装在匿名函数中,当哪个路由被使用时触发对应的函数加载对应的组件。
好处:相对于一次性加载所有组件,懒加载减轻了服务器压力,提高了用户体验。
const Home = () => import('./components/Home.vue');
const About = () => import('./components/About.vue');
const Contact = () => import('./components/Contact.vue');
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '/contact', component: Contact },
];
const router = new VueRouter({
routes,
});
$route和$router区别
$route
和$router
是Vue Router提供的两个不同的对象,用于在Vue.js应用程序中处理路由相关的信息和导航。
-
$route
对象:$route
是一个表示当前活动路由的对象,包含了当前路由的信息,例如路径、参数、查询参数、哈希等。- 它是一个只读属性,用于访问当前路由的信息。
- 您可以通过
this.$route
在Vue组件中访问到当前路由对象。
-
$router
对象:$router
是Vue Router的实例,它提供了一些方法来进行编程式的路由导航,例如push
、replace
和go
等。- 它是用于在Vue组件中进行路由导航的工具,允许您在代码中动态地进行路由跳转。
$router
对象具有一些方法来处理路由导航,例如this.$router.push
用于导航到新的路由。
总结:
$route
是一个对象,用于访问当前活动路由的信息。$router
是Vue Router的实例,提供了方法用于进行编程式的路由导航。
因此,您可以使用$route
来访问当前路由的信息,而使用$router
来执行编程式路由导航操作。
路由传参跳转
1.声明式导航
1.声明式导航进行路由传参
有两种:一种叫查询参数,一种叫动态参数
2.声明式导航进行路由传参的实现
查询参数方式:①
②目标组件 {{$route.query.属性名}} 方法中 $route 前加this
动态参数方式:①
②路由表中对应路由规则path中添加 path:'/路径/:属性名/:属性名'
③目标组件 {{$route.params.属性名}} 方法中 $route 前加this
2.编程式导航(重点)
第一种 this.$router.push({path:'/路径'})(跳转到路由表中对应路径的路由)
传参:①--->this.$router.push({path:'/路径',query{属性:值}
)
---> 目标组件 $route.query.属性
②--->this.$router.push({path:'/路径/值
')
--->路由表{path: '/路径/:属性名
', component:''}
--->目标组件 $route.query.属性
第二种 this.$router.push({name:'路由名'
})(跳转到路由表中对应路由名的路由)
传参:①--->this.$router.push({name:'路由名'
,query
)
---> 目标组件 $route.query.属性
②--->this.$router.push({name:'路由名'
,params
)
---> 目标组件 $route.params.属性
3.前进或后退导航
使用$router.go
方法进行前进或后退导航:
// 前进一步
this.$router.go(1);
@click("$router.go(1)")
// 后退一步
this.$router.go(-1);
@click("$router.go(-1)")
// 前进两步
this.$router.go(2);
@click("$router.go(2)")
路由重定向
作用:输入网址时让其强制转到某个路由界面。
用法:
// 在路由表第一个写
{ path: '/', redirect: ()=>import('@/view/首页组件.vue')},
vue路由 - 404
404:找不到路径匹配时,给个提示页面
路由最后,path匹配*(任意路径) - 前面路径都不匹配就匹配这个。
为什么要写在最后呢?应为路由表匹配规则从上到下,匹配成功下面将不再执行。
const router = new VueRouter({
routes: [
{ path: '/', redirect: '/find' },
{ path: '/find', component: ()=>import('@/view/FindPage.vue')},
{ path: '/my', component: ()=>import('@/view/MayPage.vue')},
{ path: '/part/:name/:name1', component: ()=>import('@/view/PartPage.vue')},
{path: '/*', component: ()=>import('@/view/NoFindPage.vue')}
] //路由规则,url和组件的对应关系
})
组件缓存
使用场景:路由切换, 保证组件不被销毁
语法
include
- 字符串或正则表达式。指定哪些组件会被缓存。exclude
- 字符串或正则表达式。指定哪些组件不会被缓存。max
- 数字。最多可以缓存多少组件实例。
<keep-alive include="组件名"> //
<router-view></router-view>
</keep-alive>
两个钩子函数
activated
和 deactivated
是 Vue 组件的生命周期钩子函数,用于处理组件被缓存时的激活和停用事件。
当一个组件被 <keep-alive>
缓存时,它可能会经历以下生命周期阶段:
- 创建和挂载阶段:
created
: 组件实例被创建后调用。mounted
: 组件挂载到 DOM 后调用。
- 激活和停用阶段:
activated
: 当组件被缓存并激活时调用。在组件第一次被缓存后,每次激活时都会调用该钩子函数。deactivated
: 当组件被缓存并停用时调用。在组件从活动状态转为非活动状态时,每次停用时都会调用该钩子函数。
- 销毁阶段:
beforeDestroy
: 组件实例销毁之前调用。destroyed
: 组件实例销毁后调用。
通过使用 activated
和 deactivated
钩子函数,你可以在组件被缓存时执行特定的操作,例如重新加载数据或执行清理操作。
利用activated钩子函数,手动让组件每次激活都会发送新的axios请求
App.vue文件
<!-- 一级目录 -->
<keep-alive>
<router-view></router-view>
</keep-alive>
面经详情页.vue组件中
export default {
name: 'ArticleDetailPage',
//组件激活时
activated() {
//发送axios请求
},
vuex
本质:一个公共仓库,用来存储公共数据和方法。
使用场景:大型项目,需要较复杂的数据处理(父传子,子传父解决不了的情况,比如一棵树两层三层之间兄弟互传数据)。
结构
export default new Vuex.Store({
//公共数据,类似于data,不同于data的函数体,他是一个唯一对象(vuex是一个公共库)不用担心变量名污染问题。
state: {},
//公共数据的计算属性,数据只读,不允许修改。利用旧数据得到新数据
getters: {},
//唯一修改数据的方法存放处(只能写同步代码,作者要求)
mutations: {},
//写异步操作的地方,不可以直接修改state的数据,要通知mutation去修改
actions: {},
//创建小仓库,里面包含大仓库中所有方法。注意一定要写namespaced:true,不然里面定义的属性或方法会被当成公共的。
modules: {
子仓库名:{
namespaced:true, //使其成为带命名空间的独立模块。
state: {},
getters: {},
mutations: {},
actions: {},
modules:{}
}
}
})
使用vuex
在创建项目时,选择自定义模式,勾选Vuex,在src下自动生成一个store文件和一个index.js文件。
|___src
|___store
|___index.js //vuex仓库所在文件
state单一状态树
它作为一个“唯一数据源”而存在。这也意味着,每个应用将仅仅包含一个 store 实例
它和vue实例中的data最寻同样的规则。
获取state中数据的方法:
在vue文件中(原生)
---this.$store.state
.小仓库名.属性名 (只在函数方法中可用)
---{{$store.state
.小仓库名.属性名}}
在vue文件中(辅助函数)
import {mapState
} from 'vuex'
computed:{...mapState
('小仓库',['属性名1','属性名2'])}
---{{属性名}}
---this.属性名
在js文件按中
import store from 'vuex'
---store.state
.小仓库名.属性名 (只在函数方法中可用)
getters
他和vue实例中的计算属性具有相同规则
特点:数据只读,不允许修改。
应用:可以利用一些数组或字符串方法获得一些新数据。
获取getter中数据的方法:
在vue文件中(原生)
---this.$store.getters
.小仓库名.属性名 (只在函数方法中可用)
---{{$store.getters
.小仓库名.属性名}}
在vue文件中(辅助函数)
import {mapGetters
} from 'vuex'
computed:{...mapGetters
('小仓库名',['属性名1','属性名2'])}
---{{属性名}}
---this.属性名
在js文件按中
import store from 'vuex'
---store.getters
.小仓库名.属性名 (只在函数方法中可用)
mutations
唯一修改数据的方法存放处(只能写同步代码,作者要求)
特点:mutations中自带两个属性,state
和 paylode
- state: 就是数据对象
- paylode: 提交载荷,大多情况下载荷应该是一个对象,这样我们就可以一次传递多个数据。
mutations: {
increment (state, payload) { //这里我们只能有一个payload载荷(形参),只能接收一条数据。state是回调。
state.count += payload.amount
}
}
获取mutations中方法的方法:
vue文件中的方法
this.$store.commit('小仓库名/increment', 10) //一条数据
this.$store.commit('小仓库名/increment', {}) //多条数据
this.$store.commit('小仓库名/increment', [10,11,12])//多条数据
js文件中的方法
import store from '@/store'
store.commit('小仓库名/increment', 10) //一条数据
store.commit('小仓库名/increment', {}) //多条数据
store.commit('小仓库名/increment', [10,11,12])//多条数据
Actions
写异步操作的地方,不可以直接修改state的数据,要通知mutation去修改
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,
因此你可以调用
context.commit
提交一个 mutation,或者通过
context.state
和context.getters
来获取 state 和 getters。
特点:mutations中自带两个属性,context
和 paylode
- context: 与 store 实例具有相同方法和属性的对象(但不是store)
- paylode: 提交载荷,大多情况下载荷应该是一个对象,这样我们就可以一次传递多个数据。
actions: {
_increment (state, payload) { //这里我们只能有一个payload载荷(形参),只能接收一条数据。state是回调。
context.commit('小仓库名/方法名',参数) //调用mutations中的方法,可传参
}
}
获取actions中方法的方法:
vue文件中的方法
// 这种方法只能在函数体中使用,不能直接暴露在外使用
this.$store.dispatch('小仓库名/_increment', 10) //一条数据
this.$store.dispatch('小仓库名/_increment', {}) //多条数据
this.$store.dispatch('小仓库名/_increment', [10,11,12])//多条数据
辅助函数写法
import { mapActions } from 'vuex'
methods: {
...mapActions('小仓库名',['方法名']) //这样小仓库中Actions对象中的方法就被映射过来了,可直接使用。
}
js文件中的方法
import store from '@/store'
// 这种方法只能在函数体中使用,不能直接暴露在外使用
store.dispatch('小仓库名/_increment', 10) //一条数据
store.dispatch('小仓库名/_increment', {}) //多条数据
store.dispatch('小仓库名/_increment', [10,11,12])//多条数据
module
Vuex 允许我们将 store 分割成模块(module)。
每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
注意: 子模块中一定要加 namespaced: true,主要作用让子模块成为独立模块拥有独立作用域。
抽离写法
store/cart.js 小仓库模块
import axios from 'axios'
export default {
namespaced: true, //开启独立作用域
state: {},
getters: {},
mutations: {},
actions: {}
}
store/index.js 大仓库(唯一公共仓库)
import Vue from 'vue'
import Vuex from 'vuex'
import cart from './cart' //引入子仓库
//注册Vuex
Vue.use(Vuex)
//创建并暴露出store仓库
export default new Vuex.Store({
state: {},
getters: {},
mutations: {},
actions: {},
modules: {
cart //嵌入子仓库
}
})
修改组件内样式
scss使用 ::v-deep
sass和less的样式穿透 使用 /deep/
stylus的样式穿透 使用 >>>