1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象;
2.root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法;
3.root容器里的代码被称为【Vue模板】;
4.Vue实例和容器是一一对应的;
5.真实开发中只有一个Vue实例,并且会配合着组件一起使用;
6.{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性;
7.一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新;
注意区分:js表达式 和 js代码(语句)
1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方:
(1). a
(2). a+b
(3). demo(1)
(4). x === y ? 'a' : 'b'
2.js代码(语句)
(1). if(){}
(2). for(){}
Vue模板语法有2大类:
1.插值语法:
功能:用于解析标签体内容。
写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性。
** 2.指令语法:**
功能:用于解析标签(包括:标签属性、标签体内容、绑定事件…)。
举例:v-bind:href=“xxx” 或 简写为 :href=“xxx”,xxx同样要写js表达式,
且可以直接读取到data中的所有属性。
备注:Vue中有很多的指令,且形式都是:v-???,此处我们只是拿v-bind举个例子。
Vue中有2种数据绑定的方式:
1.单向绑定(v-bind):数据只能从data流向页面。
2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。
备注:
1.双向绑定一般都应用在表单类元素上(如:input、select等)
2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。
<!-- 普通写法 -->
单向数据绑定:<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/>
<template>
<div>
<!--绑定样式-->
<div :style="['font-size:50px','color:red']">box</div>
<div :style="[fontSize,bgColor]">box</div>
<hr>
<!--绑定类-->
<!-- <div class="one" :class="'two'">aaaaaaaa</div>-->
<div class="one" :class="two">aaaaaaaa</div>
<!-- <div class="one" :class="['one','two']">aaaaaaaa</div>-->
<!--数组方式-->
<div class="one" :class="[one,two]">元素为变量</div>
<div class="one" :class="boxStyle">数组为变量</div>
<hr>
<!--对象方式 {类名:真假值} 真则添加 假则不添加-->
<div :class="{one:isone,two:istwo}">{类名:真假值} 真则添加 假则不添加</div>
<div :class="{three}">键值相同可简写</div><!--键值相同可简写-->
<!--函数返回值方式-->
<div :class="getStyleObj()">函数返回对象</div>
<div :class="getStyleArr()">函数返回数组</div>
</div>
</template>
<script>
/*
* 单向绑定 v-bind 简写 :
*
* */
export default {
name: 'App',
data() {
return {
size: 100,
fontSize: 'font-size:50px',
bgColor: 'background-color:blue',
two: 'two',
one: 'one ',
boxStyle: ['one', 'two'],
isone: false,
istwo: true,
three: true,
};
},
methods: {
getStyleArr() {
return [this.one, this.two];
},
getStyleObj() {
return { one: this.isone, two: this.istwo };
},
},
};
</script>
1.定义:要用的属性不存在,要通过已有属性计算得来。
2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
3.get函数什么时候执行?
(1).初次读取时会执行一次。
(2).当依赖的数据发生改变时会被再次调用。
4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
5.备注:
(1)计算属性最终会出现在vm上,直接读取使用即可。
(2)如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
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]
}
}
}
在前端开发中,需要经常和用户交互
绑定事件监听器指令:v-on
缩写: @ (语法糖)
参数: $event
v-on事件修饰符号
–.stop 阻止事件冒泡
–.self 当事件在该元素本身触发时才触发事件
–.capture 添加事件侦听器是,使用事件捕获模式
–.prevent 阻止默认事件
–.once 事件只触发一次
1.v-if
写法:
(1).v-if=“表达式”
(2).v-else-if=“表达式”
(3).v-else=“表达式”
适用于:切换频率较低的场景。
** 特点:不展示的DOM元素直接被移除。**
注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。
2.v-show
写法:v-show=“表达式”
适用于:切换频率较高的场景。
特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉(display:none)
3.备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。
v-for指令:
1.用于展示列表数据
2.语法:v-for=“(item, index) in xxx” :key=“yyy”
3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
<!-- 遍历数组 -->
<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>
:::info
面试题:react、vue中的key有什么作用?(key的内部原理)
1. 虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
2.对比规则:
(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
(2).旧虚拟DOM中未找到与新虚拟DOM相同的key
创建新的真实DOM,随后渲染到到页面。
3. 用index作为key可能会引发的问题:
1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
2. 如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题。
4. 开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
使用index作为key是没有问题的。
:::
v-model的修饰符号:
.lazy 懒加载修饰符
.number 修饰符让其转换为 number 类型
.trim修饰符可以自动过滤掉输入框的首尾空格
1、使用v-model 可以代替name 变量相同则代表同组
2、单选框状态发生改变时 会把value中的数据传到 v-model绑定的变量中
3、初始选项不必再使用checked ,直接给变量赋初值即可
<input type="radio" name="sex" value="女">女-->
<input type="radio" value="男" v-model="sex">男
<input type="radio" value="女" v-model="sex">女
<br>{{sex}}
data() {
return {
msg: 'this is a test',
sex:'男',
isRead:false,
hobby:[],
language:'vue',
languages:'vue',
}
1、当只需要一个复选框为真假值判断的时候,v-model传递一个布尔值,会自动根据选种情况来改变 变量值的真或假
2、当需要多个复选框同组使用时 , 需要使用数组变量接收 ,会把选中项的value值存到数组中
使用v-model 可以代替name 变量相同则代表同组
<input type="checkbox" v-model="isRead">我已阅读协议{{isRead}}
<br>
<input type="checkbox" v-model="hobby" value="smoke">抽烟
<input type="checkbox" v-model="hobby" value="drink">喝酒
<input type="checkbox" v-model="hobby" value="hotHead">烫头
<br>
{{hobby}}
data() {
return {
msg: 'this is a test',
sex:'男',
isRead:false,
hobby:[],
language:'vue',
languages:'vue',
}
1、单选时
1)v-model绑定在select标签上 可以代替name的功能
2)使用一个字符串接受选中value值
3)设置初始选项时可以将目标选项的value赋给字符串变量
2、多选时 multiple
会自动将变量转成数组类型,并将选中选项的value值存到数组中
<select v-model="language">
<option value="java">java</option>
<option value="php">php</option>
<option value="vue">vue</option>
<option value="python">python</option>
</select>
{{language}}
<br>
<select v-model="languages" multiple>
<option value="java">java</option>
<option value="php">php</option>
<option value="vue">vue</option>
<option value="python">python</option>
</select>
{{languages}}
data() {
return {
msg: 'this is a test',
sex:'男',
isRead:false,
hobby:[],
language:'vue',
languages:'vue',
}
props配置项
//父组件
<my-conn :article="article"></my-conn>
//子组件
<li v-for="item in article">{{item}}</li>
export default {
name: "MyConn",
props:{
article:{
type:Array,
}
}
}
**通过自定义事件 e m i t ( ) 和事件监听实现 ∗ ∗ 子组件通过使用 t h i s . emit()和事件监听实现** 子组件通过使用this. emit()和事件监听实现∗∗子组件通过使用this.emit(‘自定义事件名称’,传递参数data)
父组件通过在组件标签上使用<子组件 @自定义事件名称=“方法fun”>子组件>
fun(子组件传递的参数data){}
//子组件 my-conn
<button @click="changeNum(2)">++++</button>
methods:{
changeNum(n){
this.$emit("myCountEvent",n)
}
}
//父组件
<my-conn @myCountEvent="myDemo"></my-conn>
methods:{
myDemo(data){
this.count += data
}
}
可以通过$parent获取父组件中的属性和方法,可连续调用访问多层
如果访问跟组件可直接调用$root方法
在Vue2中可以使用$children 获取一个子组件数组,Vue3删除了该方法
可以先使用 ref属性标记子组件 (类似id属性) ref="xxx"
再调用 $refs.xxx 获取子组件
<!-- 默认插槽 ==>父组件 -->
<MyBar>
<button>默认插槽--提交</button>
</MyBar>
<!-- 默认插槽 ==>子组件-->
<slot>默认值</slot>
:::info
需要使用包裹内容
template中设置属性
1. v-slot:子组件中插槽name值 简写 #子组件中插槽name值
2. Vue2中还可使用 slot=“子组件中插槽name值” Vue3已删除
:::
<!-- 具名插槽 ==>父组件-->
<MyBar>
<template v-slot:btn>
<button>具名插槽--提交</button>
</template>
<template #one>
<a href="">具名插槽--one</a>
</template>
<template #two>
<a href="">具名插槽--two</a>
</template>
</MyBar>
<!-- 具名插槽 ==>子组件-->
<slot name="btn">默认值1</slot>
<br>
<slot name="one">默认值2</slot>
<br>
<slot name="two">默认值3</slot>
<br>
:::info
理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
(userinfo和school数据在子组件Mybar中,但使用数据所遍历出来的结构由父组件MySidebar决定)
使用方法 :
v-slot:子组件中插槽的name值=“自定义对象” ,子组件传的所有数据都会存到自定义的对象中
简写:#子组件中插槽的name值=“自定义对象”
:::
<!--作用域插槽 ==>父组件 -->
<MyBar>
<!-- <template v-slot:user="user">-->
<template #user="hello">
<p>作用域插槽--{{hello.userinfo.name}}-{{hello.userinfo.age}}--{{hello.userinfo.sex}}</p>
<p v-for="item in hello.school">{{item}}</p>
</template>
</MyBar>
<!-- 作用域插槽 ==>子组件-->
<slot name="user" :userinfo="userinfo" :school="school"></slot>
data(){
return{
title:"this is a title",
userinfo:{name:'张三',age:24,sex:'男'},
school:['融职教育','清华大学','北京大学','麻省理工']
}
}
Vue3
beforeUnmount()
unmounted()
(4) nextTick
this.$nextTick(回调函数)
(5)Vue-router的生命周期钩子
:::info
:::
activated路由组件被激活时触发。
deactivated路由组件失活时触发。
import axios from "axios";
const server = axios.create({
baseURL: 'https://api.shop.eduwork.cn',
timeout: 10000,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
//请求拦截器
server.interceptors.request.use(
config => {
console.log('-------------------请求拦截器----------------------')
config.headers.Authorization = `Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2FwaS5zaG9wLmVkdXdvcmsuY24vYXBpL2F1dGgvbG9naW4iLCJpYXQiOjE2ODE4MTk0OTQsImV4cCI6MTY4MjE3OTQ5NCwibmJmIjoxNjgxODE5NDk0LCJqdGkiOiJ4clZ6c2ZVelpySVJnYk1wIiwic3ViIjoiODk0MiIsInBydiI6IjIzYmQ1Yzg5NDlmNjAwYWRiMzllNzAxYzQwMDg3MmRiN2E1OTc2ZjcifQ.vsKQvw9m0HhWfUbzJuOvBvWVK4BnAxi-vOSNCkBwJoQ`
return config
},
err => {
return Promise.reject(error)
}
)
//响应拦截器
server.interceptors.response.use(
resp => {
console.log('-------------------响应拦截器----------------------')
return resp
},
err => {
return Promise.reject(err)
}
)
export function get(url) {
return server.get(url)
}
export function getParams(url, params) {
return server.get(url, {params})
}
export function post(url, params) {
return server.post(url, params)
}
export function put(url, params) {
return server.put(url, params)
}
export function del(url, params) {
return server.delete(url, params)
}
npm i vue-router
Vue.use(VueRouter)
import router from './router'
createApp(App).use(router).mount('#app')
//引入路由的创建方法和模式
import {createRouter,createWebHistory} from 'vue-router'
//引入组件
import About from "@/view/About";
import Home from "@/view/Home";
import User from "@/view/User";
// 声明变量
const routes = [
{
path:'/',
name:'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
},
{
path: '/user',
name: 'User',
component: User
}
]
//创建路由
const router = createRouter({
history:createWebHistory(process.env.BASE_URL), //历史模式
// routes:routes,
routes
})
export default router
<router-link to="/">首页</router-link> |
<router-link active-class="active" to="/about">关于我们</router-link> |
<router-link to="/user">个人中心</router-link>
//active-class="active" 当跳转到当前路由时添加active类样式
路由是由多个URL组成的,使用不同的URL可以相应的导航到不同的位置
Vue-Router在切换页面时是没有重新进行请求的,使用起来就好像页面是有状态的一样
借助了浏览器的History API来实现的,这样可以使得页面跳转而不刷新,页面的状态就被维持在浏览器中
vue-router中默认使用的是hash模式,也就是会出现如URL:‘localhost:8080/#/’ URL中带有#号
有三种模式
Hash: 使用URL的hash值来作为路由,用来指导浏览器动作的,对服务器端完全无用,支持所有浏览器。
History: 以来HTML5 History API 和服务器配置。
Abstract: 支持所有javascript运行模式。如果发现没有浏览器的API,路由会自动强制进入这个模式。
引入路由
:::info
//引入路由的创建方法和模式
import {createRouter,createWebHistory,createWebHashHistory} from ‘vue-router’
:::
创建路由
const router = createRouter({
//设计模式
history:createWebHistory(process.env.BASE_URL), //历史模式
// history:createWebHashHistory(process.env.BASE_URL),//哈希模式
//定义路由组件
/*
routes:[
{
path:'/',
name:'Home',
component: Home
},
]
*/
//外部引入变量方式
// routes:routes,
//简写
routes
})
引入组件的方式
方式一:普通方式:
打包时会将所有路由全部打包到一个js文件中,并加载全部组件
//引入组件
import Home from "@/view/Home";
import About from "@/view/About";
import User from "@/view/User";
const routes = [
{
path:'/',
name:'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
},
{
path: '/user',
name: 'User',
component:User
}
]
方式二:懒加载:
通过下面方法引入组件,会在打包时会打包成多个js文件,访问哪个路由加载哪个js文件(懒加载) — 加载速度快
const routes = [
{
path:'/',
name:'Home',
component: ()=>import('../view/Home')
},
{
path: '/about',
name: 'About',
component: About
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
//通过下面方法引入组件,会在打包时会打包成多个js文件,访问哪个路由加载哪个js文件(懒加载) --- 加载速度快
/* component: () => import(/!* webpackChunkName: "about" *!/ '../views/About.vue')*/
/*component: ()=>{return import('../view/About')}*/
component: ()=>import('../view/About')
},
{
path: '/user',
name: 'User',
component:()=>import('../view/User')
}
]
拆分写法
//引入路由的创建方法和模式
import {createRouter,createWebHistory,createWebHashHistory} from 'vue-router'
const Home = ()=> import('../view/Home')
const About = ()=> import('../view/About')
const User = ()=> import('../view/User')
// 声明变量
const routes = [
{
path:'/',
name:'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
},
{
path: '/user',
name: 'User',
component:User
}
]
//创建路由
const router = createRouter({
//设计模式
history:createWebHistory(process.env.BASE_URL), //历史模式
// history:createWebHashHistory(process.env.BASE_URL),//哈希模式
// routes:routes,
routes
})
export default router
使用路由:在入口js文件中
import {createApp} from 'vue'
import App from './App'
import router from './router'
createApp(App).use(router).mount('#app')
标签在打包时会编译成a标签,如果想要自定义其他标签的话在Vue3中需要通过以下方法:
<router-link to="/about" custom v-slot="{navigate}">
<button @click="navigate" @keypress.enter="navigate" role="link">关于我们</button>
</router-link>
//或
// 通过在全局路由追加历史记录实现
<button @click="$router.push('/user')" :class="{active:$route.path ==='/user'}">个人中心</button>
$router 表示全局路由
$route 表示当前路由
的replace属性push
和replace
,push
是追加历史记录,replace
是替换当前记录。路由跳转时候默认为push
replace
模式:News
const routes = [
{
path:'/',
name:'Home',
component: Home
},
{
path: '/user',
name: 'User',
component:User,
// /user/order
children: [
{
path:'', //默认页面
component:MyOrder,
},
{
path:'order', //此处一定不要写:/order
name:'MyOrder',
component:MyOrder,
},
{
path:'setting', //此处一定不要写:/setting
name:'MySetting',
component:MySetting,
},
{
path:'page/:id',
name:'MyPage',
component:MyPage,
},
]
}
]
<router-link to="/user/order">我的订单</router-link>
<br>
<router-link to="/user/setting">个人设置</router-link>
<!-- 跳转并携带query参数,to的字符串写法 -->
<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>
$route.query.id
$route.query.title
{
path:'/demo',
component:Demo,
children:[
{
path:'test',
component:Test,
children:[
{
name:'hello' //给路由命名
path:'welcome',
component:Hello,
}
]
}
]
}
跳转
跳转
跳转
{
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
作用:让路由组件更方便的收到参数
{
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
}
}
}
- 消息编号:{{id}}
- 消息标题:{{title}}
实现路由跳转,让路由跳转更加灵活//$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() //可前进也可后退
重定向:跳转到当前路由时,若此路由被重定向,则跳转到重定向指定的路由
redirect{name:‘路由name’}
别名:别
名是 **路径 ,**通过别名也可代替path中的路径
单个别名:alias: ‘/a’
多个别名:alias: [‘/a’ ,‘/b’,‘/c’]
注意:原路径有params参数 别名也需要写
:::info
{
path:‘page/:id’,
name:‘MyPage’,
alias:[‘p/:id’],
}
:::
const routes = [
{
path:'/',
name:'HomeRoot',
component: Home
},
{
path:'/home',
name:'Home',
//重定向
// redirect:'/', //路径
redirect:{name:'HomeRoot'}, //名字
component: Home
},
{
path: '/about',
name: 'About',
//单个别名
// alias:'/a',
//多个别名
alias:['/a','/b','/c'],
//原路径有params参数 别名也需要写
component: About
},
{
path: '/user',
name: 'User',
component:User,
// /user/order
children: [
{
path:'page/:id',
name:'MyPage',
//原路径有params参数 别名也需要写
alias:['p/:id'],
/* redirect:to=>{
//to => $route
return {path:'article',query:{name:'zhangsan',age:to.params.id}}
},*/
//缩写 to=>({})
component:MyPage,
},
]
}
]
//全局路由守卫
//全局前置路由守卫
/*Vue2中 有三个参数 :to :即将进入的路由
from 要离开的路由,
next (放行)
Vue3中 可以有两个参数:to ,from,next(可选) ,是否放行取决于返回值,假则禁止放行,真或不写则放行*/
router.beforeEach((to,from)=>{
document.title = to.meta.title;
// return false
})
//全局后置路由守卫
router.afterEach((to,from)=>{
// console.log('afterEach',to,from)
if(to.meta.title){
document.title = to.meta.title //修改网页的title
}else{
document.title = 'vue_test'
}
})
{
path:'setting', //此处一定不要写:/setting
name:'MySetting',
beforeEnter(to,from){
console.log('beforeEnter',to,from)
if(localStorage.getItem('school') === 'rongzhi'){
return true
}else{
alert('暂无权限查看')
return false
}
},
component:MySetting,
},
进入守卫:通过路由规则,进入该组件时被调用
:::info
beforeRouteEnter (to, from) {
},
:::
离开守卫:通过路由规则,离开该组件时被调用
:::info
beforeRouteLeave (to, from) {
}
:::
Vue3中:
<router-view v-slot="{Component}">
<transition>
<keep-alive>
<component :is="Component"/>
keep-alive>
transition>
router-view>
Vue2中:
<keep-alive include="News">
<router-view>router-view>
keep-alive>
activated
路由组件被激活时触发。deactivated
路由组件失活时触发。 在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
多个组件需要共享数据时
export default createStore({
state: {
num:0,
dnum:0,
},
getters: {
},
mutations: {
mutAdd(state){
state.dnum ++
},
mutSub(state){
state.dnum --
},
//接收一个参数,参数可以使任意类型
mutAdd2(state,count){
state.dnum +=count
},
mutSub2(state,count){
state.dnum -=count
},
//接收多个参数
//将多个参数存在一个对象中
mutAdd3(state,payload){
state.dnum +=payload.count+payload.num
},
mutSub3(state,payload){
state.dnum -=payload.count+payload.num
},
//对象写法接收
mutSub4(state,p){
state.dnum -=p.payload.count+p.payload.num
},
},
actions: {
},
modules: {
}
})
备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit
src/store/index.js
//引入Vuex
import { createStore } from 'vuex'
//暴露
export default createStore({
//准备state对象——保存具体的数据
state: {
num:0,
},
//VueX中的计算属性
getters: {
},
//准备mutations对象——修改state中的数据
mutations: {
},
//准备actions对象——响应组件中用户的动作
actions: {
},
//模块化
modules: {
}
})
import store from './store'
createApp(App).use(store).use(router).mount('#app')
mutations中的方法只能接受两个参数
第一个参数:当前 state
第二个参数:接收到的数据
可以接收任何类型的数据,如果要传递多个数据,则需要将数据放到一个对象中进行传递
组件读取mutations中方法的方式:this.$store.commit(‘方法名’, 参数)
mutations: {
mutAdd(state){
state.dnum ++
},
mutSub(state){
state.dnum --
},
//接收一个参数,参数可以使任意类型
mutAdd2(state,count){
state.dnum +=count
},
mutSub2(state,count){
state.dnum -=count
},
//接收多个参数
//将多个参数存在一个对象中
mutAdd3(state,payload){
state.dnum +=payload.count+payload.num
},
mutSub3(state,payload){
state.dnum -=payload.count+payload.num
},
//对象写法接收
mutSub4(state,p){
state.dnum -=p.payload.count+p.payload.num
},
},
调用mutations中的方法
subMut() {
//调用Vuex中mutation中的方法
//this.$store.commit.('方法名')
this.$store.commit('mutSub')
},
subTwo() {
let count = 2
this.$store.commit('mutSub2', count)
},
addThree() {
/*let count = 2
let num = 1*/
let payload = {
count: 2,
num: 1
}
//commit只有两个参数,如果想传多个参数则需要放到一个对象里
this.$store.commit('mutAdd3', payload)
},
subThree() {
let payload={
count:2,
num:1
}
// this.$store.commit('mutSub3',payload)
// 对象写法
this.$store.commit({
type: 'mutSub4', //方法名
/*payload: {
count: 2,
num: 1
}*/
payload
})
}
vxNum(state) {
return state.num * state.num
},
booksPrice(state) {
let priceSum;
priceSum = state.books.reduce((s, n) => {
return s + n.price
}, 0)
return priceSum
},
booksGet(state) {
return state.books.filter(book=>{
return book.price >30
})
},
booksGet1(state,getters) {
//参入以回调函数参数形式传入
return function (price) {
return state.books.filter(book=>{
return book.price > price
})
}
/*return state.books.filter(book=>{
return book.price >30
})*/
},
//组件中
<h2>getter中的计算属性</h2>
<h3>{{$store.getters.vxNum}}</h3>
<h1>全部图书的总价</h1>
<h2>{{$store.getters.booksPrice}}</h2>
<h1>价格大于30的数的图书</h1>
<h2>{{$store.getters.booksGet}}</h2>
<h1>价格大于30的数的图书总价</h1>
<h2>{{$store.getters.booksPrice1}}</h2>
<h1>参数传递:价格大于20的数的图书</h1>
<h2>{{$store.getters.booksGet1(20)}}</h2>
:::info
参数:第一个参数 context 代表上下文
相当于组件中的 this. s t o r e 第二个参数和 m u t a t i o n s 中方法的第二个参数一样 , 负责接收数据 : : : 组件中获取 a c t i o n s 中方法的方式: ∗ ∗ t h i s . store 第二个参数和mutations中方法的第二个参数一样,负责接收数据 ::: 组件中获取actions中方法的方式:**this. store第二个参数和mutations中方法的第二个参数一样,负责接收数据:::组件中获取actions中方法的方式:∗∗this.store.dispatch(‘方法名’,参数)**
demo(context){
setTimeout(()=>{
// context.state.num = 99;
context.commit('mutAdd')
},3000)
},
context中的方法: 可以使用解构赋值选择调用
1.commit
2.dispatch
3.getters
4.state
5.rootGetters 获取根中的getters
6.rootState 获取根中的state
fun2({state,commit,getters},payload){
// const {state,commit} = context
setTimeout(()=>{
state.num=99+payload.num1
commit('cnum')
},100)
}
注意:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写****commit
modules: {
//拆分成多个模块
//普通形式
user:{
state:{
},
getters:{},
mutations:{},
actions:{}
},
//声明调用分开
article:article,
//简写
cart,
goods,
}
const article = {
//在模块中state状态需要放在函数里面返回 类似 data(){return{}}
state:()=>({
name:'lmonkey',
slogen:'abc'
}),
getters:{
fullname(state){
return state.name+state.slogen
},
fullname2(state,getters){
//本模块中的getters
return getters.fullname+"222222"
},
fullname3(state,getters,rootState){
//rootState 根
//调用根中的state
return getters.fullname2+rootState.books[0].name
}
},
mutations:{
setname(state,payload){
state.name = payload.name
}
},
actions:{
demosome(context,payload){
/* context中的方法: 可以使用解构赋值选择调用
1.commit
2.dispatch
3.getters
4.state
5.rootGetters 获取根中的getters
6.rootState 获取根中的state
*/
// console.log(context)
setTimeout(()=>{
context.commit('setname',payload)
},2000)
}
}
}
const cart = {
state:{
},
getters:{},
mutations:{},
actions:{}
}
const goods = {
state:{
},
getters:{},
mutations:{},
actions:{}
}
如果在模块中想要获取根中的数据
在getters中,可以直接使用第三个参数rootState,获取根中的状态
在actions中,可以使用context中的rootState或rootGetters
https://vue3js.cn/vue-composition-api/