【Vue 2.x】学习vue之二组件

发布于:2024-05-04 ⋅ 阅读:(23) ⋅ 点赞:(0)

在这里插入图片描述

文章目录

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代码)进行模块化

image-20230516200318145

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程序

image-20230517174220127

main.js---------它是vue的入口js文件,vue的实例是在此文件中创建的,要导入各种插件,也需要在改文件中导入

image-20230517175621085

app.vue是一个入口组件,其他组件都要通过它进行加载

image-20230517180340211

image-20230517180509165

重点关注文件
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、脚手架

image-20230518163857299

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、待办事项的选择	

image-20230518221005902

在这里插入图片描述

父组件向子组件传递参数,子组件可以用props接受

但是平级不能使用props接受传递过来的参数
实现头部功能

image-20230518230945734

如果是多个组件都要操作的数据,一般可以在父组件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中,所有组件都可以直接访问这里面的数据,并且允许直接操作这些数据

image-20230522185348801

第一个示例:
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这个变量即为成功
      }

image-20230522192133138

第九章

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, //计算结果
            }

image-20230523104354730

image-20230523105534825

2、简化流程

​ 组件—>mutations—>state

//组件不需要做逻辑判断,则可以直接访问函数来修改数据
//如果需要逻辑判断,则必须先进到逻辑判断中
	add(){
		直接访问JIA()函数
		  this.$store.commit("JIA", this.n);
	}

image-20230523110618282

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中进行映射
	方式1methods:{
			...mapActions({evenAdd:'evenAdd'})
		}
	方式2methods:{
			...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中进行映射

	方式1methods:{
			...mapMutations({JIA:'JIA',JIAN:'JIAN'}),
		}
	方式2methods:{
			...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
	    }
	});


网站公告

今日签到

点亮在社区的每一天
去签到