Vue基础
1. Vue和脚手架的介绍
1.1Vue概念
- Vue是一个渐进式的的JavaScript 的开发框架,是一套拥有自己规则的语法。
1.2 脚手架
1.2.1使用步骤:
- @vue/cli 安装到全局
yarn global add @vue/cli
# OR
npm install -g @vue/cli
- 查看安装的版本 有版本号则安装成功,否则安装失败
vue -V
- 创建项目 vuecli-demo为自定义的项目名,不能有大小字母及中文及特殊符号
vue create vuecli-demo
-
选择模板 上下箭头选择
1,选择Vue的版本
2,选择 包管理工具 NPM / Yarn
3,回车等待生成项目文件夹+文件+下载必须的第三方包们
4,进入脚手架项目下, 启动内置的热更新本地服务器
5,看到绿色的DONE即表示创建成功
1.2.2脚手架项目结构
- node_modules -> 第三方依赖包
- public/index.html -> 浏览器运行的网页
- src/ App.vue -> 页面根组件
- src/ main.js -> 项目入口 /打包的入口
- package.json -> 记录项目的依赖包
- vue.config.js -> 脚手架项目的配置文件
- 脚手架项目运行流程 -> src/main.js -> src/App.vue -> public/index.html
1.2.3 Vue单文件
- js作用域独立
- style配合scoped属性作用域独立 ,否则为全局样式
- template下面只能有一个根标签
2. Vue的指令
2.1 插值表达式
- 语法 : {{ 表达式 }}
- 作用:把表达式内容插入到插值所在的位置
- 变量要声明在data方法的返回对象里
- 表达式举例:变量 / 属性 / 三元运算符 / 方法调用 / 数字 / 字符串等
- 举例:
<template>
<div>
<h1>{{name}}</h1>
<h2>{{obj.age}}</h2>
<h3>{{obj.gender}}</h3>
<h4>{{sayHi()}}</h4>
<h4>{{obj.sayfn()}}</h4>
<h5>{{obj.age>18? '成年':'未成年'}}</h5>
</div>
</template>
<script>
export default {
data() {
return {
name:'小青',
obj:{
age:18,
gender:'男',
sayfn(){
return this.age
}
},
sayHi(){
return '成年与否'
}
}
}
}
</script>
2.2 v-bind 为标签绑定属性
- 语法:v-bind:属性名="Vue变量" 或简写: :属性名="Vue变量"
- 作用:给标签绑定属性,使属性值能够使用 Vue变量。
- Vue变量声明在data方法的返回对象里
- 举例:
<template>
<div>
<a v-bind:href="baiduUrl">百度</a>
<img :src="imgUrl" alt="">
</div>
</template>
<script>
export default {
data() {
return {
baiduUrl:'https://www.baidu.com/',
imgUrl:'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png'
}
}
}
</script>
2.3 v-on 标签绑定事件
2.3.1 v-on 事件绑定
- 语法
- v-on:事件名=“要执行的少量代码" 简写 @事件名=“要执行的少量代码"
- v-on:事件名=“methods中的函数名" 简写 @事件名=“methods中的函数名"
- v-on:事件名=“methods中的函数名(实参)" 简写 @事件名=“要methods中的函数名(实参)"
- 作用:给标签绑定事件
- 举例:
<template>
<div>
<h2>计数{{ count }}</h2>
<button v-on:click="count++">加一</button>
<button v-on:click="addFive()">加五</button>
<button v-on:click="addfn(50)">加五十</button>
<button @click="addfn(100)">加100</button>
<a href="https://www.baidu.com/" @click.prevent="fn"></a>
</div>
</template>
<script>
export default {
data() {
return {
count: 0,
};
},
methods: {
addFive() {
this.count += 5;
},
addfn(num) {
this.count += num;
},
fn(e){
// e.preventDefault()
console.log(e);
}
},
};
</script>
2.3.2 v-on修饰符
- 语法:@事件名.修饰符="方法"
- 分类:
- .stop 阻止事件冒泡
- .prevent 阻止默认行为
- .once 程序运行期间,事件只触发一次
- 按键修饰符(针对 keydown / keyup 事件等)
- .enter 回车键触发
- .esc 按ESC触发
- 举例:按键修饰符
<template>
<div>
<p>
用户名
<input type="text" @keyup.enter="keyEvent" @keyup.esc="say" @keyup.d="sayd">
</p>
</div>
</template>
<script>
export default {
data() {
return {
};
},
methods: {
keyEvent(){
console.log('登录');
},
say(){
console.log('esc');
},
sayd(){
console.log('d');
}
},
};
</script>
2.3.3 Vue语法中获取事件对象
- 事件函数的第一个形参 参数名可自定义,如 e / event
- 如果第一个参数已有实参,则传入一个形参 $event ,只此一种写法
2.3.4 案例:点击翻转字符串
- 需求:点击按钮,文本的每个字符翻转排列
<template>
<div>
<p>{{ message }}</p>
<button @click="reverseworld">点击翻转</button>
</div>
</template>
<script>
export default {
data() {
return {
message: "hello,world",
};
},
methods: {
reverseworld() {
// 先用 .split('')方法将字符串转成数组
const arr = this.message.split("");
// 数组的翻转方法 会改变原有数组 .reverse()
arr.reverse();
// 将新数组重新赋值给 Vue变量
this.message = arr.join("");
},
},
};
</script>
<style>
</style>
2.4 v-model 双向绑定
2.4.1 v-model基本介绍
- 语法: v-model="变量"
- 作用: value和vue变量双向绑定 ,实现同步改变
- 变量记得声明在data方法的返回对象里
2.4.2 v-model的修饰符
- 语法: v-model.修饰符="变量"
- 分类;
- .number 转换为数字赋值给变量
- .trim 去掉字符串首尾的空白符
- .lazy input失去焦点才更新变量
2.4.3 v-model在表单中的使用
- 下拉选择框: v-model写在select上面 , 绑定的选中的option的value
- checkbox 多选框
- v-model变量为非数组 :绑定的是布尔值,checked属性
- v-model变量为数组 : 绑定的是选中项的value
- radio单选框: v-model绑定的是选中的value
- textarea 文本域: 绑定用户输入的value
2.4.4综合举例
<template>
<div>
<p>用户名:<input type="text" v-model="userName" /></p>
<p>密码:<input type="text" v-model="password" /></p>
<p>
<!-- 多选 :变量声明为数组获取的是选中项的value,否则是布尔类型-->
爱好:
<input type="checkbox" v-model="hobby" value="音乐" />音乐
<input type="checkbox" v-model="hobby" value="嘻哈" />嘻哈
<input type="checkbox" v-model="hobby" value="打豆豆" />打豆豆
</p>
<p>
<!-- 单选: 声明为普通变量即可,v-model获取到的是value-->
<input type="radio" v-model="gender" value="男" />男
<input type="radio" v-model="gender" value="女" />女
</p>
<p>
<!-- 下拉列表:v-model 写在selected标签,获取的是选中项的value -->
<select v-model="city">
<option value="广州">广州</option>
<option value="长沙">长沙</option>
<option value="北京">北京</option>
<option value="韶关">韶关</option>
<option value="湛江">湛江</option>
</select>
</p>
<button @click="login">登录</button>
<textarea v-model.trim="txt" id="" cols="30" rows="10"></textarea>
</div>
</template>
<script>
export default {
data() {
return {
userName: "admin",
password: "",
hobby: [],
gender: "",
city: "",
txt: "",
};
},
methods: {
login() {
console.log("userName", this.userName);
console.log("password", this.password);
console.log("hobby", this.hobby);
console.log("gender", this.gender);
console.log("city", this.city);
console.log("txt", this.txt);
},
},
};
</script>
2.5 v-for 数据的遍历
2.5.1 v-for的基本用法
- 语法: v-for="变量 in 目标数据" 或 v-for="(变量, 索引) in 目标数据"
- 作用:遍历列表,(数组,对象,字符串,数字)
- 扩展:如果是数字遍历,会从数字1递增到目标数字,目标数字必须大于或等于1
- 举例
<template>
<div>
<ul> <!-- 数组 -->
<li v-for="(item,index) in arr">{{index+1}}:{{item}}</li>
</ul>
<ul> <!-- 对象 -->
<li v-for="(value,key) in obj">{{key}}:{{value}}</li>
</ul>
<ul> <!-- 字符串 -->
<li v-for="(value,index) in str">{{index+1}}:{{value}}</li>
</ul>
<ul> <!-- 数字 -->
<li v-for="(value,index) in num">{{index}}:{{value}}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
arr:['伏黑惠','旋涡玖辛奈','五条悟','夏油杰','利姆露','红丸'],
obj:{
userName:'哈利波特',
parent:'莉莉.詹姆斯',
ass:5000000,
},
str:'飞天小女警,我才不管你',
num:8
};
},
methods: {},
};
</script>
2.5.2 v-for的更新
2.5.2.1 触发更新的条件
- 对数组而言:
- 当数组方法不会修改原始数组的方法不会导致v-for更新 ,如: array.filter / array.slice
- 等当数组方法 修改原始数组的方法会导致v-for更新 ,如:array.push / array.reverse 等
- 当通过数组下标 array[index] = value 这种方式 操作数组时,不会触发更新,而是要用 **$set(数组, 索引, 值)**该方法才会触发v-for的更新
- 当数组里面的元素是一个对象时,通过 array[index].属性名=value 这种方式更新对象,也会触发v-for的更新
- 对对象而言,当对象的属性发生改变或新增了属性时就会触发更新
2.5.2.2 key对v-for更新的影响(设置 key属性)
- 设置key的方法:给v-for的标签添加 key="唯一标识"
- 设置与否的区别
- 不设置key时的更新方式:就地更新,拿到原来的列表逐一对比更新,性能消耗较大
- 设置key时的更新方式:比较后更新利用key为索引在上一次的列表寻找相同key的数据,对比后更新,性能消耗较小
- 建议:条件允许则尽量添加key属性
2.6 v-text与v-html
2.6.1 v-text
- 语法: v-text="变量"
- 作用: v-text把内容作为文本直接显示,不解析内容 , 变量声明在data方法返回对象里
2.6.2 v-html
- 语法: v-html="变量"
- v-html会解析内容中的html标签 , 变量声明在data方法返回对象里
2.6.3 代码演示
<template>
<div>
<h1 v-text="hello"></h1>
<h1 v-text="helloHTML"></h1>
<h1 v-html="helloHTML"></h1>
<h1 v-html="hello"></h1>
</div>
</template>
<script>
export default {
data() {
return {
hello: "hello world",
helloHTML: "<button>点我</button>"
}
}
}
</script>
2.7 v-show与v-if(显示与隐藏)
2.7.1 v-show
- 语法: v-show="表达式" ,表达式的布尔类型为 true 时,标签显示,反之则隐藏
- 作用: 控制标签显示和隐藏
- 原理: v-show通过控制display: none属性来控制显示隐藏
- 注意点:表达式一般声明在 data方法返回的对象里
<template>
<div>
<h1 v-show="age >= 18">成年人的快乐</h1>//会显示,
<h1 v-show="age < 18">给你一瓶营养快线</h1>//会隐藏,但是html中还是会有该标签的结构
</div>
</template>
<script>
export default {
data() {
return {
age: 27,
};
},
};
</script>
2.7.2 v-if / v-else-if /v-else
- 语法:v-if="表达式",v-else-if="表达式",v-else 这三者可搭配使用,逻辑线类似 if /else if / else条件语句
- 作用:用于控制便签的显示和隐藏,
- 原理:通过验证表达式的布尔类型决定是否将该标签插入到html结构中,true则插入,反之则不。
- 注意点: v-if,v-else-if 和 v-else必须是相邻同级节点 ,否则报错
<template>
<div>
<input type="text" v-model.number="age">
<h2 v-if="age < 18">甜甜圈</h2>
<h2 v-else-if="age < 60">快乐水</h2>
<h2 v-else-if="age < 100">脑白金</h2>
<h2 v-else>冬虫夏草</h2>
</div>
</template>
<script>
export default {
data() {
return {
age: 8,
};
},
};
</script>
2.8 条件控制样式
2.8.1 :class
- 语法: :class="{ 类名: 布尔值 }"
- 作用:用于控制类名是否添加给标签 ,true为添加,否则除去
- 注意点:可控制多个类名, :class="{ 类名: 布尔值 ,类名: 布尔值}" ,当类名有横线是,用单引号包裹类名
<template>
<div>
<button :class="{ on: isOpen, off: !isOpen }" @click="fn">{{isOpen?'我开灯了':'关灯睡觉'}}</button>
</div>
</template>
<script>
export default {
data() {
return {
isOpen:false,
};
},
methods:{
fn(){
this.isOpen=!this.isOpen
},
}
};
</script>
<style>
.on{
background-color: pink;
}
.off {
background-color: orange;
}
</style>
2.8.2 :style
- 语法::style="{ 样式属性名: 合法的样式值 }"
- 作用:动态修改样式,使样式值能使用变量
- 注意点:样式名如果带横线,改为小驼峰,也可以使用引号
<template>
<div>
<button
@click="fontColor = 'blue'"
:style="{ color: fontColor, 'font-size': '60px' }"
:class="{ 'text-center': true, textTop: true }"
>
变色
</button>
</div>
</template>
<script>
export default {
data() {
return {
fontColor: "red",
};
},
};
</script>
2.9 过滤器
- 语法: {{ 表达式 | 过滤器1 | 过滤器2(参数1) }}
- 作用:转换内容格式
- 过滤器的方法注意点:
- 记得返回数据 (return)
- 方法第一个参数:表达式内容
- 传给方法的参数从第二个开始
- 过滤器能使用在插值表达式和v-bind属性里
- 全局与单文件过滤器:
- 全局:声明在 main.js 文件,格式: Vue.filter('过滤器名', 方法)
- 单文件:声明在当下vue文件的与data方法同级的 filters属性里
- 演示:
<template>
<div>
<!-- 过滤器作用:转换数据格式 -->
商品价格:{{ price | priceFilter }}
<h2>{{ "hello" | toUpperCase }}</h2>
<!-- 过滤器能使用在插值表达式和v-bind属性里 -->
<p :title="'hello vue' | toUpperCase">hello vue</p>
</div>
</template>
<script>
export default {
data() {
return {
price: 9,
};
},
// 声明在data同级下的filters对象里
// 声明在filters内的过滤器只能在当前vue文件使用
filters: {
// 过滤器要声明为方法
// 表达式的值是过滤器的第一个参数
priceFilter(num) {
return `${num < 10 ? "0" + num : num}¥`;
},
toUpperCase(value) {
return value.toUpperCase();
},
},
};
</script>
<style>
</style>
2.10 计算属性
- 是什么: 依赖一些变量运算出来的属性
- 语法:{{ 变量 }}
- 声明的完整写法: 计算属性: { get() {}, set(value) { } }
- 声明在 data同级的computed对象内 , 计算属性方法要返回值
- 好处:缓存计算结果,只有依赖项变化才会重新运算
<template>
<div>
<!-- 计算属性,作用:根据一些数据计算出来一个属性 -->
<!-- 当计算属性依赖的数据变化的时候,计算属性会重新运算 -->
<!-- 计算属性是作为变量使用的,不要使用括号的语法 -->
<!-- 计算属性不能和data里的变量重名 -->
<h1>{{sum}} = {{a}} + {{b}}</h1>
a: <input type="text" v-model.number="a">
</div>
</template>
<script>
export default {
data() {
return {
a: 10,
b: 20,
};
},
// 计算属性声明在data同级的computed对象里
computed: {
// 计算属性声明为方法
sum() {
return this.a + this.b;
}
},
}
</script>
2.11 侦听器
-
作用:可以侦听data/computed属性值的改变,方便开发者做出应对
-
语法:写在与data方法同级的watch属性里面
-
注意点:如果需要监听复杂数据类型需加额外配置,deep: true, 深度监听,immediate: true, 页面挂载后立即执行一次
-
分类:
- 简单数据类型
- 对象/数组等
<template> <div> msg <input type="text" v-model="msg"> <br> user.name <input type="text" v-model="user.name"> user.age <input type="text" v-model="user.age"> <br> <input type="text" v-model="num1"> 总数: {{num2}} </div> </template> <script> export default { data() { return { msg: '', user: { name: 'tom', age: 13 }, num1: 2, num2: 0 } }, watch: { // 以键值对的形式指定 被监听字段: 触发后回调函数 msg(newVal, oldVal) { console.log(newVal, oldVal); }, user: { deep: true, // deep 深度监听 handler(newVal, oldVal) { console.log(newVal, oldVal); } }, num1: { immediate: true, // immediate 页面挂载后立即执行一次 handler (newVal) { this.num2 += newVal } } } } </script>
2.12 自定义vue指令
- 自定义指令是vue指令的拓展,当vue指令不能满足我们的一些需求时,就可使用自定义指令
- 自定义指令有两个钩子函数,
- inserted( el,options ),在绑定自定义指令的dom元素被插入后触发,第一个参数为被绑定的dom元素本身,options是包含自定义指令及钩子函数的复杂对象,其中 options.value 等价于 自定义指令的属性值
- update( el,options ),在绑定自定义指令的dom元素的值或模板更新时触发 ,参数含义与上述相同
<template>
<div v-boxbg="'orange'">
我的颜色是通过 v-boxbg指令设置的
</div>
</template>
<script>
export default {
directives:{
boxbg:{
inserted(el,options){
// options.value 是自定义指令调用时 等号 右边的值
el.style.backgroundColor=options.value
console.log(options);
}
}
}
}
</script>
<style>
div {
width: 300px;
height: 300px;
}
</style>
3. Vue组件
3.1 组件的基本介绍
-
概念:组件就是做单独封装的单个vue文件,用于封装可复用的代码,提升开发效率
-
组件的使用方法:封装 -> 引入 -> 注册 -> 使用标签渲染,注册后使用组件名以标签的形式使用:如:
- 全局引入注册:在main.js文件,
import Vue from 'vue' //如文件中已有实例vue,省略此步骤 import 组件对象 from '组件vue文件路径' //引入 Vue.component('组件名',组件对象) //注册- 局部引入:单个vue 文件
import 组件对象 from 'vue文件路径' export default { components:{ //注册写在components属性内 "组件名":组件对象 } } -
完整演示
<template> <div> <div class="list"> <ProdItem/> <ProdItem/> <!-- 使用组件名以标签的形式渲染 --> </div> </div> </template> <script> // 局部注册的演示 import ProdItem from '@/components/ProdItem.vue' export default { components: { "ProdItem" :ProdItem } } </script>
3.2 组件通信 父传给子
-
作用:将数据传递给子组件,
-
方法步骤:
- 第一步,将要使用的数据变量,用属性方式写在子组件的单标签上 :prod="item"
- 第二步,在子组件的文件中 export default {props:['prod']} props:['prod']属性,以数组的方式储存变量,变量名为第一步的自定义属性名
- 第三步,直接使用储存在数组中的变量
-
单向数据流:父组件传递给子组件的数据,子组件为只读状态,无法修改原数据
-
注意点: ,组件中style标签加上 scoped 属性,可使样式只作用于属于本组件的标签
-
演示:
- 父组件的代码
<template> <div> <!-- :prod="item" 以属性的方式书写在标签上 --> <testProdItem :prod="item" v-for="(item,index) in list" :key="index" /> <div class="item">我不属于组件</div> </div> </template> <script> import testProdItem from '@/components/子组件-testProdItem.vue' export default { components:{ testProdItem, }, data(){ return { list:['周黑鸭','口水鸡','螺蛳粉','牛肉丸','四川火锅',] } } } </script> <style scoped> //scoped属性 范围化样式作用域 .item { width: 200px; height: 200px; background-color: pink; color: purple; } </style>- 子组件的代码
<template> <div> <!-- 按照正常的vue指令使用 prod 即可 --> <div class="item">{{prod}}</div> </div> </template> <script> export default { props:['prod'] //在props属性中以 以数组的元素方式接收,需加引号 } </script> <style> .item { width: 100px; height: 100px; background-color: orange; } </style> -
当子组件对父组件传递的数据有具体的格式要求时,可将 props定义成对象,每一个接收的数据变量为属性名
<script> export default { // props: ['bg', 'color', 'title'] // props 的数组写法, 其实可以换成对象 // 可以设定要求的数据格式 props: { bg: String, //要求传递的数据必须为字符串 color: { type: String, default: '#fff' //设置默认值 }, title: { type: String, required: true //数据的必填校验 } } } </script>
3.3组件通信 子传父
-
作用:将子组件的数据传递给父组件
-
方法步骤:
- 子组件触发自定义事件, 传递参数(可选) this.$emit('自定义事件名', 传参1, 传参2)
-
父组件的子组件便签内 ,以@自定义事件名="函数fn",接收数据
- 父组件methods属性内定义 "函数fn" ,fn中 形参1=传参1,形参2=传参2
-
演示:
子组件的代码
<template> <div> <!-- 第二步:绑定合适的触发时机 --> <button @click.prevent="testClick">子传父</button> </div> </template> <script> export default { data(){ return { dataTest:'传递给父组件的数据', } }, methods:{ testClick(){ //第一步,将要发送的数据传递this.$emit('自定义事件名',要传递的数据1,要传递的数据2) //并封装在函数内 this.$emit('getData',this.dataTest) } } } </script> <style> </style>父组件的代码
<template> <div> <!--第三步:在子组件标签中,以那个自定义的事件名为事件,并绑定真正在父组件中要触发的函数 --> <ProdTest @getData="EvetFn"></ProdTest> <div>子组件的数据:</div> <div class="fromson">{{fromSonData}}</div> </div> </template> <script> import ProdTest from "./测试子组件.vue"; export default { data(){ return { fromSonData:'' } }, components:{ ProdTest, }, methods:{ //第四步,触发函数的第一个参数就是子组件传递的数据1,以此类推 EvetFn(val){ this.fromSonData=val } } }; </script> <style scoped> .fromson{ color: orange; font-size: 30px; } </style>
4. Vue-生命周期
4.1 钩子函数
- 概念:Vue 框架内置函数,随着组件的生命周期阶段,自动执行
- 作用: 特定的时间点,执行特定的操作
- 场景: 组件创建完毕后,可以在created 生命周期函数中发起Ajax 请求,从而初始化 data 数据
- 注意点
- 分类: 4大阶段8个方法
| 阶段 | 方法名 | 方法名 |
|---|---|---|
| 初始化 | beforeCreate | created |
| 挂载 | beforeMount | mounted |
| 更新 | beforeUpdate | updated |
| 销毁 | beforeDestroy | destroyed |
贴上关于钩子函数的官方文档,按需查看。
4.2 初始化阶段
初始化阶段2个钩子函数作用和执行时机
含义讲解:
1.new Vue() – Vue实例化(组件也是一个小的Vue实例)
2.Init Events & Lifecycle – 初始化事件和生命周期函数
3.beforeCreate – 生命周期钩子函数被执行
4.Init injections&reactivity – Vue内部添加data和methods等
5.created – 生命周期钩子函数被执行, 实例创建
6.接下来是编译模板阶段 –开始分析
7.Has el option? – 是否有el选项 – 检查要挂到哪里
没有. 调用$mount()方法
有, 继续检查template选项
components/Life.vue - 创建一个文件
<script>
export default {
data(){
return {
msg: "hello, Vue"
}
},
// 一. 初始化
// new Vue()以后, vue内部给实例对象添加了一些属性和方法, data和methods初始化"之前"
beforeCreate(){
console.log("beforeCreate -- 执行");
console.log(this.msg); // undefined
},
// data和methods初始化以后
// 场景: 网络请求, 注册全局事件
created(){
console.log("created -- 执行");
console.log(this.msg); // hello, Vue
this.timer = setInterval(() => {
console.log("哈哈哈");
}, 1000)
}
}
</script>
App.vue - 引入使用
<template>
<div>
<h1>1. 生命周期</h1>
<Life></Life>
</div>
</template>
<script>
import Life from './components/Life'
export default {
components: {
Life
}
}
</script>
4.3 挂载阶段
挂载阶段2个钩子函数作用和执行时机
含义讲解:
1.template选项检查
有 - 编译template返回render渲染函数
无 – 编译el选项对应标签作为template(要渲染的模板)
2.虚拟DOM挂载成真实DOM之前
3.beforeMount – 生命周期钩子函数被执行
4.Create … – 把虚拟DOM和渲染的数据一并挂到真实DOM上
5.真实DOM挂载完毕
6.mounted – 生命周期钩子函数被执行
components/Life.vue - 创建一个文件
<template>
<div>
<p>学习生命周期 - 看控制台打印</p>
<p id="myP">{{ msg }}</p>
</div>
</template>
<script>
export default {
// ...省略其他代码
// 二. 挂载
// 真实DOM挂载之前
// 场景: 预处理data, 不会触发updated钩子函数
beforeMount(){
console.log("beforeMount -- 执行");
console.log(document.getElementById("myP")); // null
this.msg = "重新值"
},
// 真实DOM挂载以后
// 场景: 挂载后真实DOM
mounted(){
console.log("mounted -- 执行");
console.log(document.getElementById("myP")); // p
}
}
</script>
复制代码
4.4 更新阶段
更新阶段2个钩子函数作用和执行时机
含义讲解:
1.当data里数据改变, 更新DOM之前
2.beforeUpdate – 生命周期钩子函数被执行
3.Virtual DOM…… – 虚拟DOM重新渲染, 打补丁到真实DOM
4.updated – 生命周期钩子函数被执行
5.当有data数据改变 – 重复这个循环
components/Life.vue - 创建一个文件
准备ul+li循环, 按钮添加元素, 触发data改变->导致更新周期开始
<template>
<div>
<p>学习生命周期 - 看控制台打印</p>
<p id="myP">{{ msg }}</p>
<ul id="myUL">
<li v-for="(val, index) in arr" :key="index">
{{ val }}
</li>
</ul>
<button @click="arr.push(1000)">点击末尾加值</button>
</div>
</template>
<script>
export default {
data(){
return {
msg: "hello, Vue",
arr: [5, 8, 2, 1]
}
},
// ...省略其他代码
// 三. 更新
// 前提: data数据改变才执行
// 更新之前
beforeUpdate(){
console.log("beforeUpdate -- 执行");
console.log(document.querySelectorAll("#myUL>li")[4]); // undefined
},
// 更新之后
// 场景: 获取更新后的真实DOM
updated(){
console.log("updated -- 执行");
console.log(document.querySelectorAll("#myUL>li")[4]); // li
}
}
</script>
4.5 销毁阶段
销毁阶段2个钩子函数作用和执行时机
含义讲解:
1.当$destroy()被调用 – 比如组件DOM被移除(例v-if)
2.beforeDestroy – 生命周期钩子函数被执行
3.拆卸数据监视器、子组件和事件侦听器
4.实例销毁后, 最后触发一个钩子函数
5.destroyed – 生命周期钩子函数被执行
components/Life.vue - 准备生命周期方法(Life组件即将要被删除)
<script>
export default {
// ...省略其他代码
// 四. 销毁
// 前提: v-if="false" 销毁Vue实例
// 场景: 移除全局事件, 移除当前组件, 计时器, 定时器, eventBus移除事件$off方法
beforeDestroy(){
// console.log('beforeDestroy -- 执行');
clearInterval(this.timer)
},
destroyed(){
// console.log("destroyed -- 执行");
}
}
</script>
复制代码
主要: App.vue - 点击按钮让Life组件从DOM上移除 -> 导致Life组件进入销毁阶段
<Life v-if="show"></Life>
<button @click="show = false">销毁组件</button>
<script>
data(){
return {
show: true
}
},
</script>
5. ref与nextTick
5.1 ref属性
-
作用:用于获取组件对象或者标签,还可以修改组件中的数据
-
语法:
- 给标签或组件标签设置 ref属性
- 恰当时机, 通过ref属性 获取组件对象, 可调用组件对象里方法等
-
演示
- 父组件
<template> <div> <ProdTest id="testId" ref="testRef"></ProdTest> </div> </template> <script> import ProdTest from "./components/02-组件-refs的测试.vue"; export default { components: { ProdTest, }, mounted(){ console.log(document.querySelector('#testId'));//打印的是子组件的第一层根标签 console.log(this.$refs.testRef);//打印的是子组件对象 this.$refs.testRef.testData='我偏不' //修改子组件数据 this.$refs.testRef.sayHi() //调用子组件方法 } }; </script>- 子组件
<template> <div> <ul> <li>{{testData}}</li> </ul> </div> </template> <script> export default { data (){ return { testData:'生意嘛,不寒碜' } }, methods:{ sayHi(){ alert('方法调用成功') } } } </script>
5.2 this.$nextTick
- 应用场景:由于dom元素的更新是异步的,this.$nextTick(函数体) 可以等DOM更新后, 触发此方法里函数体执行
- 语法:this.$nextTick(函数体)
- 代码演示:
<template>
<div>
<button @click="tooggleShow" v-if="isShow">切换</button>
<input type="text" v-else placeholder="天真" ref="ipt">
</div>
</template>
<script>
export default {
data(){
return {
isShow:true
}
},
methods:{
tooggleShow(){
this.isShow=!this.isShow //值取反后dom元素并不会马上渲染到页面,
this.$nextTick(()=>{ //因此要使用该方法,执行dom更新后要执行的函数代码
this.$refs.ipt.focus()
console.log(this.$refs.ipt);
})
}
}
}
</script>
<style>
input {
animation: testAni 2s infinite alternate linear;
}
@keyframes testAni {
from{
margin-top: 0;
}to{
margin-top: 400px;
}
}
</style>
6.Vue组件进阶
6.1 动态组件
-
作用:用于组件间的切换
-
原理:设置挂载点, 使用is属性来设置要显示哪个组件,is的属性值为要切换的组件名
-
代码演示(先自行创建2个或以上的子组件,并完成引入与注册)
<template> <div> <p> <!-- 通过按钮控制变量的取值 --> <button @click="comName = 'TestProid1'">组件1</button> <button @click="comName = 'TestProid2'">组件2</button> </p> <!-- 通过v-bind指令使 is属性值能使用变量,进而控制变量值即可完成组件切换 --> <component :is="comName"></component> </div> </template> <script> import TestProid1 from "@/components/01-动态组件-子1.vue"; import TestProid2 from "@/components/02-动态组件-子2.vue"; export default { data() { return { comName: "TestProid1", }; }, components: { TestProid1, TestProid2, }, }; </script> -
通过挂载点,切换组件的原理是反复创建于销毁组件,故建议使用keep-alive内置组件优化性能,此时切换的两个子组件会多两个钩子函数:
-
钩子函数在子组件内部定义
-
activated – 激活时触发
-
deactivated – 失去激活状态时触发
-
<template>
<div>
<p>
<button @click="comName = 'TestProid1'">组件1</button>
<button @click="comName = 'TestProid2'">组件2</button>
</p>
<!-- keep-alive组件包裹component组件即可 -->
<keep-alive>
<component :is="comName"></component>
</keep-alive>
</div>
</template>
<script>
import TestProid1 from "@/components/01-动态组件-子1.vue";
import TestProid2 from "@/components/02-动态组件-子2.vue";
export default {
data() {
return {
comName: "TestProid1",
};
},
components: {
TestProid1,
TestProid2,
},
};
</script>
6.2 slot 组件插槽
- 应用场景:一个组件内有需要外部传入标签的地方,
- 使用方法:在组件内用占位,使用组件时夹着的地方, 传入标签替换slot ,(Pannel为自定义的组件名)
- 中间包裹的内容为,默认显示内容,中间无内容时,子组件内的会替换成默认显示内容
- 代码演示
<!-- 子组件 -->
<template>
<div>
<!-- slot 用于占位,需要调用子组件的的人自定义标签内容 -->
<slot>你调用子组件不传入内容我就默认显示这个</slot>
</div>
</template>
<script>
export default {}
</script>
<style scoped>
div {
width: 100%;
height: 80px;
border: 2px dashed orange;
}
</style>
<!-- 父组件 -->
<template>
<div>
<!-- 子组件双标签之间夹住的内容,实际上会代替 slot的位置 -->
<TestSlot>
<button>李白</button>
<button>杜甫</button>
</TestSlot>
<TestSlot>
<button>白居易</button>
</TestSlot>
<!--组件标签内无内容时,会显示 slot的默认值 -->
<TestSlot> </TestSlot>
</div>
</template>
<script>
import TestSlot from "@/components/04-slot 插槽标签.vue";
export default {
components: {
TestSlot,
},
};
</script>
6.3 v-slot 具名插槽
-
应用场景:一个组件内有2处以上需要外部传入标签的地方
-
语法:
- v-slot:可以简化成 #
- slot使用name属性区分名字
- template配合v-slot:名字来分发对应标签
- 在v-slot属性上可以绑定一个变量名,这个变量是一个对象,这个对象包含子组件传过来的所有数据
- 代码演示
<!-- 子组件 -->
<template>
<div>
<!-- slot上的name属性值,绑定具名 -->
<slot name="left"></slot>
<slot name="right"></slot>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
div {
width: 100%;
height: 80px;
border: 2px dashed orange;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 25px;
}
</style>
<!-- 父组件 -->
<template>
<div>
<TestSlot>
<!-- 组件标签的template标签 v-slot 简写 # 绑定使用 -->
<template #left>
<button>显示在左边</button>
</template>
<template #right>
<button>显示在右边</button>
</template>
</TestSlot>
<TestSlot>
<template #left> 我只是一个小标题 </template>
<template #right>
<span> 我很听话地待在右边 </span>
</template>
</TestSlot>
</div>
</template>
<script>
import TestSlot from "@/components/06- v-slot具名插槽.vue";
export default {
components: {
TestSlot,
},
};
</script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
</style>
- 具名插槽 - 子组件传递数据给父组件
<!-- 子组件 -->
<template>
<div>
<!-- 第一步:用属性绑定变量传递 -->
<slot :data="str" name="left"></slot>
<slot name="right"></slot>
</div>
</template>
<script>
export default {
data(){
return {
str:'君不见黄河之水天上来'
}
}
}
</script>
<style scoped>
div {
width: 100%;
height: 80px;
border: 2px dashed orange;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 25px;
}
</style>
<!-- 父组件 -->
<template>
<div>
<TestSlot>
<!-- 第二步:通过 #具名="自定义变量名" 自定义变量名(对象)会一次接收所有子组件通过 v-bind属性名 传递的数据,-->
<template #left="obj">
<!-- 通过 obj.属性 的方式调用 -->
<button>{{ obj.data }}</button>
</template>
<template #right>
<button>显示在右边</button>
</template>
</TestSlot>
</div>
</template>
<script>
import TestSlot from "@/components/08-通过v-slot 子传父-子组件.vue";
export default {
components: {
TestSlot,
},
};
</script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
</style>
7. 路由
7.1 简单理解
- 概念:路由是一种标记到资源的映射关系,在vue中就是url路径和组件的映射关系,即 特定的url路径指向对应的组件
- 作用:在没有发生html跳转的情况下,完成页面的切换
- 从语义及作用出发将组件分类:/src/views (pages) 页面组件 / /src/components 复用组件
7.2 路由系统的引入
-
方式一:引入和配置对象都写在main.js文件中,不单独封装
// 如果main.js没有引入vue则要先 //import Vue from 'vue' // 1. 引入库 import VueRouter from 'vue-router' // 2.注册全局组件 Vue.use(VueRouter) // 3. routes 创建路由规则 路由配置 详见7.3 // 4. 创建一个实例 const router = new VueRouter({ // 放入 routes, 属性名必须叫 routes //mode: 'history' 去掉地址栏上的 # (默认值为 hash ) }) new Vue({ // 4. 将实例挂载到 new Vue 根实例上 router, render: h => h(App), }).$mount('#app') -
方式二:在 /src/router (index.js) 下单独封装,导出并挂载到main.js中
//在 index.js文件中 //1. 引入路由系统及 vue import VueRouter from "vue-router"; import Vue from "vue"; // 2. 注册全局组件 Vue.use(VueRouter) // 3. routes 创建路由规则 路由配置 详见7.3 // 4. 将路由配置放入实例化的路由对象中, const router=new VueRouter({ // 放入 routes, 属性名必须叫 routes }) // 5. 导出路由对象 export default router //在main.js文件中 // 6. 引入封装的路由对象 import router from './router/index.js'; new Vue({ router, // 7. 将实例挂载到 new Vue 根实例上 render: h => h(App), }).$mount('#app')
7.3 路由配置
-
路由配置是指路由对象里的一个属性,用于指定url与路由组件的映射关系
-
路由配置有两种写法:逐一引入 / 按需引入
- 逐一先引入路由组件后配置
// 1 引入组件对象 2 指定对应路径 import Login from '@/views/Login.vue' import Find from '@/views/Find.vue' const routes = [ { path: '/', // 重定向,当用户直接访问localhost:8080时强制跳转到登录页 redirect: '/login' }, { // 1. path 路径 / 开头 path: '/find', // 2. component 组件 component: Find }, { // 1. path 路径 / 开头 path: '/login', // 2. component 组件 component: Login }, ] //注:定义好的路由配置最终要放在 router 实例中- 按需引入组件,当用户访问到对应页面是才会加载组件
const routes=[ { path:'/', // 重定向,当用户直接访问localhost:8080时强制跳转到登录页 redirect: '/login' }, { path:'/login', // 按需引入组件,当用户访问到login页面才加载login.vue组件 component:()=>import('@/views/login.vue') }, { path:'/register', component:()=>import('@/views/register.vue') }, ] //注:定义好的路由配置最终要放在 router 实例中 -
路由配置嵌套 =>直接在一级路由配置里面嵌套即可
const routes=[ { // 1. path 路径 / 开头 path: '/find', // 2. component 组件 component: Find, redirect: '/find/ranking', //子路由的重定向 // 嵌套子路由 children: [ // 依旧是 path 跟 component 的配对 // 不要加斜杠, 因为需要改上一层拼接在一起 // 如果加了, 就需要在根路径进行访问 { path: 'ranking', component: ()=>import('@/views/ranking.vue') }, { path: 'recommend', component: ()=>import('@/views/recommend.vue') }, { path: 'songlist', component: ()=>import('@/views/songlist.vue') }, ] }, ] //注:二级路由的挂载点(<router-view></router-view>)放在对应的一级路由组件中
7.4 挂载点和路由链接
7.4.1 简单介绍
- 路由第三方库给我们提供了两个组件, router-view/挂载点, router-link/路由链接
- 挂载点:router-view, 决定了路由组件最终摆放的位置
- 路由链接:router-link ,最终会编译成 a 标签,to属性的值接收了要跳转的路由组件的url
- 演示:
<template>
<div>
<!-- 点击不同的 router-link 时,下方的挂载点会显示对应的组件-->
<router-link to="/find/ranking">排行榜</router-link>
<router-link to="/find/recommend">推荐</router-link>
<router-link to="/find/songList">列表</router-link>
<!-- 最终对应的路由组件摆放的位置 -->
<router-view></router-view>
</div>
</template>
7.4.2路由链接传值给路由组件
- 在 router-link的 to 属性上传值(两种方式)
- /path?参数名=值
- /path/值 该方法需在路由配表中对应的配置对象提前配置 path:"/path/:参数名"
- 在对应路由组件接收传递的值(分别对应)
- 方法1.1的接收方式: $route.query.参数名
- 方法1.2的接收方式: $route.params.参数名
<!-- 调用者文件 -->
<template>
<div>
<router-link to="/find?name=方方方"> 跳转到发现页</router-link>
<router-view></router-view>
</div>
</template>
<!-- 被调用的路由组件 -->
<template>
<div>
发现音乐<br>
{{$route.query.name}}
</div>
</template>
7.5 编程式导航与声明式导航
7.5.1编程式导航
编程式导航是用在js处理逻辑后需要页面跳转,比如点击button按钮跳转
export default {
methods: {
//点击按钮跳转路由
/*方式一: 直接 path 作为字符串传入
handleClick() {
this.$router.push('/my')
} */
/*方式二: 传入一个对象, 其中带有 path 属性
handleClick() {
this.$router.push({
path: '/my'
})
} */
// 方式三:传入一个对象, 其中带有 name 属性, 需要在路由中预先配置
handleClick() {
this.$router.push({
// 需要 params 传参的话
// path 跟 params 两个属性会冲突
// path: 'part/8888',
//name 属性, 需要在路由中预先配置 同一个属性值
name: 'partPage',
//路由组件同样可以用 $route.params.参数名 接收参数值
params: {
id: 66666
}
})
}
}
}
7.5.2声明式导航
声明式导航是直接渲染到页面的,比如a链接 与 router-link组件
<router-link to="/find"> 跳转到发现页</router-link>
<router-link to="/my">跳转到我的音乐</router-link>
<a href="#/login">跳转到登录页</a> <!-- a标签跳转路由需加上 # 号 -->
<router-view></router-view>
7.5.3 $router 方法小扩展
- this.$router.push() //会进行页面跳转,同时会在历史记录上留下记录
- this.$router.replce() //和push功能相同,但是会替换当前页出现在历史记录中
- this.$router.go(num) //表示距离当前页的在历史记录上的页数
- this.$router.back() 返回到上一页
- this.$router.forward() 前进到下一页
7.6 路由守卫
-
简单理解为所有路由跳转前都会执行的函数,router路由实例上添加,一般定义在main.js文件中
//创建的路由实例叫什么,路由守卫函数的前缀就得叫什么 const router = new Router({ // 这里可以有配置对象 }) router.beforeEach((to,from,next)=>{ // 拦住了必须放行, 默认这个函数可以接收到三个参数 // to 目的地, from 来源, next 放行回调函数 if (to.path==='/my/75668' && !localStorage.getItem('token')) { next('/find') }else{ next() } })
8. vant组件库
8.1使用方法
-
利用npm命令下载第三方包:npm i vant@2
-
三种引入方式
- 引入全部组件
import Vant from 'vant'; //引入第三方包 import 'vant/lib/index.css'; //引入样式 Vue.use(Vant); //全局注册组件- 手动按需引入
import { Button } from 'vant'; //解构引入具体组件 import 'vant/lib/button/style'; //具体组件对应的样式 Vue.use(Button); //注册该组件- 半自动按需引入, 需先安装插件:npm i babel-plugin-import -D
// 按需引入 ,解构的方式引入 import { Button,Field,} from 'vant'; //省去了对应样式的引入步骤,插件会自动引入样式 // 注册对应组件,注册不能合并成一行写 Vue.use(Button); Vue.use(Field);vuex
1. 简单介绍
- 概念:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
- 大白话:集中管理系列全局的数据变量等的一个对象,通过内部封装的各个属性方法对全局数据修改更新。
- 特点:对于数据的更新和修改,只能使用内置属性,不再是传统方法。
- 使用方法:
npm i vuex@3
注意:如果用的是vue2这个框架,vuex必须下载3这个版本
2. state 共享状态数据
-
理解:用来声明全局数据的属性
-
声明方法:
const store=new Vuex.Store({ state:{ str:'肥仔快乐水', num:111, list:[1,2,3,4,5,6,7,8,9,110] }, }) -
组件如何调用
<template> <div> <!--第一种 $store.state.变量名 --> <h3>{{$store.state.num}}</h3> <!--第二种 computed属性里的函数返回值 --> <h3>写在计算属性:{{myNum}}</h3> <!--第三种 内置辅助函数解构形同正常变量使用 --> <h3>通过mapState辅助函数解构的state变量str:{{str}}</h3> <h3>通过mapState辅助函数解构的state变量num:{{num}}</h3> </template> <script> // 辅助函数第1步. 引入 import {mapState} from 'vuex' export default { computed:{ // state优化使用,写在computed属性中,通过函数返回值 myNum(){ return this.$store.state.num }, // 辅助函数第2步. 以方法解构的方式 ...mapState(['state变量名1','state变量名2']) ...mapState(['str','num']) }, } </script>
3. mutations 同步更新修改
-
理解:state数据的修改只能通过mutations,并且必须是同步更新(也就是里面不能有异步代码),目的是形成数据快照。(mutations是专门用来修改state中的变量的对象(属性))
-
声明函数的方法(main.js文件中, mutations 属性内):
const store=new Vuex.Store({ state:{ num:111, }, mutations:{ // 通过mutations里面的方法修改state里面的数据,除state外,只能有一个形参,可通过以数组为形参的方式扩参 addfn(state,data){ //state 为上述定义的数据变量 state.num+=data } }, }) -
组件如何调用:
<template> <div> <h3>观察num的改变:{{$store.state.num}}</h3> <!--1. $store.commit('要调用的函数名',实参) --> <button @click="$store.commit('addfn',5)">直接调用:加5</button> <!--2. 在methods属性中声明函数,函数内进行$store.commit,详见addFnTest函数 --> <button @click="addFnTest(100)">函数封装:加100</button> <!--3. 通过mapMutations辅助函数将方法解构出来,当正常函数使用 --> <button @click="addfn(200)">mapMutations解构的: 点我加200</button> </div> </template> <script> // 辅助函数第1步 引入 import {mapMutations} from 'vuex' export default { methods:{ // 优化,函数调用函数 addFnTest(num){ this.$store.commit('addfn',num) }, // 辅助函数第2步,解构: ...mapMutations(['要解构的函数名']) ...mapMutations(['addfn']) } } </script>
4.actions异步更新
-
actions就是可以通过异步操作,调用mutations中的函数,从而修改state中的变量。
-
声明函数的办法(main.js文件中, actions属性内):
const store=new Vuex.Store({ state:{ num:111, }, actions:{ // 第一个参数是,store实例对象, store.state才是上述的数据属性 getAsyncNum(store,data){ setTimeout(() => { store.state.num+=data }, 2000); } }, }) -
组件如何调用:
<template> <div> <h3>观察num的改变:{{$store.state.num}}</h3> <!--1. $store.dispatch('要调用的函数名',实参) --> <button @click="$store.dispatch('getAsyncNum',10)">直接调用:延迟2秒后加10</button> <!--2. 在methods属性中声明函数,函数内进行$store.dispatch,详见testAsyncNum函数 --> <button @click="testAsyncNum(20)">函数封装:延迟2秒后加20</button> <!--3. 通过mapMutations辅助函数将方法解构出来,当正常函数使用 --> <button @click="getAsyncNum(30)">mapActions解构的: 延迟2秒后加30</button> </div> </template> <script> // 辅助函数第1步 引入 import {mapActions} from 'vuex' export default { methods:{ // 优化,函数调用函数 testAsyncNum(num){ this.$store.dispatch('addfn',num) }, // 辅助函数第2步,解构: ...mapActions(['要解构的函数名']) ...mapActions(['getAsyncNum']) } } </script>
5.getters 变量派生
-
理解:除了state可以声明全局变量之外,还可以利用getters声明全局变量,只不过getters声明的变量是从state派生出来的,getters就相当于vue中的computed计算属性。
-
声明办法:
const store=new Vuex.Store({ state:{ list:[1,2,3,4,5,6,7,8,9,110] }, // getters类似于计算属性中的变量 getters:{ // 内置参数 state 即state属性 filterList:(state)=>{ return state.list.filter(item=>item>5) } } }) -
组件调用
<template> <div> <!--1. $store.getters.变量名 --> <h2>$store.getters.mapList直接调用:{{$store.getters.mapList}}</h2> <!--2. 在computed属性中声明函数,函数内return this.$store.getters.变量名 --> <h2>函数封装返回值{{testmapList}}</h2> <!--3. 通过mapGetters辅助函数将方法解构出来,当正常计算属性变量使用 --> <h2>辅助函数解构:{{mapList}}</h2> </div> </template> <script> // 辅助函数第1步 引入 import { mapGetters,} from 'vuex' export default { computed:{ // 辅助函数第2步,解构: ...mapGetters(['要解构的变量名']) ...mapGetters(['mapList']), testmapList(){ return this.$store.getters.mapList } } } </script>
6.module模块化
-
理解:分模块管理我们的全局变量,这样有利于项目的后期维护
-
声明方法
const store=new Vuex.Store({ state:{ str:'肥仔快乐水', num:111, list:[1,2,3,4,5,6,7,8,9,110] }, // 通过mutations里面的方法修改state里面的数据 mutations:{ addfn(state,[data,abc]){ state.num+=data console.log(typeof data); console.log(abc); } }, actions:{ // 第一个参数是,store实例对象 getAsyncNum(store,num){ setTimeout(() => { store.state.num=store.state.num*num }, 2000); } }, // getters类似于计算属性中的变量 getters:{ // 内置参数 state 即state属性 mapList:(state)=>{ return state.list.filter(item=>item>5) }, // 利用一层getters简化模块内的数据 userName:state=>state.user.userName, my_like:state=>state.setting.my_like }, modules:{ /* 模块内的mutations,actions,getters 都是挂载到一层的,调用方法与一层一致 */ user:{ // 加锁,模块封闭化 namespaced:true, state:{ userName:'黄昏' }, mutations:{ changeUN(state){ state.userName='约尔' } }, actions:{ asyncChangeUN(store){ setTimeout(() => { store.commit('changeUN') }, 2000); } } }, setting:{ state:{ my_like:'间谍过家家' } } } }) -
组件调用
<template> <div> <h2>$store.state.user.变量名,直接调用:{{$store.state.user.userName}}</h2> <h2>$store.state.user.变量名,直接调用:{{$store.state.setting.my_like}}</h2> <h3>getters简化,解构后调用:{{userName}}</h3> <h3>getters简化,解构后调用:{{my_like}}</h3> <!-- 模块加namespaced:true 后不能全局直接调用,加多一层模块名才可 <button @click="$store.commit('changeUN')">mutations修改变量userName</button> <button @click="$store.dispatch('asyncChangeUN')">actions延迟修改变量userName</button> --> <!-- <h3>当设置模块内属性namespaced:true,加模块名后才能调用方法</h3> <button @click="$store.commit('user/changeUN')">mutations修改变量userName</button> <button @click="$store.dispatch('user/asyncChangeUN')">actions延迟修改变量userName</button> --> <h3>当设置模块内属性namespaced:true,辅助函数接解构调用也有所不同</h3> <button @click="changeUN">mutations修改变量userName</button> <button @click="asyncChangeUN">actions延迟修改变量userName</button> </div> </template> <script> import {mapGetters,mapMutations,mapActions} from 'vuex' export default { computed:{ ...mapGetters(['userName','my_like']) }, methods:{ // 模块上锁后,辅助函数解构,方式有所不同 ...mapMutations('user',['changeUN']), ...mapActions('user',['asyncChangeUN']) } } </script> <style> </style>