文章目录
- Vue
- 二组件
- 第五章
- es6文件导入出
- 1、导出export
- 组件(component)
- 1、定义
- 2、模块化与组件化
- 3、组件的分类
- 1、非单文件组件
- 非单文件三步骤
- 创建组件标准写法
- 简化写法
- 组件的嵌套
- 非单文件的不足之处
- 2、单文件组件
- vue单文件组件的使用
- 脚手架创建项目
- 重点关注文件
- 3、vue组件
- 第六章
- 1、脚手架
- 1、修改默认配置
- 2、获取文本框内容
- 1、通过dom获取
- 2、通过vue的ref语法
- 3、vue插件
- 1、plugin插件
- 4、scoped样式
- 5、props属性
- 1、子组件在接受父组件参数使用props的三种用法
- 用法1
- 用法2
- 用法3
- 2、父组件向给组件传递参数的写法
- 写法1
- 写法2
- 6、综合练习
- 实现头部功能
- 1、子组件向父组件传递参数
- 2、在向todos数组中添加数据时,每一条数据的id是唯一标识
- 实现底部数据显示
- 当鼠标悬停某一行数据时显示删除按钮
- 全选或者全取消
- 第七章
- 1、localstorage存
- 1、存放普通数据
- 2、存放对象数据
- 3、存放数组
- 2、localstorage取
- **1、取普通数据**
- 2、取数组
- 3、取对象
- 3、移除数据
- 4、监听
- 开启深度监听
- 5、自定义事件
- 6、全局消息总线
- 组件间的传递参数
- 第八章
- 1、全局消息总线
- 2、消息发布与订阅
- 1、使用步骤
- 2、参数传递的方式
- 3、vue服务器代理配置
- 跨域问题
- 4、slot插槽
- 1、默认插槽
- 2、具名插槽
- 5、vuex
- 第一个示例:
- 第九章
- 阶段1:计数器的示例
- **1、标准流程:**
- 2、简化流程
- 3、获取语法
- 4、简化state中属性的方法
- 5、简化Actions中事件的调用
- 6、简化Mutations中函数的调用
- 阶段2:模块化+命名空间
Vue
这是v2版
二组件
第五章
vue组件化 非单文件组件 es6导入、导出语法
单文件组件 单文件组件的基本语法 vue脚手架
es6文件导入出
1、导出export
export:导出
作用:用于将当前资源对外暴露,方便其他模块引用
方式1:分别暴露
//index.js中的代码
export let msg="hello,world";
export function show(){
alert(123);
}
//在html页面中引入index.js暴露的资源
<script type="module">
import * as m from './js/index.js'
//m就代表index.js文件
alert(m.msg);
m.show();
</script>
方式2:统一暴露
//index.js中的代码
let str = "CNM";
let qaq = "555";
export { str, qaq }
//在html页面中引入index.js暴露的资源
<script type="module">
import{str,msg} from './js/index.js'
//此时就不用.xx来输出了
console.log(qaq);
</script>
方式3:默认暴露
//index.js中的代码
export default{
name:"arjun",
show(){
console.log("默认暴露");
}
}
//在html页面中引入index.js暴露的资源
import * as m1 from './js/index.js'
m1.default.show()
组件(component)
1、定义
组件:实现应用中局部功能代码和资源的集合
组件是vue.js最强大的功能之一。组件可以扩展html元素,封装可重用的代码
vye组件是页面(html代码,css代码)进行模块化
2、模块化与组件化
在vue应用中,一个页面可能是由多个区域构成,每一个区域可以封装成一个单独的组件
每一个组件中就可以包含该区域要使用的html,js,css
然后将这些组件组合在一起就可以形成完整的页面
如果页面上某一个区域的内容要发生改变,只需要将对应的组件进行替换即可
3、组件的分类
1、非单文件组件
特点:非单文件组件:一个文件包含n个组件
所有代码写在一文件中,它的文件名不是vue结尾
缺点: 1、模板编写没有提示
2、没有构建过程,无法将es6转换成es5
3、不支持组件的css
4、真正开发中几乎不用
非单文件三步骤
创建组件:
1、template用于声明组件页面布局,它的内容写在``之间,它只能有一个根元素
2、组件中的数据模型data是一个函数,需要指定在()并且用return声明
3、组件中的其他用法:函数、计算属性,过滤器等用法都一样
声明组件:
var vm = new Vue({
el: '#app',//指定的vue容器id名称
//二、注册组件
components: {
//组件名:对应的组件(如果组件名与组件同名,可以省略只写一个)
school
}
应用组件:
<div id='app'>
<!-- 三、使用组件 -->
<school></school>
</div>
//注意:在非单文件组件中不允许直接闭合<school/>
创建组件标准写法
<body>
<div id='app'>
<!-- 三、使用组件 -->
<myschool></myschool>
</div>
<script src='js/vue.js'></script>
<script>
Vue.config.productionTip = false;
// 一、定义组件
const school = Vue.extend({
// 1、指定模板(要显示的html标签)
//模板中只能有一个根元素
template: `
<div>
<h1>学校信息</h1>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
`,
// 2、指定组件中的数据模型(组件中的数据是一个函数)
data() {
return {
schoolName: "东京大学",
address: "日本"
}
}
})
var vm = new Vue({
el: '#app',//指定的vue容器id名称
//二、注册组件
components: {
//组件名:对应的组件(如果组件名与组件同名,可以省略只写一个)
myschool: school
}
})
</script>
</body>
简化写法
注册组件:
const stu = {
template: `
<div>
<h1>学生信息</h1>
<h2>学生姓名:{{name}}</h2>
<h2>学生成绩:{{score}}</h2>
</div>
`,
// 2、指定组件中的数据模型(组件中的数据是一个函数)
data() {
return {
name: "张三",
score: "90"
}
}
}
组件的嵌套
1、先声明子组件
const stu = {
template: `
<div>
<h1>学生信息</h1>
<h2>学生姓名:{{name}}</h2>
<h2>学生成绩:{{score}}</h2>
</div>
`,
// 2、指定组件中的数据模型(组件中的数据是一个函数)
data() {
return {
name: "张三",
score: "90"
}
}
}
2、在父组件注册子组件
//创建父组件:school
const school = {
template: `
<div>
<h1>学校信息</h1>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<hr>
<stu></stu>
</div>
`,
// 2、指定组件中的数据模型(组件中的数据是一个函数)
data() {
return {
schoolName: "东京大学",
address: "日本"
}
},
// 在父组件中注册子组件
components: {
stu
}
};
非单文件的不足之处
1、它所有的组件包含在一个页面,编写代码并不方便
2、它的模板布局temolate要写在``中,且没有提示
//实际开发很少用到,更多的是单文件组件
2、单文件组件
把一个组件全部内容汇合到一个文件中,文件名字是以.vue结尾
一个组件就是一个独立的*.vue文件,它可以包含自己的js,template,css
特点:1、它的后缀是.vue
2、它可以将一个区域的内容封装成一个vue组件,该组件包含有:js css html
3、将这些组件组合在一起,就可以形成完整的程序
在讲解单文件组件之前,我们首先要学习es6文件的导入、导出语法
vue单文件组件的使用
.vue文件就是一个单文件组件
该方法中只能包含三个部分的内容:
template:------用于指定模板,该组件的所有html代码都要包含在该区域
srcipt:--------用于指定js代码
style:---------用于指定组件的所有样式代码
安装插件–>vuter
vue脚手架:Vue CLI
脚手架创建项目
1、创建一个目录(该目录用于保存脚手架创建的项目)
2、用cmd命令进入该目录
3、执行命令使用脚手架创建项目
vue create 项目名称
vue create arjun
4、当工程创建成功后,使用命令进入项目中
cd arjun
5、通过npm启动项目
npm run serve
6、通过返回的地址即可访问vue程序
main.js---------它是vue的入口js文件,vue的实例是在此文件中创建的,要导入各种插件,也需要在改文件中导入
app.vue是一个入口组件,其他组件都要通过它进行加载
重点关注文件
index.html 默认加载的页面
assets 它可以存放一些图片或者是css样式文件
cpmponents 它包含我们自己创建的vue组件
App.vue 它是入口组件,其他的vue组件需要通过它加载
main.js 它是入口js,用于配置vue实例,以及配置各种插件
vue.config.js 它是核心js
3、vue组件
我们自己创建的vue组件要放到components目录下
组件名字:
1、驼峰命名法
2、中间-斜杠
要求:
1、名字必须采用帕斯卡命名法
2、名称要求多个单词组合而成
第六章
1、脚手架
1、修改默认配置
在vue.config.js文件中编写如下代码
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
//忽略语法检查
lintOnSave:false
})
2、获取文本框内容
1、通过dom获取
alert(document.getElementById("user").value);
2、通过vue的ref语法
<input type="text" name="user" id="user" ref="msg" />
//获取
alert(this.$refs.msg.value);
3、vue插件
作用:进行vue功能的增强,实现功能的重复使用
例如:我们要在插件中配置一个过滤器,进行日期类型的转换,其他组件要转换日期类型数据时,就不需要重复创建过滤器
1、plugin插件
1、创建Plugins.js 编写如下代码
export default{
//安装插件 vue是关键字,代表vue实例
install(Vue){
//在此处,我们可以配置过滤器、自定义指令
Vue.filter("showDate",function(time){
let date = new Date(time);
//分别获得年月日
let y = date.getFullYear();
let m = (date.getMonth() + 1).toString().padStart(2, "0");
let d = date
.getDate()
.toString()
.padStart(2, "0");
return `${y}年${m}月${d}日`;
})
}
}
2、在main.js文件中引入插件,并且使用插件
import Vue from 'vue'
import App from './App.vue'
//导入插件
import Plugins from './plugins'
Vue.config.productionTip = false
//使用插件
Vue.use(Plugins)
new Vue({
render: h => h(App),
}).$mount('#app')
3、在每一个vue组件,直接使用插件中声明的过滤器即可
日期:{{t|showDate}}
牛了个大逼
4、scoped样式
scoped指令样式应用范围:
在默认情况下,在每一个vue组件中声明的样式,最终都要在app.vue进行汇总,即使其他组件没有在内部声明样式,在app.vue中汇总的样式,其他组件也是可以用的
//注意:在app.vue中声明的样式,所有子组件都可以直接使用
示例:
<style scoped>
/* scoped表示当前样式不在app.vue中进行汇总,只在当前组件中使用
*/
.mycss {
background: rgba(red, green, blue, 0.3);
}
</style>
//在app.vue中的<style>标签,不能声明scoped
5、props属性
作用:父组件向子组件传递值
子组件中的代码
<template>
<div class="mycss">
<h1>学生姓名:{{stuname}}</h1>
<h1>学生成绩:{{score}}</h1>
</div>
</template>
<script>
export default {
name: "MyStu",
//在子组件中,声明要接受的参数
//子组件接受到的参数就与在数据模型data中声明的参数效果是一样的
props: ["stuname", "score"]
};
父组件中的代码
<template>
<!-- 此处用于指定html模板代码,只能有一个根元素 -->
<div>
父组件
<div class="mycss">
<h1>学校名称:{{schoolname}}</h1>
<h1>学校地址:{{address}}</h1>
</div>
<hr />子组件
<stu :stuname="'张三'" :score="90" />
<stu :stuname="'李四'" :score="100" />
</div>
</template>
<script>
//导入学生组件
import stu from "./stu";
//对外暴露的js
export default {
//给当前组件指定名称
name: "MySchool",
//在组件中声明数据模型,必须是函数形式
data() {
return {
schoolname: "千硕教育",
address: "珞喻路110号"
};
},
components: {
//注册组件
stu
}
};
</script>
1、子组件在接受父组件参数使用props的三种用法
用法1
最常用
props: ["stuname", "score"]
用法2
//指定参数的数据类型
props:{
name:String,
score:Number,
}
用法3
props:{
name:{
//指定数据类型
type:String,
//指定参数是必须要的
required:true
},
score:{
//指定数据类型
type:Number,
//指定参数可写可不写,默认值为0
default:0
},
}
2、父组件向给组件传递参数的写法
写法1
//字符串不加:它就表示当前是一个String类型的数据
<stu stuname="张三" score="90" />
<stu stuname="李四" score="100" />
//如果参数是一个字符串类型的数据,前面不加:
stuname="张三"
//字符串加:表示当前是动态取值
<stu :stuname="'张三'" :score="90" />
<stu :stuname="'李四'" :score="100" />
//如果参数是一个数值类型,就加上:
:score="99" 它表示动态取到99这个值,赋值给score,系统会把99当成number使 用,两边不用写''
:stuname="张三" 它表示动态取到张三这个值,由于张三是一个字符串类型,两边必 须要有''
写法2
如果要动态获取数据模型中的属性值,传递给子组件,必须加:
<stu :stuname="stuname" :score="score" />
data() {
return {
schoolname: "千硕教育",
address: "珞喻路110号",
stuname: "王五",
score: "90"
};
6、综合练习
实现待办事项的记录
设计知识点:
1、vue组件化的使用
2、父组件向子组件传递参数
3、子组件向父组件传递参数
功能:
1、待办事项的显示
2、待办事项的添加
3、待办事项的删除
4、待办事项的选择
父组件向子组件传递参数,子组件可以用props接受
但是平级不能使用props接受传递过来的参数
实现头部功能
如果是多个组件都要操作的数据,一般可以在父组件app.vue中声明
对app.vue中的数据模型操作的函数,也全部在父组件app.vue中声明
1、子组件向父组件传递参数
1、首先在子组件用props声明一个函数,用于接受父组件传递过来的函数
2、在子组件触发事件,通过父组件传递过来的函数
2、在向todos数组中添加数据时,每一条数据的id是唯一标识
解决方案1:可以使用系统时间作为数据的id
解决方案2、可以使用nanoid这个组件,它可以为每一条数据生成一个唯一标识
1、安装nanoid
npm i nanoid
2、在当前组件中引入nanoid
import {nanoid} from 'nanoid'
3、在函数中使用nanoid给对象属性赋值
var todo ={id:nanoid(),title:"xx",done:false}
实现底部数据显示
1、保存显示的所有数据todos数组是在app.vue中,我们需要将父组件的todos传递给myFotter.vue处理
//父向子传递参数,我们可以在子组件中声明props属性来接收
当鼠标悬停某一行数据时显示删除按钮
app----------->mylid----------------->myitem
(todos数组) (删除事件触发)
解决方案:
子组件向父组件传递参数,我们可以在父组件中定义事件,然后将这个时间传递给 子组件,子组件接受传递过来的事件后,通过这个事件即可向父组件传递参数
首先app传递一个事件----->mylit--------->myitem
全选或者全取消
上同
第七章
localstorage数据本地存储
自定义事件
全局消息总线
消息的发布、订阅
1、localstorage存
localstorage:本地存储
作用:用于在本地浏览器中存放用户数据
1、存放普通数据
localstorage.setItem('msg',"普通数据")
2、存放对象数据
//对象
let obj={id:1,name:"jack",score:90};
//对象不能直接存放到localstorage,必须要转换成字符串类型
let msg=JSON.stringify(obj);
//存放
localstorage.setItem('msg',msg)
3、存放数组
//数组
todos: [
//任务编号 任务名称 标识是否完成
{ id: "1", title: "干饭", done: true },
{ id: "2", title: "学习", done: false },
{ id: "3", title: "玩游戏", done: false }
]
//对象不能直接存放到localstorage,必须要转换成字符串类型
let msg=JSON.stringify(todos);
//存放
localstorage.setItem('msg',msg)
2、localstorage取
1、取普通数据
//根据键取值
let msg=localstorage.getItem("msg");
2、取数组
var ary = JSON.parse(localStorage.getItem("todos"));
ary.forEach(obj => {
console.log(obj.id + "-" + obj.title + "-" + obj.done);
});
3、取对象
//如果是对象,则需要解析
var obj = JSON.parse(localStorage.getItem("todo"));
console.log(obj.id + "-" + obj.title + "-" + obj.done);
},
3、移除数据
移除一条数据
localStorage.removeItem("todos");
清空数据
localStorage.clear();
4、监听
//这种监听只能监听到数组中的数据改变,不能检测到数据中的属性
//比如勾中了,但一刷新就会又回到没有勾中状态
watch:{
todos() {
localStorage.setItem("todos", JSON.stringify(this.todos));
}
}
开启深度监听
watch: {
//可以监听数据,也能监听属性
todos: {
deep: true,
//开启深度监听
handler(todos) {
localStorage.setItem("todos", JSON.stringify(todos));
}
}
}
5、自定义事件
作用:通过自定义,可以从子组件向父组件传递参数
以前传递参数:父组件需要先把函数传递给子组件,如何子组件调用函数
现在传递参数:
1、在父组件中使用子组件,自定义事件名称
<!-- 在子组件声明自定义事件 -->
<stu @aj="get()" />
如果aj这个事件被触发了,当前组件就会调用get()这个方法
2、在父组件methods中声明函数响应自定义事件,接受子组件传递的参数 、
methods: {
//子组件触发自定义事件,接受学生传过来的值
get(stu) {
alert(stu);
}
}
3、在子组件中触发自定义事件
模板:
xxx(){
this.$emit("自定义事件名", 参数);
}
示例:
<button type="button" @click="shwoStu()">点击传递</button>
methods: {
shwoStu() {
// 在子组件通过出发自定义事件(同时传递参数)
this.$emit("aj", this.stu);
}
}
4、如果子组件要销毁自定义事件,可以通过下列方式销毁
clear_aj() {
//取消自定义事件
this.$off("aj");
}
6、全局消息总线
作用:一种组件间的通信方式,适用于‘任意组件间的通信’
使用步骤:
1、在main.js中安装消息总线
new Vue({
//将app组件,加载到容器中
render: h => h(App),
beforeCreate() {
//安装全局消息总线,$bus就是当前应用vm,$bus是变量名,可以任意指定
Vue.prototype.$bus=this;
}
}).$mount('#app')
2、组件通过消息总线接受数据
哪一个组件要通过消息总线接受数据,就在哪一个组件中绑定自定义事件,并且通过事件的回调函数接受数据
一般在mounted钩子函数中,向全局消息总线注册自定义事件,注册的语法是:
mounted:(){
this.$bus.$on('xxx自定义事件名',回调函数)
}
需要注意的是,注册的自定义事件名不能重名,所以一般在当前组件被销毁的钩子函数中会取消,在消息总线中注册的自定义事件
//当前组件释放时,也解绑注册的自定义事件名
beforeDestroy(){
this.$bus.$off("aj");
}
3、组件通过消息总线发送数据
stu.vue组件通过自定义事件,向school.vue提供数据
子组件发送数据
this.$bus.$emit("数据接收方注册的自定义事件","参数")
示例:
methods: {
shwoStu() {
// 在组件通过消息总线向其他组件传递数据
//不论是父子组件,还是平级组件,或者是多级组件,都可以传递
this.$bus.$emit("aj", this.stu);
}
}
组件间的传递参数
1、父向子传递参数:一般使用props接受即可
2、子向父转到参数:一般使用自定义事件或者消息总线
3、app--->mylist----->myitem :多级组件传递参数,一般建议使用消息总线
4、平级组件传递参数:也可以使用消息总线
第八章
全局消息总线的使用
消息的发布与订阅
vue的代理配置
slot插槽
vuex
1、全局消息总线
修改备忘录memo练习
1、在main.js中安装消息总线
beforeCreate() {
//安装全局消息总线,$bus就是当前应用vm,$bus是变量名,可以任意指定
Vue.prototype.$bus=this;
}
2、在app.vue中注册事件
//编写钩子函数,关联自定义事件,用于接受其他组件
mounted() {
//在总线中注册自定义事件,如果del触发了,就调用handleDel事件
this.$bus.$on("del", this.handleDel);
this.$bus.$on("state", this.handleState);
}, //编写解绑注册的事件
beforeDestroy() {
this.$bus.$off("del");
this.$bus.$off("state");
}
3、在myitem.vue中触发事件
<input type="checkbox" @click="changeState(todo.id)" />
changeState(id) {
//触发自定义事件,传递id
this.$bus.$emit("state", id);
}
2、消息发布与订阅
作用:用于任意组件间的数据传递
1、使用步骤
1、在vscode中安装组件 pubsub-js插件
npm i pubsub-js
接受消息
2、在需要接受消息的组件中导入 pubsub-js
a、import pubsub from "pubsub-js";
b、在methods中编写函数,响应自定义事件
getSchool("事件名称",传递过来的值){
alter(值)
}
c、在mounted钩子函数中订阅一个自定义事件
this.pid=pubsub.subscribe('自定义事件名称',回调函数)
//pid--它是订阅的pid,我们通过pid取消订阅
//回调函数是指在methods中声明的函数名称
d、在组件关闭时,取消订阅
beforeDestroy() {
//取消订阅
pubsub.unsubscribe(this.pid);
}
发布消息
3、在消息发送的组件中,执行操作
a、import pubsub from "pubsub-js";
b、通过pubsub发送消息,所有订阅了自定义事件的组件,都可以接受到数据
pubsub.publish('自定义事件名称',数据)
2、参数传递的方式
1、全局消总线
2、消息的订阅与发布
//全局消息总线更方便
3、vue服务器代理配置
要实现前后台交互,一般使用axios这个组件,在脚手架项目中一般通过npm在线安装即可
1、安装
npm i axios
2、在组件中引入
import axios from 'axios';
3、通过axios发送请求到后台,加载数据
axios.get('请求地址').then(res=>{
log(res.data)
})
跨域问题
access-Control-Allow-Origin:跨域问题
Access to XMLHttpRequest at 'http://localhost:8080/ajax?method=init' from origin 'http://192.168.17.159:8081' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
解决方案:
1、在后台通过cors过滤器即可解决跨域问题(最简单)
2、在前台vue.config.js文件中,配置代理服务器也可以解决跨域问题
a、 修改配置文件
devServer: {
proxy: 'http://localhost:8099/'
//proxy:代理
//当前台程序访问vue脚手架的默认8080端口时,
//代理服务器自动代理成8099的端口访问后台程序
//http://localhost:8099---这个端口号是后台服务器的端口号
}
b、在axios发送请求时,请求vue的默认8080端口
//此时,只需要请求vue默认的8080端口即可
//因为8080端口会自动被代理成8099端口访问后台
axios.get("http://localhost:8080/ajax", {
params: { method: "init" }
}).then(item => {
//请求成功时,执行的回调函数
this.list = item.data;
})
c、修改配置文件需要重新启动
备注
如果开启了前台代理服务器,那么请求地址就填前台默认8080端口
如果开启了后台代理服务器,那么请求地址还是填后台服务器地址
4、slot插槽
slot插槽:其实就是一个组件中的占位符,通过插槽可以将内容放在指定的区域
1、默认插槽
a、 在子组件可以声明一个默认插槽
<slot></slot>
b、在父组件中使用子组件,在子组件两个标签之间的内容就是赋值给子组件默认插槽的内容
<子组件>
这里的内容,就是赋值给子组件默认插槽中的内容
</子组件>
示例:
//在app.vue中,向同一个组件中放入不同的控件
<slott title="美食">
<img src="index.jpg" alt srcset />
</slott>
<slott title="书籍" :books="books">
<ul>
<li v-for="(item,index) in books" :key="index">{{item}}</li>
</ul>
</slott>
<slott title="电影">
<video controls loop src="./assets/11.mp4"></video>
</slott>
//在slott.vue中放入插槽
<h3>{{title}}档口</h3>
<slot>
</slot>
问题
一个组件只能默认只能有一个插槽,如果需要使用多个插槽,我们可以使用“具名插槽”
2、具名插槽
【具名插槽】:在子组件声明插槽时,给每一个插槽之地名称。在父组件中使用子组件时,就明确指定是给子组件的哪一个插槽赋值
a、在子组件中声明插槽
<slot name=center></slot>
<slot name=footer></slot>
b、在父组件中给子组件的指定插槽赋值
<子组件>
<div slot="center">xxx</div>
<a slot="footer">xxx</a>
</子组件>
示例:
1、在slot.vuue中声明插槽的名字
<div class="mydiv">
<h3>{{title}}档口</h3>
<slot name="conter"></slot>
<slot name="footer"></slot>
</div>
2、在app.vue中指定给哪一个插槽赋值
<slott title="美食">
<img slot="conter" src="index.jpg" alt srcset />
<ul slot="footer">
<li v-for="(item,index) in foods" :key="index">
<a href="#">{{item}}</a>
</li>
</ul>
</slott>
<slott title="书籍">
<ul slot="conter">
<li v-for="(item,index) in books" :key="index">{{item}}</li>
</ul>
</slott>
<slott title="电影">
<video slot="conter" controls loop src="718.mp4"></video>
<ul slot="footer">
<li v-for="(item,index) in films" :key="index">
<a href="#">{{item}}</a>
</li>
</ul>
</slott>
5、vuex
作用:是专门在vue中实现集中式数据(状态)管理的vue插件,对vue应用中多个组件的共享数据进行集中式的管理(读、写),也是一种组件间通信的方式,且适用任意组件间的通信
主要作用:将多个组件都要使用的数据,进行集中管理
使用场景:
1、多个组件都要使用同一条数据
2、多个组件会修改同一条数据的状态
当数据存储在vuex中,所有组件都可以直接访问这里面的数据,并且允许直接操作这些数据
第一个示例:
1、安装vuex
npm i vuex ---->vuex4.0--->vue3.0
npm i vuex@3 --->vuex3.0---->vue2.0
2、main.js引入vuex
//导入
import vuex from 'vuex'
//使用
Vue.use(vuex)
3、测试vuex是否成功
a、在main.js中编写一个变量
new Vue({
render: h => h(App),
store: "测试",//变量
}
}).$mount('#app')
b、随便打开一个vue文件
mounted() {
console.log(this);//输出这个实例,如果有store这个变量即为成功
}
第九章
vuex的使用
route路由的使用
阶段1:计数器的示例
通过一个计数器的示例,演示在vuex中可以包含哪些属性,以及如何直接操作vuex的数据
v-model.number:指定绑定数据类型
步骤:
1、搭建计算器应用的基本结构,暂时与vuex没有关系
目前:sum这个变量用于统计总和,它存在当前Counter组件中,只有Counter组件才能使用,其他组件无法直接使用
2、在main.js文件导入vuex,并且使用vuex插件
import Vuex from 'vuex'
Vue.use(Vuex);
3、在src目录下,创建一个store目录,在目录中包含一个index.js文件,该方法中包含vuex存放的内容
4、在store目录下的index.js文件中需要包含下列三个配置:
1、actions------------它用于包含vuex中的事件
2、mutations----------它用于操作state中的数据
3、state--------------它用于在vuex中指定全局共享数据
//引Vue
import Vue from 'vue'
//引入vuex
import Vuex from 'vuex'
//声明三个对象
//它用于指定vuex中的所有事件,这些事件所有组件都可以直接访问
const actions={
};
//mutations声明的函数,可以直接操作state存放的全局数据,所有组件可以直接访问这里的函数
const mutations={
//这里可以直接state中的数据
};
//state中声明的数据,所有组件都可以直接访问
const state ={
};
//先使用Vuex,然后再通过它创建Store实例
Vue.use(Vuex);
//创建store实例,实例中包含的对象,所有组件都可以直接访问
const store = new Vuex.Store({
actions,mutations,state
});
//将store实例对外暴露
export default store;
5、在main.js文件中导入store对象,并且将store存放到vuex中,即可所有组件全局共享
//导入store
import store from './store/index'
new Vue({
render: h => h(App),
//将数据存放到vuex中
store:store
}).$mount('#app')
6、使用vuex组件
store目录下的index.js文件中可以包含三个对象
actions--------用于指定所有组件共享的函数
mutations------用于指定函数操作state对象中存放的数据
state----------用于存放全局所有组件共享的数据
如果希望所有组件都可以直接共享访问的数据放在store/index.js中的state部分即可
a、访问 vuex中state对象中存放的数据,可以采用如下方式
{{$store.state.属性名}}
//当使用了vuex以后,每一个组件都存在一个$store实例,通过可以直接访问vuex中声明的函数,以及存放的数据
b、在组件中要访问 index.js文件中actions声明的函数,需要通过如下访问
this.$store.dispatch("actions中声明的函数名",要传递的参数);
注意:
@@@@@Actions中声明的函数不能直接操作state中的数据,需要通过Mutations的函数进行过渡
组件--->actions--->mutations--->state
在组件中通过下列方式可以直接访问actions中的函数
this.$store.dispatch("actions中的函数",参数);
actions的函数中访问mutations中的函数
//在actions中声明的函数名称,名称全部小写
jia(context,参数){
context.commit("mutations中的函数名",参数);
}
@@@@@@在mutations中只需要编写下列代码即可修改state中的数据
const mutations={
//这里可以直接修改state中的数据
//在mutations中声明的函数名称,名称全部大写
//参数1:即为state对象
//参数2:即为传递进来的具体参数
JIA(state,value){
state.sum +=value;
}
};
1、标准流程:
组件—>actions—>mutations—>state
1、在counter.vue中调用index.js函数
<h1>计算结果:{{ $store.state.sum }}</h1>
<button @click="add()">加【{{ n }}】</button>
//触发
add() {//+
this.$store.dispatch("jia", this.n);
}
2、index.js中的流程
a、进入到jia()事件---->actions
jia(context, val) {//测试事件
//提交JIA()函数处理
context.commit("JIA", val);
}
b、进到JIA()函数处理数据---->mutations
JIA(state, val) {
state.sum += val;
}
c、state的数据发生改变
const state = {
sum: 0, //计算结果
}
2、简化流程
组件—>mutations—>state
//组件不需要做逻辑判断,则可以直接访问函数来修改数据
//如果需要逻辑判断,则必须先进到逻辑判断中
add(){
直接访问JIA()函数
this.$store.commit("JIA", this.n);
}
3、获取语法
/在组件中从store对象中的state中获得属性值的标准语法
{{$store.state.属性名}}
/在组件中访问store中Actions对象的中的函数标准语法:
this.$store.dispatch("函数名",参数);
/在组件中访问store中mutations对象的中的函数标准语法:
this.$store.commit("函数名",参数);
4、简化state中属性的方法
@@@1、每一次访问state中的属性,如果采用下列写法比较繁琐:{{$store.state.属性名}}
简化方式:我们可以将state中的属性,映射成当前组件的计算属性
步骤:
1、在组件中引入mapState
mapState的作用是将index.js中的state属性映射成计算属性
import { mapState } from 'vuex';
2、将index.js中的state属性映射成计算属性
@@@@方式1
computed:{
...mapState({sum:'sum',id:'id',name:'name',score:'score'})
}
@@@@方式2
computed:{
...mapState(['sum','id','name','score'])
}
3、取值时使用别名即可
编号:{{id}} <BR/>
姓名:{{name}}<BR/>
成绩:{{score}}<BR/>
5、简化Actions中事件的调用
之前在组件要调用actions中的函数,格式如下: this.$store.dispatch("evenAdd",this.n);
简化步骤:
1、在组件导入mapActions
import { mapState,mapActions } from 'vuex';
2、在methods中进行映射
方式1:
methods:{
...mapActions({evenAdd:'evenAdd'})
}
方式2:
methods:{
...mapActions(['evenAdd'])
}
3、使用简化后事件
<input type="button" value="当n的值为偶数再加" @click="evenAdd(n)">
6、简化Mutations中函数的调用
之前在组件要调用mutations中的函数,格式如下:
this.$store.commit("JIA",this.n);
简化步骤:
1、在组件导入mapMutations
import { mapState,mapActions,mapMutations } from 'vuex';
2、在methods中进行映射
方式1:
methods:{
...mapMutations({JIA:'JIA',JIAN:'JIAN'}),
}
方式2:
methods:{
...mapMutations(['JIA','JIAN']),
}
3、使用简化后函数
<input type="button" value="加" @click="JIA(n)">
<input type="button" value="减" @click="JIAN(n)">
问题:
为了实现数据共享访问,我们使用了vuex,actions,mutations,state都在同一个文件中编写,当数据很多时,代码会变的比较混乱,为了解决该问题,我们可以在index.js文件中使用模块化的组件
阶段2:模块化+命名空间
@@@@@@模块化开发的目的:让代码更好维护
步骤:
1、在 index.js文件中,创建多个模块,一个模块对应的一个组件的配置
@@@注意:每一个模块必须要指定:namespaced -------命名空间
@@@每一个模块可以包含自己的 actions,mutations,state
//新建模块
const counter = {
namespaced: true,
actions: {
//如果n的值为偶数,才执行加法
evenAdd(context, n) {
if (n % 2 == 0) {
context.commit("EVENADD", n);
}
}
},
mutations: {
JIA(state, value) {
state.sum += value;
},
JIAN(state, value) {
state.sum -= value;
},
EVENADD(state, value) {
state.sum += value;
}
},
state: {
sum: 5, //保存总和
}
};
const person = {
namespaced: true,
state: {
id: 1,//编号
name: "张三",//姓名
score: 99,//分数
}
};
2、在index.js的store对象中加载模块
//创建store实例,实例中包含的对象,所有组件都可以直接访问
const store = new Vuex.Store({
modules:{
person,counter
}
});
3、在组件中映射时,要分别指定:actions,mutations,state是从哪一个模块中加载
@@@@@@@@模块化开发,一个模块就是一个独立的 js文件
1、先创建counter.js,person.js
2、在index.js文件中引入
import counter from './counter'
import person from './person'
3、使用模块
const store = new Vuex.Store({
modules:{
person,counter
}
});