概念:Vue是一个用于构建用户界面的渐进式框架
Vue的两种使用方式:
穿件Vue实例,初始化渲染的核心步骤:
开发版本
/ 生产版本代码演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--
创建Vue实例,初始化渲染
1. 准备容器(Vue所管理的范围)
2. 引包(开发版本包 / 生产版本包) 官网
3. 创建实例
4. 添加配置项 => 完成渲染
-->
<div id="app">
<!-- 这里将来会编写一些用于渲染的代码逻辑 -->
{{msg}}
</div>
<!--引入的是开发版本包(包含完整的注释和警告)-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
// 一但引入了Vue.js核心包,在全局环境,就有了Vue构造函数
const app = new Vue({
// 通过el配置选择器,指定Vue管理的是哪个盒子
el: '#app',
// 通过data提供数据
data:{
msg: '小吴在敲Bug'
}
})
</script>
</body>
</html>
插值表达式是一种Vue的模版语法
代码演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--
插值表达式:Vue的一种模板语法
作用:利用 表达式进行插值渲染
语法:{{表达式}}
-->
<div id="app">
<p>{{msg}}</p>
<p>{{msg.toUpperCase()}}</p>
<p>{{msg + '你好'}}</p>
<p>{{age>18? '成年':'未成年'}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data:{
msg: '小吴在敲Bug',
age: 21
}
})
</script>
</body>
</html>
我们已经掌握了寄出的模版渲染,其实除了基本的模版渲染,Vue背后还做了大量工作。
比如:数据的响应式处理 —— 数据变化,视图自动更新
聚焦于数据——>数据驱动视图
使用Vue开发,关注 业务的核心逻辑
,根据业务 修改数据即可
代码演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<p>{{msg}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data:{
// 响应式
msg: '小吴在敲Bug'
}
})
// 1. 访问数据 实例.属性名
// 2. 修改数据 实例.属性名=新值
</script>
</body>
</html>
Vue会根据不同的指令,针对不同标签实现不同的功能
指令:带有 v-前缀
的特殊 标签属性
v-html指令:
作用:向指定节点中渲染包含html结构的内容。
与插值语法的区别:
v-html会替换掉节点中所有的内容,{{xx}}则不会。
v-html可以识别html结构。
严重注意:v-html有安全性问题!!!!
在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
代码演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div v-html="msg"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data:{
msg:`
<a href="www.4399.com">
4399小游戏
</a>
`
}
})
</script>
</body>
</html>
v-show
切换display:none
控制显示隐藏v-if
条件渲染
)条件判断
,是否创建或移除元素节点代码演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<div >
<p v-if="gender===1">性别:♂ 男</p>
<p v-else>性别:♀ 女</p>
<hr>
<p v-if="score==='A'">成绩评定A:奖励电脑一台</p>
<p v-else-if="score==='B'">成绩评定B:奖励周末郊游</p>
<p v-else-if="score==='C'">成绩评定C:奖励零食礼包</p>
<p v-else>成绩评定D:惩罚一周不能玩手机</p>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
gender: 1,
score: 'B'
}
})
</script>
</body>
</html>
v-on调用传参
代码演示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="count--">-</button>
<span>{{count}}</span>
<button v-on:click="count++">+</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data:{
count: 0
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<button @click="fn()">切换显示隐藏</button>
<h1 v-show="isShow">小吴在敲Bug</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isShow:true
},
methods:{
fn(){
this.isShow=!this.isShow
}
}
})
</script>
</body>
</html>
代码演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<img v-bind:src="imgUrl" v-bind:title="msg" alt="">
<img :src="imgUrl" :title="msg" alt="">
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
msg:'波仔喝奶茶',
imgUrl:'./imgs/10-02.png'
}
})
</script>
</body>
</html>
v-bind对于样式控制的增强
为了方便开发者进行样式控制,Vue扩展了v-bind的语法,可以针对class类名和style行内样式进行控制。
语法 :class="对象/数组"
对象 ——> 键就是类名,值是布尔值。如果值为true,有这个类,否则没有这个类
<div class="box" :class="{类名1:布尔值,类名2:布尔值}"></div>
数组 ——> 数组中所有的类,都会添加到盒子上,本质就是一个class列表
<div class="box" :class="[类名1,类名2,类名3]"></div>
v-for = “(item,index) in 数组”
代码演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<h3>小黑水果店</h3>
<ul>
<li v-for="(item, index) in list">
{{ item }} - {{ index }}
</li>
</ul>
<ul>
<li v-for="item in list">
{{ item }}
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
list: ['西瓜', '苹果', '鸭梨', '榴莲']
}
})
</script>
</body>
</html>
v-for中的key
代码演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<!--
v-model 可以让数据和视图,形成双向数据绑定
(1) 数据变化,视图自动更新
(2) 视图变化,数据自动更新
可以快速[获取]或[设置]表单元素的内容
-->
账户:<input type="text" v-model="username"> <br><br>
密码:<input type="password" v-model="password"> <br><br>
<button @click="login">登录</button>
<button @click="reset">重置</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: '',
password: ''
},
methods: {
login () {
console.log(this.username, this.password)
},
reset () {
this.username = ''
this.password = ''
}
}
})
</script>
</body>
</html>
通过“.
”指明一些指令后缀
,不同后缀
封装了不同的处理操作(简化代码)
概念:基于现有的数据
,计算出来的新属性
。依赖
的数据变化,自动
重新计算
语法:
computed配置项
中,一个计算属性对应一个函数计算属性名
} }computed: {
计算属性名() {
基于现有的数据,编写求值逻辑
return 结果
}
}
computed计算属性 VS methods方法
computed
配置中this.计算属性
| { { 计算属性
} }结果缓存
,再次使用直接读取缓存,依赖项变化了,会 自动
重新计算,并 再次缓存
methods
配置项中this.方法名()
| @事件名=“方法名
”计算属性完整写法
计算属性默认的简写,只能读取访问, 不能"修改"
如果要 修改
,需要写计算属性的 完整写法
computed: {
计算属性名: {
get(){
一段逻辑代码
return 结果
},
set(修改的值){
一段逻辑代码
}
}
}
作用:监视数据变化,执行一些业务逻辑或异步操作
data:{
words: '苹果'
},
watch: {
// 该方法会在数据变化时,触发执行
words —— 数据属性名(newValue,oldValue){
一些业务逻辑 或 异步操作
},
'对象.属性名'(newValue,oldValue){
一些业务逻辑 或 异步操作
}
}
watch: {
数据属性名:{ //数据属性是对象
deep: true, //深度监视,对对象里的所有子属性进行监视
immediate: true // 立刻执行,打开页面就马上执行一次
handler(newValue,oldValue){
一些业务逻辑 或 异步操作
}
}
Vue生命周期:一个Vue实例从创建
到销毁
的整个过程
生命周期四个阶段:
Vue生命周期过程中,会自动运行一些函数
,被称为生命周期钩子
,让开发者可以在特定阶段
运行自己的代码
// 1.创建阶段(准备数据)
beforeCreate(){
console.log("beforeCreate 响应式数据准备好之前")
},
created(){
console.log("create 响应式数据准备好之后")
},
// 2.挂载阶段(渲染模板)
beforeMount(){
console.log("beforeMount 模板渲染之前")
},
mounted(){
console.log("mounted 模板渲染之后")
},
// 3.更新阶段
beforeUpdate(){
console.log("beforeUpdate 数据修改了,视图还没更新")
},
updated(){
console.log("updated 数据修改了,视图已经更新" )
},
// 4.卸载阶段
beforeDestroy(){
console.log("beforeDestroy")
},
destroyed(){
console.log("destroyed")
}
开发Vue的两种方式:
基本介绍:
好处:
使用步骤:
npm i @vue/cli -g
vue --version
vue create 项目名称 (项目名不能用中文)
npm run serve (找package.json)
一个个组件
,每个组件有着自己独立的 结构
、样式
、行为
根组件: 整个应用 最上层
的组件,包裹了所有普通小组件
- template
结构
- style
样式(可以支持less,需要安装less和less-loader)
- script
行为
组件注册的两种方式
只能在注册的组件内使用
main.js
中进行全局注册使用: 当成html标签使用 <组件名>组件名>
注意: 组件命名规范 —— 大驼峰命名法
默认情况: 写在组件中的样式会 全局生效
,因此很容易造成多个组件之间的样式冲突问题
全局样式: 默认组件中的样式会作用到全局
局部样式: 可以给组件加上 scoped
属性, 可以让样式只作用于当前组件
<style scoped>
</style>
组件通信,就是指 组件与组件
之间的数据传递
独立
的,无法直接访问其他组件的数据组件关系分类:
prop定义:组件上
注册的一些 自定义属性
prop作用:向子组件传递数据
特点:
任意数量
的prop任意类型
的propprops校验
作用: 为组件的prop指定 验证要求
,不符合要求,控制台就会有 错误提示
语法:
类型校验
props:{
校验的属性名:类型 // 类型有 Number String Boolean Array Object Function
}
非空校验
默认值
自定义校验
props:{
校验的属性名:{
type: 类型, // 类型有 Number String Boolean Array
required: true, // 是否必填
default: 默认值, // 默认值
validator (value) { // 形参可以接受到传过来的值
// 自定义校验逻辑
return 是否通过校验 // true 通过校验 false 不通过校验
}
}
}
事件总线
创建一个都能访问到的事件总线(空Vue实例)
import Vue from 'vue'
const Bus = new Vue()
export default Bus
A 组件(接收方),监听 Bus 实例
的事件
created(){
Bus.$on('sendMsg',(msg) =>{
this.msg = msg
})
}
B组件(发送方),触发 Bus 实例
的事件
Bus.$emit('sendMsg','这是一个消息')
provide & inject
provide & inject作用:跨层级
共享数据
父组件provide提供数据
export default {
provide() {
return {
// 普通类型【非响应式】
color: this.color,
// 复杂类型【响应式】
userInfo: this.userInfo
}
}
}
子/孙组件inject取值使用
export default {
inject: ['color','userInfo']
created(){
console.log(this.color,this.userInfo)
}
}
props
传递过来的,v-model 拆解
绑定数据v-model简化代码
父组件v-model 简化代码
,实现子组件与父组件数据 双向绑定
value
接收,事件触发 input
v-model
给组件直接绑定数据作用:可以实现子组件
与父组件数据
的双向绑定
特点:prop属性名,可以自定义
,非固定为value
本质:就是:属性名
和@update:属性名
和写
<BaseDialog :visble.sync="isShow" />
作用:利用ref和$refs可以用于获取dom元素
,或组件实例
特点
:查找范围 —— 当前组件内(更精确稳定)
获取dom:
<div ref="chartRef">我是渲染图表的容器</div>
mounte(){
console.log(this.$refs.chartRef)
}
获取组件:
<BaseForm ref="baseForm"></BaseForm>
调用组件对象里面的方法
this.$refs.baseForm.组件方法()
$nextTick:等DOM更新后
,才会触发执行此方法的函数体
语法: this.$nextTick(函数体)
this.$nextTick(() => {
// 业务逻辑
})
自定义指令:自己定义的指令,可以封装一些DOM操作
,扩展额外功能
全局注册 —— 语法(main.js中编写语句)
Vue.directive('指令名',{
// inserted 会在指令所在的元素,被插入到页面中时触发
inserted (el){
// 可以对 el 标签,扩展额外功能
el.focus()
}
})
局部注册 —— 语法
directives:{
指令名:{
inserted(el){
// 可以对 el 标签,扩展额外功能
el.focus()
}
}
}
使用
<input v-指令名 type="text">
作用:让组件内部的一些
结构
支持自定义
插槽基本语法:
插槽后备内容:封装组件时,可以为预留的
插槽提供后备内容
(默认值)
具名插槽语法
基本使用步骤:
给slot标签,以添加属性的方式传值
<slot :id="item.id" msg="测试文本"></slot>
所有添加的属性,都会被收集到一个对象中
{id: 3, msg: '测试文本'}
咋提template中,通过#插槽名="obj"
接收,默认插槽名为default
<MyTable :list="list">
<template #default="obj">
<button @click="del(obj.id)">删除</button>
</template>
</MyTable>
作用:修改
地址栏路径时,切换显示
匹配的组件
说明:Vue官方的一个路由插件,是一个第三方包
官网
五个基本步骤(main.js
)
下载:下载VueRouter模板到当前工程
npm install vue-router@3.6.5
引入
import VueRouter from 'vue-router'
安装注册
Vue.use(VueRouter)
创建路由对象
const router = new VueRouter()
注入,将路由对象注入到new Vue实例中,建立关联
new Vue({
render: h => h(App),
router
}).$mount('#app')
2个核心步骤
创建需要的组件(views目录),配置路由规则
const router = new VueRouter({
// routers 路由规则们
// router 一条路由规则{path: 路径, component: 组件}
routes: [
{path: '/find', component: Find
children:[{ //子路由
path: '路由路径',
component: 组件名
}]
},
{path: '/my',component: My},
{path: '/friend',component: Friend}
]
})
配置导航:配置路由出口(路径匹配的组件显示的位置)
<template>
<div>
<div class="footer_wrap">
<a href="#/find">发现音乐</a>
<a href="#/my">我的音乐</a>
<a href="#/friend">朋友</a>
</div>
<div class="top">
<!-- 路由出口 → 匹配的组件所展示的位置 -->
<router-view></router-view>
</div>
</div>
</template>
问题:所有的路由配置都堆在main.js中不合适
目标:将路由模块抽离出来
好处:拆分模块
,利于维护
在index.js文件中编写路由规则
import Find from "@/views/Find";
import My from "@/views/My";
import Friend from "@/views/Friend";
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter) //VueRouter插件初始化
const router = new VueRouter({
// routers 路由规则们
// router 一条路由规则{path: 路径, component: 组件}
routes: [
{path: '/find', component: Find},
{path: '/my',component: My},
{path: '/friend',component: Friend}
]
})
// 导出router
export default router
vue-router提供了一个全局组件router-link(取代了a标签)
能跳转
,配置to属性指定路径(必须
),本质还是a标签,to无需#
能高亮
,默认就会提供高亮类名
,可以直接设置高亮样式router-link —— 两个类名
模糊匹配(常用)
精确匹配
自定义匹配类名
说明:router-link的两个类名太长了
,我们可以自定义匹配类名
const router = new VueRouter({
// routers 路由规则们
// router 一条路由规则{path: 路径, component: 组件}
routes: [ …… ],
林肯ActiveClass: '精确匹配的类名',
linkExactActiveClass: '模糊匹配的类名'
})
目标:在跳转路由时,进行传值
to="/path?参数名=值(&参数名n=值n)
$router.query.参数名
path:"/path/:参数名
?
(/path/:参数名?)const router = new VueRouter({
routes: [
{ path: '/search/:words', component: Search }
]
})
to="/path/参数值
$route.params.参数名
问题:网页打开,url默认是/路径,未匹配到组件时,会出现空白
重定向:匹配到path后,强制跳转path路径
语法
: {path: 匹配路径,redirect: 重定向到的路径}
const router = new VueRouter({
routes: [
{path: '/',redirect: '/home'},
{path: '/home', component: Home},
{path: '/search', component: Search}
]
})
404页面设置
作用: 当路径找不到匹配时,给个提示页面
位置: 配在路由最后
语法:path:“*”(任意路径)
—— 前面的路由不匹配就匹配最后一个
const router = new VueRouter({
routes: [
{path: '/',redirect: '/home'},
{path: '/home', component: Home},
{path: '/search', component: Search},
{path: "*",component: NotFind}
]
})
路由模式
问题:路由的路径看起来不自然,有#,能否切换成真正的路径形式?
const router = new VueRouter({
routes: [ …… ],
mode: "history"
})
问题:点击按钮跳转如何实现?
编程式导航:用JS代码来进行跳转
基本跳转
path路径跳转(简易方便)
this.$router.push('路由路径')
this.$router.push({
path: '路由路径'
})
name命名路由跳转(适合path路径长的场景)
this.$router.push({
name: '路由名'
})
{name: '路由名',path: '/path',component: 组件名}
路由传参
两种传参方式:查询参数+动态路由传参
两种跳转方式,对于两种传参方式都支持
path路径跳转传参(query传参)
this.$router.push('路由路径?参数名1=参数值1&参数名2=参数值2')
this.$router.push({
path: '路由路径',
query:{
参数名1: '参数值1',
参数名2: '参数值2'
}
})
path路径跳转传参(动态路由传参)
this.$router.push('路由路径/参数值')
this.$router.push({
path: '路由路径/参数值'
})
name命名路由跳转传参(query传参)
this.$router.push({
path: '路由名',
query:{
参数名1: '参数值1',
参数名2: '参数值2'
}
})
name命令路由跳转传参(动态路由传参)
this.$router.push({
path: '路由名',
params:{
参数名: '参数值'
}
})
使用keep-alive
包裹路由出口,可以使得切换组件时上一个组件不会被销毁
<keep-alive>
<router-view></router-view>
</keep-alive>
keep-alive的三个属性
<keep-alive :include="['组件名1','组件名2']">
<router-view></router-view>
</keep-alive>
两个钩子
代码规范:一套写代码的约定规则
老话说:“没有规矩不成方圆
” —— 正规的团队需要统一
的编码风格
如果你的代码不符合standard的要求,ESlint会跳出来刀子嘴,豆腐心提示你
JavaScript Standard Style 规范说明
代码规范错误解决方案
vuex是一个vue的状态管理工具(状态就是数据)
大白话:vuex是一个插件,可以帮我们管理vue通用的数据(多组件共享的数据)
场景:
优势:
多组件共享的数据环境
Vue.use(Vuex)
创建创库 new Vuex.Store()
// 这里存放的就是 vuex的相关核心代码
import Vue from 'vue'
import Vuex from 'vuex'
// 插件安装
Vue.use(Vuex)
// 创建仓库(空仓库)
const store = new Vuex.Store()
// 导出给main.js使用
export default store
目标:明确如何给仓库提供数据,如何使用仓库数据
提供数据: State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储。在State对象中可以添加我们要共享的数据
// 创建仓库
const store = new Vuex.Store({
// state状态:即数据,类似于Vue组件中的data
/*
区别:
1.data是自己的数据
2.State是所有组件共享的数据
*/
state: {
count: 100
}
})
使用数据:
获取 store:
(1)this.$store
(2)import 导入 store
模板中:{{$store.state.xxx}}
组件逻辑中:this.$store.state.xxx
JS模块中:store.state.xxx
import { mapState } from 'vuex'
mapState(['count'])
computed: { ...mapState(['count']) }
目标:明确vuex同样是遵循单向数据流,组件中不能直接修改仓库的数据
通过strict: true
可以开启严格模式(项目上线移除掉,会吃性能)
// 创建仓库(空仓库)
const store = new Vuex.Store({
// 开启严格模式
strict: true,
// state状态:即数据,类似于Vue组件中的data
/*
区别:
1.data是自己的数据
2.State是所有组件共享的数据
*/
state: {
title: '大标题',
count: 100
}
})
mutations
目标掌握mutations的操作流程,来修改state数据(state数据的修改只能通过mutations)
定义mutations对象,对象中存放修改state的方法
const store = new Vuex.Store({
state: {
title: '大标题',
count: 100
},
// 定义mutations
mutations: {
// 第一个参数是当前store的state属性
addCount (state){
state.count += 1
}
}
})
组件中提交调用mutations
this.$store.commit('addCount')
mutations传参语法
提供 mutation 函数(带参数 —— 提交载荷 payload)
mutations: {
...
addCount (state, n) {
state.count += n
}
}
页面中调用 mutation
this.$store.commit('addCount', 10)
辅助函数(mapMutations):mapMutations 和 mapState 很像,它是把位于mutations中的方法提取出来,映射到组件methods中
mutations: {
subCount (state, n) {
state.count -= n
}
}
import { mapMutations } from 'vuex'
methods: {
...mapMutations(['subCount'])
}
this.subCount(10) //JS中调用
目标:明确 actions 的基本语法,处理异步操作
说明:mutations 必须是同步的(便于检测数据变化,记录调试)
提供actions方法
actions: {
setAsyncCount (context, num) {
// 一秒钟后,给一个数,去修改 num
setTimeout(() => {
context.commit('changeCount', num)
}, 1000)
}
}
页面中 dispatch 调用
this.$store.dispatch('setAsyncCount', 200)
辅助函数mapActions
目标:掌握辅助函数 mapActions,映射方法
mapAction 是把位于actions中的方法提取出来,映射到组件methods中
actions: {
setAsyncCount (context, num) {
// 一秒钟后,给一个数,去修改 num
setTimeout(() => {
context.commit('changeCount', num)
}, 1000)
}
}
import { mapActions } from 'vuex'
methods: {
...mapActions(['setAsyncCoun'])
}
this.setAsyncCoun(666) //调用
目标:掌握核心概念 getters 的基本语法(类似于计算属性)
说明:除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到getters
例如:state 中定义了list,为1-10的数组,组件中,需要显示所有大于5的数据
state: {
list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
定义 getters
getters: {
/*
注意:
(1) getters函数的第一个参数是 state
(2)getters函数必须要有返回值
*/
filterList (state) {
return state.list.filter(item => item > 5)
}
}
访问getters
通过store访问getters
{{ $store.getters.filterList }}
通过辅助函数 mapGetterrs映射
import { mapGetters } from 'vuex'
computed: {
...mapGetters(['filterList'])
}
{{ filterList }} //使用
由于vuex使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿(当项目变得越来越大的时候,vuex会变得越来越难以维护)
编写模块
// user模块
const state = {
userInfo: {
name: 'zhangsan',
age: 18
},
score: 80
}
const mutations = {}
const actions = {}
const getters = {}
// 导出模块
export default {
state,
mutations,
actions,
getters
}
导入和挂载
import user from '@/store/modules/user'
const store = new Vuex.Store({
modules: {
user
}
})
访问模块中的state
尽管已经分模块了,但其实子模块的状态,还是会挂到根级别的state中,属性名就是模块名
使用模块中的数据:
$store.state.模块名.xxx
mapState(['xxx'])
mapState('模块名',['xxx'])
需要开启命名空间export default {
namespaced: true, // 开启命名空间
state,
mutations,
actions,
getters
}
使用模块中getters中的数据
$store.getters['模块名/xxx']
**mapGetters(['xxx'])
mapGetters('模块名',['xxx']
需要开启命名空间export default {
namespaced: true, // 开启命名空间
state,
mutations,
actions,
getters
}
调用子模块中mutation
注意:默认模块中的 mutation 和 actions 会被挂载到全局,需要开启命名空间,才会挂载到子模块
$store.commit('模块名/xxx',额外参数)
mapMutations(['xxx'])
mapMutations('模块名',['xxx'])
需要开启命名空间export default {
namespaced: true, // 开启命名空间
state,
mutations,
actions,
getters
}
调用子模块中action
注意:默认模块中的 mutation 和 actions 会被挂载到全局,需要开启命名空间,才会挂载到子模块
$store.dispatch('模块名/xxx',额外参数)
mapActions(['xxx'])
mapActions('模块名',['xxx'])
需要开启命名空间export default {
namespaced: true, // 开启命名空间
state,
mutations,
actions,
getters
}
Vue3 组合式API vs Vue2 选项式 API
代码量变少了
选项式API
<script>
export default {
data () {
return {
count: 0
}
},
methods: {
addCount () {
this.count++
}
}
}
</script>
组合式API
<script setup>
import [ ref } from 'vue'
const count = ref(0)
const addCount = () => count.value++
</script>
create-vue是Vue官方新的脚手架工具,底层切换到了 vite(下一代构建工具),为了开发提供极速响应
前提环境条件:已安装 16.0 或更高版本的 Node.js
创建一个Vue应用:npm init vue@latest(这一指令将会安装并执行create-vue)
关键文件: