前端Vue框架系列—— 学习笔记总结Day02

news2024/11/20 12:41:25

❤ 作者主页:欢迎来到我的技术博客😎
❀ 个人介绍:大家好,本人热衷于Java后端开发,欢迎来交流学习哦!( ̄▽ ̄)~*
🍊 如果文章对您有帮助,记得关注点赞收藏评论⭐️⭐️⭐️
📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉

文章目录

  • 第一章 Vue组件化编程
    • 1.1 模块与组件、模块化与组件化
      • 1.1.1 模块
      • 1.1.2 组件
      • 1.1.3 模块化
      • 1.1.4 组件化
    • 1.2 非单文件组件
      • 1.2.1 基本使用
      • 1.2.2 几个注意点
      • 1.2.3 组件的嵌套
      • 1.2.4 VueComponent
      • 1.2.5 一个重要的内置关系
    • 1.3 单文件组件
  • 第二章 使用Vue脚手架
    • 2.1 初始化脚手架
      • 2.1.1 说明
      • 2.1.2 具体步骤
      • 2.1.3 分析脚手架结构
      • 2.1.4 render函数
      • 2.1.5 修改默认配置
    • 2.2 ref属性
    • 2.3 props配置
    • 2.4 mixin混入(合)
    • 2.5 plugin插件
    • 2.6 scoped样式
    • 2.7 TodoList案例
    • 2.8 浏览器本地存储
    • 2.9 TodoList_本地存储
    • 2.10 组件自定义事件
      • 2.10.1 绑定
      • 2.10.2 解绑
    • 2.11 TodoList_自定义事件
    • 2.12 全局事件总线(GlobalEventBus)
    • 2.13 TodoList_事件总线
    • 2.14 消息订阅与发布(pubsub)
    • 2.15 使用消息的订阅与发布优化Todo-List
    • 2.16 nextTick(回调函数)
    • 2.17 过度与动画

第一章 Vue组件化编程

1.1 模块与组件、模块化与组件化

在这里插入图片描述


在这里插入图片描述


1.1.1 模块

  1. 理解: 向外提供特定功能的 js 程序, 一般就是一个 js 文件
  2. 为什么: js 文件很多很复杂
  3. 作用: 复用 js, 简化 js 的编写, 提高 js 运行效率

1.1.2 组件

  1. 理解: 用来实现局部(特定)功能效果的代码集合(html/css/js/image……)
  2. 为什么: 一个界面的功能很复杂
  3. 作用: 复用编码, 简化项目编码, 提高运行效率

1.1.3 模块化

当应用中的 js 都以模块来编写的, 那这个应用就是一个模块化的应用。

1.1.4 组件化

当应用中的功能都是多组件的方式来编写的, 那这个应用就是一个组件化的应用。


1.2 非单文件组件

1.2.1 基本使用

代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>基本使用</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>

		<!-- 准备好一个容器-->
		<div id="root">
			<hello></hello>
			<hr>
			<h1>{{msg}}</h1>
			<hr>
			<!-- 第三步:编写组件标签 -->
			<school></school>
			<hr>
			<!-- 第三步:编写组件标签 -->
			<student></student>
		</div>

		<div id="root2">
			<hello></hello>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false

		//第一步:创建school组件
		const school = Vue.extend({
			template:`
				<div class="demo">
					<h2>学校名称:{{schoolName}}</h2>
					<h2>学校地址:{{address}}</h2>
					<button @click="showName">点我提示学校名</button>	
				</div>
			`,
			// el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。
			data(){
				return {
					schoolName:'光明学校',
					address:'广州'
				}
			},
			methods: {
				showName(){
					alert(this.schoolName)
				}
			},
		})

		//第一步:创建student组件
		const student = Vue.extend({
			template:`
				<div>
					<h2>学生姓名:{{studentName}}</h2>
					<h2>学生年龄:{{age}}</h2>
				</div>
			`,
			data(){
				return {
					studentName:'张三',
					age:18
				}
			}
		})
		
		//第一步:创建hello组件
		const hello = Vue.extend({
			template:`
				<div>	
					<h2>你好啊!{{name}}</h2>
				</div>
			`,
			data(){
				return {
					name:'Tom'
				}
			}
		})
		
		//第二步:全局注册组件
		Vue.component('hello',hello)

		//创建vm
		new Vue({
			el:'#root',
			data:{
				msg:'你好啊!'
			},
			//第二步:注册组件(局部注册)
			components:{
				school,
				student
			}
		})

		new Vue({
			el:'#root2',
		})
	</script>
</html>

效果:
在这里插入图片描述


总结:

  • Vue中使用组件的三大步骤:

    1. 定义组件(创建组件)
    2. 注册组件
    3. 使用组件(写组件标签)
  • 如何定义一个组件:?
    使用 Vue.extend(options) 创建,其中 optionsnew Vue(options) 时传入的那个 options 几乎一样,但也有点区别:

    1. el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
    2. data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。

    备注:使用template可以配置组件结构。

  • 如何注册组件?

    1. 局部注册:靠 new Vue的时候传入 components 选项
    2. 全局注册:靠 Vue.component('组件名',组件)
  • 编写组件标签:
    例如: <school></school>


1.2.2 几个注意点

代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>几个注意点</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h1>{{msg}}</h1>
			<school></school>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false
		
		//定义组件
		const s = Vue.extend({
			name:'zhangsan',
			template:`
				<div>
					<h2>学校名称:{{name}}</h2>	
					<h2>学校地址:{{address}}</h2>	
				</div>
			`,
			data(){
				return {
					name:'光明学校',
					address:'广州'
				}
			}
		})

		new Vue({
			el:'#root',
			data:{
				msg:'欢迎学习Vue!'
			},
			components:{
				school:s
			}
		})
	</script>
</html>

效果:
在这里插入图片描述


总结:

几个注意点:

  1. 关于组件名

    • 一个单词组成:

      • 第一种写法(首字母小写):school
      • 第二种写法(首字母大写):School
    • 多个单词组成:

      • 第一种写法(kebab-case命名):my-school
      • 第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
    • 备注:

      • 组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
      • 可以使用name配置项指定组件在开发者工具中呈现的名字。
  2. 关于组件标签

    • 第一种写法:<school></school>
    • 第二种写法:<school/>
    • 备注:不用使用脚手架时,<school/> 会导致后续组件不能渲染。
  3. 一个简写方式

    • const school = Vue.extend(options) 可简写为:const school = options

1.2.3 组件的嵌套

代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>组件的嵌套</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		//定义student组件
		const student = Vue.extend({
			name:'student',
			template:`
				<div>
					<h2>学生姓名:{{name}}</h2>	
					<h2>学生年龄:{{age}}</h2>	
				</div>
			`,
			data(){
				return {
					name:'张三',
					age:18
				}
			}
		})
		
		//定义school组件
		const school = Vue.extend({
			name:'school',
			template:`
				<div>
					<h2>学校名称:{{name}}</h2>	
					<h2>学校地址:{{address}}</h2>	
					<student></student>
				</div>
			`,
			data(){
				return {
					name:'光明学校',
					address:'广州'
				}
			},
			//注册组件(局部)
			components:{
				student
			}
		})

		//定义hello组件
		const hello = Vue.extend({
			template:`<h1>{{msg}}</h1>`,
			data(){
				return {
					msg:'欢迎习Vue组件!'
				}
			}
		})
		
		//定义app组件
		const app = Vue.extend({
			template:`
				<div>	
					<hello></hello>
					<school></school>
				</div>
			`,
			components:{
				school,
				hello
			}
		})

		//创建vm
		new Vue({
			template:'<app></app>',
			el:'#root',
			//注册组件(局部)
			components:{app}
		})
	</script>
</html>

效果:

在这里插入图片描述


1.2.4 VueComponent

代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>VueComponent</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<school></school>
			<hello></hello>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false
		
		//定义school组件
		const school = Vue.extend({
			name:'school',
			template:`
				<div>
					<h2>学校名称:{{name}}</h2>	
					<h2>学校地址:{{address}}</h2>	
					<button @click="showName">点我提示学校名</button>
				</div>
			`,
			data(){
				return {
					name:'光明学校',
					address:'广州'
				}
			},
			methods: {
				showName(){
					console.log('showName',this)
				}
			},
		})

		const test = Vue.extend({
			template:`<span>张三</span>`
		})

		//定义hello组件
		const hello = Vue.extend({
			template:`
				<div>
					<h2>{{msg}}</h2>
					<test></test>	
				</div>
			`,
			data(){
				return {
					msg:'你好啊!'
				}
			},
			components:{test}
		})


		// console.log('@',school)
		// console.log('#',hello)

		//创建vm
		const vm = new Vue({
			el:'#root',
			components:{school,hello}
		})
	</script>
</html>

效果:
在这里插入图片描述


总结:

关于 VueComponent

  1. school组件本质是一个名为 VueComponent 的构造函数,且不是程序员定义的,是 Vue.extend 生成的。

  2. 我们只需要写 <school/><school></school>,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)

  3. 特别注意:每次调用 Vue.extend,返回的都是一个全新的VueComponent

  4. 关于this指向:

    1. 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
    2. new Vue(options) 配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
  5. VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。

    • Vue的实例对象,以后简称vm。

1.2.5 一个重要的内置关系

代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>一个重要的内置关系</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<school></school>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		Vue.prototype.x = 99

		//定义school组件
		const school = Vue.extend({
			name:'school',
			template:`
				<div>
					<h2>学校名称:{{name}}</h2>	
					<h2>学校地址:{{address}}</h2>	
					<button @click="showX">点我输出x</button>
				</div>
			`,
			data(){
				return {
					name:'光明学校',
					address:'广州'
				}
			},
			methods: {
				showX(){
					console.log(this.x)
				}
			},
		})

		//创建一个vm
		const vm = new Vue({
			el:'#root',
			data:{
				msg:'你好'
			},
			components:{school}
		})

		
		//定义一个构造函数
		/* function Demo(){
			this.a = 1
			this.b = 2
		}
		//创建一个Demo的实例对象
		const d = new Demo()

		console.log(Demo.prototype) //显示原型属性

		console.log(d.__proto__) //隐式原型属性

		console.log(Demo.prototype === d.__proto__)

		//程序员通过显示原型属性操作原型对象,追加一个x属性,值为99
		Demo.prototype.x = 99

		console.log('@',d) */

	</script>
</html>

效果:
在这里插入图片描述


总结:

  1. 一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
  2. 为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。

1.3 单文件组件

  • School.vue

    <template>
        <div id='Demo'>
            <h2>学校名称:{{name}}</h2>
            <h2>学校地址:{{address}}</h2>
            <button @click="showName">点我提示学校名</button>
        </div>
    </template>
    
    <script>
        export default {
            name:'School',
            data() {
                return {
                    name:'光明学校',
                    address:'广州'
                }
            },
            methods: {
                showName(){
                    alert(this.name)
                }
            },
        }
    </script>
    
    <style>
        #Demo{
            background: orange;
        }
    </style>
    
    
  • Student.vue:

    <template>
        <div>
            <h2>学生姓名:{{name}}</h2>
            <h2>学生年龄:{{age}}</h2>
        </div>
    </template>
    
    <script>
        export default {
            name:'Student',
            data() {
                return {
                    name:'张三',
                    age:20
                }
            },
        }
    </script>
    
    
  • App.vue

    <template>
        <div>
            <School></School>
            <Student></Student>
        </div>
    </template>
    
    <script>
        import School from './School.vue'
        import Student from './Student.vue'
    
        export default {
            name:'App',
            components:{
                School,
                Student
            }
        }
    </script>
    
    
  • main.js

    import App from './App.vue'
    
    new Vue({
        template:`<App></App>`,
        el:'#root',
        components:{App}
    })
    
  • index.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>单文件组件练习</title>
    </head>
    <body>
        <div id="root"></div>
        <script src="../../js/vue.js"></script>
        <script src="./main.js"></script>
    </body>
    </html>
    

第二章 使用Vue脚手架

2.1 初始化脚手架

2.1.1 说明

  1. Vue 脚手架是 Vue 官方提供的标准化开发工具(开发平台)。
  2. 最新的版本是 4.x。
  3. 文档: https://cli.vuejs.org/zh/

2.1.2 具体步骤

  1. 如果下载缓慢请配置 npm 淘宝镜像:npm config set registry http://registry.npm.taobao.org
  2. 全局安装@vue/cli:npm install -g @vue/cli
  3. 切换到你要创建项目的目录,然后使用命令创建项目:vue create xxxx
  4. 选择使用vue的版本
  5. 启动项目:npm run serve
  6. 暂停项目:Ctrl+C

备注:
Vue 脚手架隐藏了所有 webpack 相关的配置,若想查看具体的 webpakc 配置,请执行:vue inspect > output.js


2.1.3 分析脚手架结构

脚手架文件结构:

.文件目录
├── node_modules 
├── public
│   ├── favicon.ico: 页签图标
│   └── index.html: 主页面
├── src
│   ├── assets: 存放静态资源
│   │   └── logo.png
│   │── component: 存放组件
│   │   └── HelloWorld.vue
│   │── App.vue: 汇总所有组件
│   └── main.js: 入口文件
├── .gitignore: git版本管制忽略的配置
├── babel.config.js: babel的配置文件
├── package.json: 应用包配置文件 
├── README.md: 应用描述文件
└── package-lock.json: 包版本控制文件

2.1.4 render函数

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
    el:'#app',
    // 简写形式
	render: h => h(App),
    // 完整形式
	// render(createElement){
	//     return createElement(App)
	// }
})

总结:

关于不同版本的函数:

  1. vue.jsvue.runtime.xxx.js 的区别:

    1. vue.js 是完整版的 Vue,包含:核心功能+模板解析器
    2. vue.runtime.xxx.js 是运行版的 Vue,只包含核心功能,没有模板解析器
  2. 因为 vue.runtime.xxx.js 没有模板解析器,所以不能使用 template 配置项,需要使用 render 函数接收到的 createElement 函数去指定具体内容


2.1.5 修改默认配置

  • vue.config.js 是一个可选的配置文件,如果项目的(和 package.json 同级的)根目录中存在这个文件,那么它会被 @vue/cli-service 自动加载
  • 使用 vue.config.js可以对脚手架进行个性化定制,详情见:https://cli.vuejs.org/zh
module.exports = {
    pages: {
        index: {
            // 入口
            entry: 'src/index/main.js'
        }
    },
  // 关闭语法检查
  lineOnSave:false
}

2.2 ref属性

代码:

  • School.vue

    <template>
    	<div class="school">
    		<h2>学校名称:{{name}}</h2>
    		<h2>学校地址:{{address}}</h2>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'School',
    		data() {
    			return {
    				name:'光明学校',
    				address:'广州'
    			}
    		},
    	}
    </script>
    
    <style>
    	.school{
    		background-color: gray;
    	}
    </style>
    
  • App.vue

    <template>
    	<div>
    		<h1 v-text="msg" ref="title" id="msg"></h1>
    		<button ref="btn" @click="showDOM">点我输出上方的DOM元素</button>
    		<School ref="sch"/>
    	</div>
    </template>
    
    <script>
    	//引入School组件
    	import School from './components/School'
    
    	export default {
    		name:'App',
    
    		components:{
    			School
    		},
    
    		data() {
    			return {
    				msg:'欢迎学习Vue!'
    			}
    		},
    
    		methods: {
    			showDOM(){
    				console.log(document.getElementById("msg")) //传统中用于获取指定id的DOM元素
    				console.log(this.$refs.title) //真实DOM元素
    				console.log(this.$refs.btn) //真实DOM元素
    				console.log(this.$refs.sch) //School组件的实例对象(vc)
    			}
    		},
    	}
    </script>
    

效果:
在这里插入图片描述


总结:

ref属性:

  1. 被用来给元素或子组件注册引用信息(id的替代者:document.getElementById()
  2. 应用在 html标签 上获取的是 真实DOM元素 ,应用在 组件 标签上是 组件实例对象(vc)
  3. 使用方式:
    1. 打标识:<h1 ref="xxx">.....</h1><School ref="xxx"></School>
    2. 获取:this.$refs.xxx

2.3 props配置

代码:

  • Student.vue

    <template>
    	<div>
    		<h1>{{msg}}</h1>
    		<h2>学生姓名:{{name}}</h2>
    		<h2>学生性别:{{sex}}</h2>
    		<h2>学生年龄:{{myAge+1}}</h2>
    		<button @click="updateAge">尝试修改收到的年龄</button>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'Student',
    		data() {
    			console.log(this)
    			return {
    				msg:'我在学Vue!',
    				myAge:this.age
    			}
    		},
    		methods: {
    			updateAge(){
    				this.myAge++
    			}
    		},
    		//简单声明接收
    		// props:['name','age','sex'] 
    
    		//接收的同时对数据进行类型限制
    		/* props:{
    			name:String,
    			age:Number,
    			sex:String
    		} */
    
    		//接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
    		props:{
    			name:{
    				type:String, //name的类型是字符串
    				required:true, //name是必要的
    			},
    			age:{
    				type:Number,
    				default:99 //默认值
    			},
    			sex:{
    				type:String,
    				required:true
    			}
    		}
    	}
    </script>
    
  • App.vue

    <template>
    	<div>
    		<Student name="李四" sex="女" :age="18"/>
    	</div>
    </template>
    
    <script>
    	import Student from './components/Student'
    
    	export default {
    		name:'App',
    		components:{Student}
    	}
    </script>
    

效果:
在这里插入图片描述


总结:
props配置项:

  1. 功能:让组件接收外部传过来的数据

  2. 传递数据:<Demo name="xxx"/>

  3. 接收数据:

    1. 第一种方式(只接收):props:['name']

    2. 第二种方式(限制类型):props:{name:String}

    3. 第三种方式(限制类型、限制必要性、指定默认值):

      props:{
      	name:{
      	type:String, //类型
      	required:true, //必要性
      	default:'老王' //默认值
      	}
      }
      

    备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。


2.4 mixin混入(合)

1. 局部混入
代码:

  • School.vue

    <template>
    	<div>
    		<h2 @click="showName">学校名称:{{name}}</h2>
    		<h2>学校地址:{{address}}</h2>
    	</div>
    </template>
    
    <script>
    	//引入一个hunhe
    	import {hunhe,hunhe2} from '../mixin'
    
    	export default {
    		name:'School',
    		data() {
    			return {
    				name:'光明学校',
    				address:'广州',
    				x:666
    			}
    		},
    		mixins:[hunhe,hunhe2],
    	}
    </script>
    
  • Student.vue

    <template>
    	<div>
    		<h2 @click="showName">学生姓名:{{name}}</h2>
    		<h2>学生性别:{{sex}}</h2>
    	</div>
    </template>
    
    <script>
    	import {hunhe,hunhe2} from '../mixin'
    
    	export default {
    		name:'Student',
    		data() {
    			return {
    				name:'张三',
    				sex:'男'
    			}
    		},
    		mixins:[hunhe,hunhe2]
    	}
    </script>
    
  • mixin.js

    export const hunhe = {
    	methods: {
    		showName(){
    			alert(this.name)
    		}
    	},
    	mounted() {
    		console.log('你好啊!')
    	},
    }
    export const hunhe2 = {
    	data() {
    		return {
    			x:100,
    			y:200
    		}
    	},
    }
    
    

效果:
在这里插入图片描述


2. 全局混入

代码:

  • School.vue

    <template>
    	<div>
    		<h2 @click="showName">学校名称:{{name}}</h2>
    		<h2>学校地址:{{address}}</h2>
    	</div>
    </template>
    
    <script>
    	//引入一个hunhe
    	// import {hunhe,hunhe2} from '../mixin'
    
    	export default {
    		name:'School',
    		data() {
    			return {
    				name:'光明学校',
    				address:'广州',
    				x:666
    			}
    		},
    		// mixins:[hunhe,hunhe2],
    	}
    </script>
    
  • Student.vue

    <template>
    	<div>
    		<h2 @click="showName">学生姓名:{{name}}</h2>
    		<h2>学生性别:{{sex}}</h2>
    	</div>
    </template>
    
    <script>
    	// import {hunhe,hunhe2} from '../mixin'
    
    	export default {
    		name:'Student',
    		data() {
    			return {
    				name:'张三',
    				sex:'男'
    			}
    		},
    		// mixins:[hunhe,hunhe2]
    	}
    </script>
    
  • main.js

    //引入Vue
    import Vue from 'vue'
    //引入App
    import App from './App.vue'
    import {hunhe,hunhe2} from './mixin'
    //关闭Vue的生产提示
    Vue.config.productionTip = false
    
    Vue.mixin(hunhe)
    Vue.mixin(hunhe2)
    
    
    //创建vm
    new Vue({
    	el:'#app',
    	render: h => h(App)
    })
    

效果:
在这里插入图片描述


总结:

  1. 功能:可以把多个组件共用的配置提取成一个混入对象,实现组件功能的复用。

  2. 使用方式:

    第一步定义混合:

    export const xxx = {
        data() {
        
        },
        
        methods: {
        
        }
        ....
    }
    

    第二步使用混入:

    ​ 全局混入:Vue.mixin(xxx)
    ​ 局部混入:mixins:['xxx']

  3. mixin的优点:

    • 复用组件间的共同行为和属性
    • 避免重复代码
    • 易维护
  4. 注意事项:

    • mixin对象中的方法和数据会与组件自身产生冲突,需要避免名称重复
    • mixin会影响整个组件树,应谨慎使用全局mixin
    • 过多mixin会增加组件的复杂度

2.5 plugin插件

  • src/components/School.vue

    <template>
    	<div>
    		<h2>学校名称:{{name | mySlice}}</h2>
    		<h2>学校地址:{{address}}</h2>
    		<button @click="test">点我测试一个hello方法</button>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'School',
    		data() {
    			return {
    				name:'光明学校',
    				address:'广州',
    			}
    		},
    		methods: {
    			test(){
    				this.hello()
    			}
    		},
    	}
    </script>
    
  • src/components/Student.vue

    <template>
    	<div>
    		<h2>学生姓名:{{name}}</h2>
    		<h2>学生性别:{{sex}}</h2>
    		<input type="text" v-fbind:value="name">
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'Student',
    		data() {
    			return {
    				name:'张三',
    				sex:'男'
    			}
    			
    		},
    	}
    </script>
    
  • src/plugin.js

    export default {
    	install(Vue,x,y,z){
    		console.log(x,y,z)
    		//全局过滤器
    		Vue.filter('mySlice',function(value){
    			return value.slice(0,4)
    		})
    
    		//定义全局指令
    		Vue.directive('fbind',{
    			//指令与元素成功绑定时(一上来)
    			bind(element,binding){
    				element.value = binding.value
    			},
    			//指令所在元素被插入页面时
    			inserted(element,binding){
    				element.focus()
    			},
    			//指令所在的模板被重新解析时
    			update(element,binding){
    				element.value = binding.value
    			}
    		})
    
    		//定义混入
    		Vue.mixin({
    			data() {
    				return {
    					x:100,
    					y:200
    				}
    			},
    		})
    
    		//给Vue原型上添加一个方法(vm和vc就都能用了)
    		Vue.prototype.hello = ()=>{alert('你好啊')}
    	}
    }
    
  • src/main.js

    //引入Vue
    import Vue from 'vue'
    //引入App
    import App from './App.vue'
    //引入插件
    import plugins from './plugins'
    //关闭Vue的生产提示
    Vue.config.productionTip = false
    
    //应用(使用)插件
    Vue.use(plugins,1,2,3)
    //创建vm
    new Vue({
    	el:'#app',
    	render: h => h(App)
    })
    

效果:
在这里插入图片描述


总结:

  1. 功能:用于增强Vue

  2. 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。

  3. 定义插件:

    对象.install = function (Vue, options) {
        // 1. 添加全局过滤器
        Vue.filter(....)
    
        // 2. 添加全局指令
        Vue.directive(....)
    
        // 3. 配置全局混入(合)
        Vue.mixin(....)
    
        // 4. 添加实例方法
        Vue.prototype.$myMethod = function () {...}
        Vue.prototype.$myProperty = xxxx
    }
    
  4. 使用插件:Vue.use()


2.6 scoped样式

  • src/components/Student.vue

    <template>
    	<div class="demo">
    		<h2 class="title">学校名称:{{name}}</h2>
    		<h2>学校地址:{{address}}</h2>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'School',
    		data() {
    			return {
    				name:'光明学校',
    				address:'广州',
    			}
    		}
    	}
    </script>
    
    <style scoped>
    	.demo{
    		background-color: skyblue;
    	}
    </style>
    
  • src/components/School.vue

    <template>
    	<div class="demo">
    		<h2 class="title">学生姓名:{{name}}</h2>
    		<h2 class="sex">学生性别:{{sex}}</h2>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'Student',
    		data() {
    			return {
    				name:'张三',
    				sex:'男'
    			}
    		}
    	}
    </script>
    
    <style lang="less" scoped>
    	.demo{
    		background-color: pink;
    		.sex{
    			font-size: 40px;
    		}
    	}
    </style>
    
  • App.vue

    <template>
    	<div>
    		<h1 class="title">你好啊</h1>
    		<School/>
    		<Student/>
    	</div>
    </template>
    
    <script>
    	import Student from './components/Student'
    	import School from './components/School'
    
    	export default {
    		name:'App',
    		components:{School,Student}
    	}
    </script>
    
    <style scoped>
    	.title{
    		color: red;
    	}
    </style>
    
    

效果:
在这里插入图片描述


总结:

在传统的CSS中,样式规则是全局的,会对整个页面中所有匹配的元素生效。这可能导致样式冲突和命名空间污染的问题。

为了解决这些问题,HTML5中引入了 scoped 样式。当在 <style>标签中添加 scoped 属性时,样式规则只会应用于当前组件或元素及其子元素,而不会泄漏到其他组件或元素中。

  1. 定义:scoped 样式是一种用于指定样式仅应用于当前组件或元素的CSS样式作用域。
  2. 作用:让样式在局部生效,防止冲突。
  3. 写法:<style scoped>

注意: scoped 样式一般不会在 App.vue 中使用。


2.7 TodoList案例

  • src/components/MyHeader.vue

    <template>
    	<div class="todo-header">
    		<input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="add"/>
    	</div>
    </template>
    
    <script>
    	import {nanoid} from 'nanoid'
    	export default {
    		name:'MyHeader',
    		//接收从App传递过来的addTodo
    		props:['addTodo'],
    		data() {
    			return {
    				//收集用户输入的title
    				title:''
    			}
    		},
    		methods: {
    			add(){
    				//校验数据
    				if(!this.title.trim()) return alert('输入不能为空')
    				//将用户的输入包装成一个todo对象
    				const todoObj = {id:nanoid(),title:this.title,done:false}
    				//通知App组件去添加一个todo对象
    				this.addTodo(todoObj)
    				//清空输入
    				this.title = ''
    			}
    		},
    	}
    </script>
    
    <style scoped>
    	/*header*/
    	.todo-header input {
    		width: 560px;
    		height: 28px;
    		font-size: 14px;
    		border: 1px solid #ccc;
    		border-radius: 4px;
    		padding: 4px 7px;
    	}
    
    	.todo-header input:focus {
    		outline: none;
    		border-color: rgba(82, 168, 236, 0.8);
    		box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
    	}
    </style>
    
  • src/components/MyList.vue

    <template>
    	<ul class="todo-main">
    		<MyItem 
    			v-for="todoObj in todos"
    			:key="todoObj.id" 
    			:todo="todoObj" 
    			:checkTodo="checkTodo"
    			:deleteTodo="deleteTodo"
    		/>
    	</ul>
    </template>
    
    <script>
    	import MyItem from './MyItem'
    
    	export default {
    		name:'MyList',
    		components:{MyItem},
    		//声明接收App传递过来的数据,其中todos是自己用的,checkTodo和deleteTodo是给子组件MyItem用的
    		props:['todos','checkTodo','deleteTodo']
    	}
    </script>
    
    <style scoped>
    	/*main*/
    	.todo-main {
    		margin-left: 0px;
    		border: 1px solid #ddd;
    		border-radius: 2px;
    		padding: 0px;
    	}
    
    	.todo-empty {
    		height: 40px;
    		line-height: 40px;
    		border: 1px solid #ddd;
    		border-radius: 2px;
    		padding-left: 5px;
    		margin-top: 10px;
    	}
    </style>
    
  • src/components/MyItem.vue

    <template>
    	<li>
    		<label>
    			<input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>
    			<!-- 如下代码也能实现功能,但是不太推荐,因为有点违反原则,因为修改了props -->
    			<!-- <input type="checkbox" v-model="todo.done"/> -->
    			<span>{{todo.title}}</span>
    		</label>
    		<button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
    	</li>
    </template>
    
    <script>
    	export default {
    		name:'MyItem',
    		//声明接收todo、checkTodo、deleteTodo
    		props:['todo','checkTodo','deleteTodo'],
    		methods: {
    			//勾选or取消勾选
    			handleCheck(id){
    				//通知App组件将对应的todo对象的done值取反
    				this.checkTodo(id)
    			},
    			//删除
    			handleDelete(id){
    				if(confirm('确定删除吗?')){
    					//通知App组件将对应的todo对象删除
    					this.deleteTodo(id)
    				}
    			}
    		},
    	}
    </script>
    
    <style scoped>
    	/*item*/
    	li {
    		list-style: none;
    		height: 36px;
    		line-height: 36px;
    		padding: 0 5px;
    		border-bottom: 1px solid #ddd;
    	}
    
    	li label {
    		float: left;
    		cursor: pointer;
    	}
    
    	li label li input {
    		vertical-align: middle;
    		margin-right: 6px;
    		position: relative;
    		top: -1px;
    	}
    
    	li button {
    		float: right;
    		display: none;
    		margin-top: 3px;
    	}
    
    	li:before {
    		content: initial;
    	}
    
    	li:last-child {
    		border-bottom: none;
    	}
    
    	li:hover{
    		background-color: #ddd;
    	}
    	
    	li:hover button{
    		display: block;
    	}
    </style>
    
  • src/components/MyFooter.vue

    <template>
    	<div class="todo-footer" v-show="total">
    		<label>
    			<!-- <input type="checkbox" :checked="isAll" @change="checkAll"/> -->
    			<input type="checkbox" v-model="isAll"/>
    		</label>
    		<span>
    			<span>已完成{{doneTotal}}</span> / 全部{{total}}
    		</span>
    		<button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'MyFooter',
    		props:['todos','checkAllTodo','clearAllTodo'],
    		computed: {
    			//总数
    			total(){
    				return this.todos.length
    			},
    			//已完成数
    			doneTotal(){
    				//此处使用reduce方法做条件统计
    				/* const x = this.todos.reduce((pre,current)=>{
    					console.log('@',pre,current)
    					return pre + (current.done ? 1 : 0)
    				},0) */
    				//简写
    				return this.todos.reduce((pre,todo)=> pre + (todo.done ? 1 : 0) ,0)
    			},
    			//控制全选框
    			isAll:{
    				//全选框是否勾选
    				get(){
    					return this.doneTotal === this.total && this.total > 0
    				},
    				//isAll被修改时set被调用
    				set(value){
    					this.checkAllTodo(value)
    				}
    			}
    		},
    		methods: {
    			/* checkAll(e){
    				this.checkAllTodo(e.target.checked)
    			} */
    			//清空所有已完成
    			clearAll(){
    				this.clearAllTodo()
    			}
    		},
    	}
    </script>
    
    <style scoped>
    	/*footer*/
    	.todo-footer {
    		height: 40px;
    		line-height: 40px;
    		padding-left: 6px;
    		margin-top: 5px;
    	}
    
    	.todo-footer label {
    		display: inline-block;
    		margin-right: 20px;
    		cursor: pointer;
    	}
    
    	.todo-footer label input {
    		position: relative;
    		top: -1px;
    		vertical-align: middle;
    		margin-right: 5px;
    	}
    
    	.todo-footer button {
    		float: right;
    		margin-top: 5px;
    	}
    </style>
    
  • src/App.vue

    <template>
    	<div id="root">
    		<div class="todo-container">
    			<div class="todo-wrap">
    				<MyHeader :addTodo="addTodo"/>
    				<MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>
    				<MyFooter :todos="todos" :checkAllTodo="checkAllTodo" :clearAllTodo="clearAllTodo"/>
    			</div>
    		</div>
    	</div>
    </template>
    
    <script>
    	import MyHeader from './components/MyHeader'
    	import MyList from './components/MyList'
    	import MyFooter from './components/MyFooter.vue'
    
    	export default {
    		name:'App',
    
    		components:{
    			MyHeader,
    			MyList,
    			MyFooter
    		},
    
    		data() {
    			return {
    				//由于todos是MyHeader组件和MyFooter组件都在使用,所以放在App中(状态提升)
    				todos:[
    					{id:'001',title:'学习',done:true},
    					{id:'002',title:'吃饭',done:false},
    					{id:'003',title:'看剧',done:true}
    				]
    			}
    		},
    		methods: {
    			//添加一个todo
    			addTodo(todoObj){
    				this.todos.unshift(todoObj)
    			},
    			//勾选or取消勾选一个todo
    			checkTodo(id){
    				this.todos.forEach((todo)=>{
    					if(todo.id === id) todo.done = !todo.done
    				})
    			},
    			//删除一个todo
    			deleteTodo(id){
    				this.todos = this.todos.filter( todo => todo.id !== id )
    			},
    			//全选or取消全选
    			checkAllTodo(done){
    				this.todos.forEach((todo)=>{
    					todo.done = done
    				})
    			},
    			//清除所有已经完成的todo
    			clearAllTodo(){
    				this.todos = this.todos.filter((todo)=>{
    					return !todo.done
    				})
    			}
    		}
    	}
    </script>
    
    <style>
    	/*base*/
    	body {
    		background: #fff;
    	}
    	.btn {
    		display: inline-block;
    		padding: 4px 12px;
    		margin-bottom: 0;
    		font-size: 14px;
    		line-height: 20px;
    		text-align: center;
    		vertical-align: middle;
    		cursor: pointer;
    		box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
    		border-radius: 4px;
    	}
    	.btn-danger {
    		color: #fff;
    		background-color: #da4f49;
    		border: 1px solid #bd362f;
    	}
    	.btn-danger:hover {
    		color: #fff;
    		background-color: #bd362f;
    	}
    	.btn:focus {
    		outline: none;
    	}
    	.todo-container {
    		width: 600px;
    		margin: 0 auto;
    	}
    	.todo-container .todo-wrap {
    		padding: 10px;
    		border: 1px solid #ddd;
    		border-radius: 5px;
    	}
    </style>
    
    

效果:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


总结:

  1. 组件化编码流程:

    ​ (1)拆分静态组件:组件要按照 功能 点拆分,命名不要与html元素冲突。

    ​ (2)实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:

    • (1)一个组件在用:放在组件自身即可。

    • (2)一些组件在用:放在他们共同的父组件上(状态提升)。

    ​ (3)实现交互:从绑定事件开始。

  2. props 适用于:

    ​ (1)父组件 ==> 子组件 通信

    ​ (2)子组件 ==> 父组件 通信(要求父先给子一个函数)

  3. 使用 v-model 时要切记:v-model 绑定的值不能是 props 传过来的值,因为 props 是不可以修改的!

  4. props 传过来的若是对象类型的值,修改对象中的属性时 Vue 不会报错,但不推荐这样做。


2.8 浏览器本地存储

代码:
localStorage.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>localStorage</title>
	</head>
	<body>
		<h2>localStorage</h2>
		<button οnclick="saveData()">点我保存一个数据</button>
		<button οnclick="readData()">点我读取一个数据</button>
		<button οnclick="deleteData()">点我删除一个数据</button>
		<button οnclick="deleteAllData()">点我清空一个数据</button>

		<script type="text/javascript" >
			let p = {name:'张三',age:18}

			function saveData(){
				localStorage.setItem('msg','hello!!!')
				localStorage.setItem('msg2',666)
				localStorage.setItem('person',JSON.stringify(p))
			}
			function readData(){
				console.log(localStorage.getItem('msg'))
				console.log(localStorage.getItem('msg2'))

				const result = localStorage.getItem('person')
				console.log(JSON.parse(result))

				// console.log(localStorage.getItem('msg3'))
			}
			function deleteData(){
				localStorage.removeItem('msg2')
			}
			function deleteAllData(){
				localStorage.clear()
			}
		</script>
	</body>
</html>

效果:
在这里插入图片描述
在这里插入图片描述


sessionStorage.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>sessionStorage</title>
	</head>
	<body>
		<h2>sessionStorage</h2>
		<button οnclick="saveData()">点我保存一个数据</button>
		<button οnclick="readData()">点我读取一个数据</button>
		<button οnclick="deleteData()">点我删除一个数据</button>
		<button οnclick="deleteAllData()">点我清空一个数据</button>

		<script type="text/javascript" >
			let p = {name:'张三',age:18}

			function saveData(){
				sessionStorage.setItem('msg','hello!!!')
				sessionStorage.setItem('msg2',666)
				sessionStorage.setItem('person',JSON.stringify(p))
			}
			function readData(){
				console.log(sessionStorage.getItem('msg'))
				console.log(sessionStorage.getItem('msg2'))

				const result = sessionStorage.getItem('person')
				console.log(JSON.parse(result))

				// console.log(sessionStorage.getItem('msg3'))
			}
			function deleteData(){
				sessionStorage.removeItem('msg2')
			}
			function deleteAllData(){
				sessionStorage.clear()
			}
		</script>
	</body>
</html>

效果:
在这里插入图片描述
在这里插入图片描述


总结:

  1. 存储内容大小一般支持5MB左右(不同浏览器可能不一样)

  2. 浏览器端通过 Window.sessionStorageWindow.localStorage 属性来实现本地存储机制。

  3. 相关API:

    1. xxxxxStorage.setItem('key', 'value')
      该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。

    2. xxxxxStorage.getItem('person')

      ​ 该方法接受一个键名作为参数,返回键名对应的值。

    3. xxxxxStorage.removeItem('key')

      ​ 该方法接受一个键名作为参数,并把该键名从存储中删除。

    4. xxxxxStorage.clear()

      ​ 该方法会清空存储中的所有数据。

  4. 备注:

    1. SessionStorage 存储的内容会随着浏览器窗口关闭而消失。
    2. LocalStorage 存储的数据是持久性的,可以长时间保存,需要手动清除才会消失。
    3. xxxxxStorage.getItem(xxx)如果xxx对应的value获取不到,那么 getItem()的返回值是null。
    4. JSON.parse(null)的结果依然是null。

2.9 TodoList_本地存储

src/App.vue

<template>
    <div id="root">
        <div class="todo-container">
            <div class="todo-wrap">
            <MyHeader :addTodo="addTodo"/>
            <MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>
            <MyFooter :todos="todos" :checkAllTodo="checkAllTodo" :clearAllTodo="clearAllTodo"/>
            </div>
        </div>
    </div>
</template>

<script>
    import MyHeader from './components/MyHeader.vue'
    import MyList from './components/MyList.vue'
    import MyFooter from './components/MyFooter.vue'

    export default {
        name:'App',
        components: { MyHeader,MyList,MyFooter },
        data() {
            return {
                //若localStorage中存有'todos'则从localStorage中取出,否则初始为空数组
                todos:JSON.parse(localStorage.getItem('todos')) || []
            }
        },
        methods:{
            //添加一个todo
            addTodo(todoObj){
                this.todos.unshift(todoObj)
            },
            //勾选or取消勾选一个todo
            checkTodo(id){
                this.todos.forEach((todo)=>{
                    if(todo.id === id) todo.done = !todo.done
                })
            },
            //删除一个todo
            deleteTodo(id){
                this.todos = this.todos.filter(todo => todo.id !== id)
            },
            //全选or取消勾选
            checkAllTodo(done){
                this.todos.forEach(todo => todo.done = done)
            },
            //删除已完成的todo
            clearAllTodo(){
                this.todos = this.todos.filter(todo => !todo.done)
            }
        },
        watch:{
            todos:{
                //由于todos是对象数组,所以必须开启深度监视才能发现数组中对象的变化
                deep:true,
                handler(value){
                    localStorage.setItem('todos',JSON.stringify(value))
                }
            }
        }
    }
</script>

<style>
    body {
    	background: #fff;
    }

    .btn {
        display: inline-block;
        padding: 4px 12px;
        margin-bottom: 0;
        font-size: 14px;
        line-height: 20px;
        text-align: center;
        vertical-align: middle;
        cursor: pointer;
        box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
        border-radius: 4px;
    }

    .btn-danger {
        color: #fff;
        background-color: #da4f49;
        border: 1px solid #bd362f;
    }

    .btn-danger:hover {
        color: #fff;
        background-color: #bd362f;
    }

    .btn:focus {
    	outline: none;
    }

    .todo-container {
        width: 600px;
        margin: 0 auto;
    }
    .todo-container .todo-wrap {
        padding: 10px;
        border: 1px solid #ddd;
        border-radius: 5px;
    }
</style>

2.10 组件自定义事件

2.10.1 绑定

  • src/App.vue

    <template>
        <div class="app">
    		
            <!-- 通过父组件给子组件传递函数类型的props实现子给父传递数据 -->
            <School :getSchoolName="getSchoolName"/>
    
            <!-- 通过父组件给子组件绑定一个自定义事件实现子给父传递数据(第一种写法,使用@或v-on) -->
            <!-- <Student @jojo="getStudentName"/> -->
    
            <!-- 通过父组件给子组件绑定一个自定义事件实现子给父传递数据(第二种写法,使用ref) -->
    		<Student ref="student"/>
        </div>
    </template>
    
    <script>
        import Student from './components/Student.vue'
        import School from './components/School.vue'
    
        export default {
            name:'App',
            components: { Student,School },
            methods:{
                getSchoolName(name){
                    console.log("已收到学校的名称:"+name)
                },
                getStudentName(name){
                    console.log("已收到学生的姓名:"+name)      
                }
            },
            mounted(){
                this.$refs.student.$on('jojo',this.getStudentName)
            }
        }
    </script>
    
    
    <style scoped>
    	.app{
    		background-color: gray;
    		padding: 5px;
    	}
    </style>
    
  • src/components/School.vue

    <template>
    	<div class="school">
    		<h2>学校名称:{{name}}</h2>
    		<h2>学校地址:{{address}}</h2>
    		<button @click="sendSchoolName">点我传递学校名给App</button>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'School',
    		props:['getSchoolName'],
    		data() {
    			return {
    				name:'光明学校',
    				address:'广州',
    			}
    		},
    		methods: {
    			sendSchoolName(){
    				this.getSchoolName(this.name)
    			}
    		},
    	}
    </script>
    
    <style scoped>
    	.school{
    		background-color: skyblue;
    		padding: 5px;
    	}
    </style>
    
  • src/components/Student.vue

    <template>
        <div class="student">
            <h2>学生姓名:{{name}}</h2>
            <h2>学生性别:{{sex}}</h2>
            <button @click="sendStudentName">点我传递学生姓名给App</button> 
        </div>
    </template>
    
    <script>
        export default {
            name:'Student',
            data() {
                return {
                    name:'张三',
    				sex:'男'
                }
            },
            methods:{
                sendStudentName(){
                    this.$emit('jojo',this.name)
                }
            }
        }
    </script>
    
    <style scoped>
        .student{
            background-color: chartreuse;
            padding: 5px;
    		margin-top: 30px;
        }
    </style>
    
    

效果:
在这里插入图片描述


2.10.2 解绑

  • src/App.vue

    <template>
        <div class="app">
            <Student @jojo="getStudentName"/>
        </div>
    </template>
    
    <script>
    import School from './components/School.vue'
        import Student from './components/Student.vue'
    
        export default {
            name:'App',
            components: { Student, School },
            methods:{
                getStudentName(name){
                    console.log("已收到学生的姓名:"+name)      
                }
            }
        }
    </script>
    
    <style scoped>
    	.app{
    		background-color: gray;
    		padding: 5px;
    	}
    </style>
    
    
  • src/components/Student.vue

    <template>
        <div class="student">
            <h2>学生姓名:{{name}}</h2>
            <h2>学生性别:{{sex}}</h2>
            <button @click="sendStudentName">点我传递学生姓名给App</button> 
            <button @click="unbind">解绑自定义事件</button> 
        </div>
    </template>
    
    <script>
        export default {
            name:'Student',
            data() {
                return {
                    name:'JOJO',
    				sex:'男'
                }
            },
            methods:{
                sendStudentName(){
                    this.$emit('jojo',this.name)
                },
                unbind(){
                    // 解绑一个自定义事件
                    // this.$off('jojo')
                    // 解绑多个自定义事件
                    // this.$off(['jojo'])
                    // 解绑所有自定义事件
                    this.$off()
                }
            }
        }
    </script>
    
    <style scoped>
        .student{
            background-color: chartreuse;
            padding: 5px;
    		margin-top: 30px;
        }
    </style>
    
    

效果:
在这里插入图片描述


总结:

  1. 一种组件间通信的方式,适用于:子组件 ===> 父组件

  2. 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。

  3. 绑定自定义事件:

    1. 第一种方式,在父组件中:<Demo @custom-event="test"/><Demo v-on:custom-event="test"/>

    2. 第二种方式,在父组件中:

      <Demo ref="demo"/>
      ......
      mounted(){
         this.$refs.xxx.$on('custom-event',this.test)
      }
      
    3. 若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。

  4. 触发自定义事件:this.$emit('custom-event',数据)

  5. 解绑自定义事件this.$off('custom-event')

  6. 组件上也可以绑定原生DOM事件,需要使用native修饰符。

  7. 注意:通过this.$refs.xxx.$on('custom-event',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!


2.11 TodoList_自定义事件

  • src/App.vue

    <template>
        <div id="root">
            <div class="todo-container">
                <div class="todo-wrap">
                <MyHeader @addTodo="addTodo"/>
                <MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>
                <MyFooter :todos="todos" @checkAllTodo="checkAllTodo" @clearAllTodo="clearAllTodo"/>
                </div>
            </div>
        </div>
    </template>
    
    <script>
        import MyHeader from './components/MyHeader.vue'
        import MyList from './components/MyList.vue'
        import MyFooter from './components/MyFooter.vue'
    
        export default {
            name:'App',
            components: { MyHeader,MyList,MyFooter },
            data() {
                return {
                    todos:JSON.parse(localStorage.getItem('todos')) || []
                }
            },
            methods:{
                //添加一个todo
                addTodo(todoObj){
                    this.todos.unshift(todoObj)
                },
                //勾选or取消勾选一个todo
                checkTodo(id){
                    this.todos.forEach((todo)=>{
                        if(todo.id === id) todo.done = !todo.done
                    })
                },
                //删除一个todo
                deleteTodo(id){
                    this.todos = this.todos.filter(todo => todo.id !== id)
                },
                //全选or取消勾选
                checkAllTodo(done){
                    this.todos.forEach(todo => todo.done = done)
                },
                //删除已完成的todo
                clearAllTodo(){
                    this.todos = this.todos.filter(todo => !todo.done)
                }
            },
            watch:{
                todos:{
                    deep:true,
                    handler(value){
                        localStorage.setItem('todos',JSON.stringify(value))
                    }
                }
            }
        }
    </script>
    
    <style>
        body {
        	background: #fff;
        }
    
        .btn {
            display: inline-block;
            padding: 4px 12px;
            margin-bottom: 0;
            font-size: 14px;
            line-height: 20px;
            text-align: center;
            vertical-align: middle;
            cursor: pointer;
            box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
            border-radius: 4px;
        }
    
        .btn-danger {
            color: #fff;
            background-color: #da4f49;
            border: 1px solid #bd362f;
        }
    
        .btn-danger:hover {
            color: #fff;
            background-color: #bd362f;
        }
    
        .btn:focus {
       		outline: none;
        }
    
        .todo-container {
        	width: 600px;
        	margin: 0 auto;
        }
        .todo-container .todo-wrap {
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
    </style>
    
  • src/components/MyHeader.vue

    <template>
        <div class="todo-header">
            <input type="text" placeholder="请输入你的任务名称,按回车键确认" @keydown.enter="add" v-model="title"/>
        </div>
    </template>
    
    <script>
        import {nanoid} from 'nanoid'
        export default {
            name:'MyHeader',
            data() {
                return {
                    title:''
                }
            },
            methods:{
                add(){
                    if(!this.title.trim()) return
                    const todoObj = {id:nanoid(),title:this.title,done:false}
                    this.$emit('addTodo',todoObj)
                    this.title = ''
                }
            }
        }
    </script>
    
    <style scoped>
        /*header*/
        .todo-header input {
            width: 560px;
            height: 28px;
            font-size: 14px;
            border: 1px solid #ccc;
            border-radius: 4px;
            padding: 4px 7px;
        }
    
        .todo-header input:focus {
            outline: none;
            border-color: rgba(82, 168, 236, 0.8);
            box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
        }
    </style>
    
  • src/components/MyFooter

    <template>
        <div class="todo-footer" v-show="total">
            <label>
                <input type="checkbox" v-model="isAll"/>
            </label>
            <span>
                <span>已完成{{doneTotal}}</span> / 全部{{total}}
            </span>
            <button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
        </div>
    </template>
    
    <script>
        export default {
            name:'MyFooter',
            props:['todos'],
            computed:{
                doneTotal(){
                    return this.todos.reduce((pre,todo)=> pre + (todo.done ? 1 : 0) ,0)
                },
                total(){
                    return this.todos.length
                },
                isAll:{
                    get(){
                        return this.total === this.doneTotal && this.total > 0
                    },
                    set(value){
                        this.$emit('checkAllTodo',value)
                    }
                }
            },
            methods:{
                clearAll(){
                    this.$emit('clearAllTodo')
                }
            }
        }
    </script>
    
    <style scoped>
        .todo-footer {
            height: 40px;
            line-height: 40px;
            padding-left: 6px;
            margin-top: 5px;
            }
    
        .todo-footer label {
            display: inline-block;
            margin-right: 20px;
            cursor: pointer;
        }
    
        .todo-footer label input {
            position: relative;
            top: -1px;
            vertical-align: middle;
            margin-right: 5px;
        }
    
        .todo-footer button {
            float: right;
            margin-top: 5px;
        }
    </style>
    

2.12 全局事件总线(GlobalEventBus)

  • src/main.js

    //引入Vue
    import Vue from 'vue'
    //引入App
    import App from './App.vue'
    //关闭Vue的生产提示
    Vue.config.productionTip = false
    
    //创建vm
    new Vue({
    	el:'#app',
    	render: h => h(App),
    	beforeCreate() {
    		Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
    	},
    })
    
  • src/App.vue

    <template>
    	<div class="app">
    		<h1>{{msg}}</h1>
    		<School/>
    		<Student/>
    	</div>
    </template>
    
    <script>
    	import Student from './components/Student'
    	import School from './components/School'
    
    	export default {
    		name:'App',
    		components:{School,Student},
    		data() {
    			return {
    				msg:'你好啊!',
    			}
    		}
    	}
    </script>
    
    <style scoped>
    	.app{
    		background-color: gray;
    		padding: 5px;
    	}
    </style>
    
  • src/components/School.vue

    <template>
    	<div class="school">
    		<h2>学校名称:{{name}}</h2>
    		<h2>学校地址:{{address}}</h2>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'School',
    		data() {
    			return {
    				name:'光明学校',
    				address:'广州',
    			}
    		},
    		mounted() {
    			// console.log('School',this)
    			this.$bus.$on('hello',(data)=>{
    				console.log('我是School组件,收到了数据:',data)
    			})
    		},
    
    		beforeDestroy() {
    			this.$bus.$off('hello') //解绑当前组件用到的事件
    		},
    	}
    </script>
    
    <style scoped>
    	.school{
    		background-color: skyblue;
    		padding: 5px;
    	}
    </style>
    
  • src/components/Student.vue

    <template>
    	<div class="student">
    		<h2>学生姓名:{{name}}</h2>
    		<h2>学生性别:{{sex}}</h2>
    		<button @click="sendStudentName">把学生名传递给School组件</button>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'Student',
    		data() {
    			return {
    				name:'张三',
    				sex:'男',
    			}
    		},
    		mounted() {
    			// console.log('Student',this.x)
    		},
    		methods: {
    			sendStudentName(){
    				this.$bus.$emit('hello',this.name)
    			}
    		},
    	}
    </script>
    
    <style lang="less" scoped>
    	.student{
    		background-color: pink;
    		padding: 5px;
    		margin-top: 30px;
    	}
    </style>
    

效果:
在这里插入图片描述


总结:

  1. 一种组件间通信的方式,适用于 任意组件间通信

  2. 安装全局事件总线:

    new Vue({
    	......
    	beforeCreate() {
    		Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
    	},
        ......
    }) 
    
  3. 使用事件总线:

    1. 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。

      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.$bus.$on('xxxx',this.demo)
      }
      
    2. 提供数据:this.$bus.$emit('xxxx',数据)

  4. 最好在 beforeDestroy 钩子中,用$off去解绑当前组件所用到的事件。


2.13 TodoList_事件总线

  • src/mian.js

    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    new Vue({
        el:"#app",
        render: h => h(App),
        beforeCreate() {
            Vue.prototype.$bus = this
        }
    })
    
  • src/components/App.vue

    <template>
        <div id="root">
            <div class="todo-container">
                <div class="todo-wrap">
                <MyHeader @addTodo="addTodo"/>
                <MyList :todos="todos"/>
                <MyFooter :todos="todos" @checkAllTodo="checkAllTodo" @clearAllTodo="clearAllTodo"/>
                </div>
            </div>
        </div>
    </template>
    
    <script>
        import MyHeader from './components/MyHeader.vue'
        import MyList from './components/MyList.vue'
        import MyFooter from './components/MyFooter.vue'
    
        export default {
            name:'App',
            components: { MyHeader,MyList,MyFooter },
            data() {
                return {
                    todos:JSON.parse(localStorage.getItem('todos')) || []
                }
            },
            methods:{
                //添加一个todo
                addTodo(todoObj){
                    this.todos.unshift(todoObj)
                },
                //勾选or取消勾选一个todo
                checkTodo(id){
                    this.todos.forEach((todo)=>{
                        if(todo.id === id) todo.done = !todo.done
                    })
                },
                //删除一个todo
                deleteTodo(id){
                    this.todos = this.todos.filter(todo => todo.id !== id)
                },
                //全选or取消勾选
                checkAllTodo(done){
                    this.todos.forEach(todo => todo.done = done)
                },
                //删除已完成的todo
                clearAllTodo(){
                    this.todos = this.todos.filter(todo => !todo.done)
                }
            },
            watch:{
                todos:{
                    deep:true,
                    handler(value){
                        localStorage.setItem('todos',JSON.stringify(value))
                    }
                }
            },
            mounted(){
                this.$bus.$on('checkTodo',this.checkTodo)
                this.$bus.$on('deleteTodo',this.deleteTodo)
            },
            beforeDestroy(){
                this.$bus.$off(['checkTodo','deleteTodo'])
            }
        }
    </script>
    
    <style>
        body {
            background: #fff;
        }
    
        .btn {
            display: inline-block;
            padding: 4px 12px;
            margin-bottom: 0;
            font-size: 14px;
            line-height: 20px;
            text-align: center;
            vertical-align: middle;
            cursor: pointer;
            box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
            border-radius: 4px;
        }
    
        .btn-danger {
            color: #fff;
            background-color: #da4f49;
            border: 1px solid #bd362f;
        }
    
        .btn-danger:hover {
            color: #fff;
            background-color: #bd362f;
        }
    
        .btn:focus {
            outline: none;
        }
    
        .todo-container {
            width: 600px;
            margin: 0 auto;
        }
        .todo-container .todo-wrap {
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
    </style>
    
  • src/components/MyItem.vue

    <template>
        <li>
            <label>
                <input type="checkbox" :checked="todo.done" @click="handleCheck(todo.id)"/>
                <span>{{todo.title}}</span>
            </label>
            <button class="btn btn-danger" @click="handleDelete(todo.id,todo.title)">删除</button>
        </li>
    </template>
    
    <script>
        export default {
            name:'MyItem',
            props:['todo'],
            methods:{
                handleCheck(id){
                    this.$bus.$emit('checkTodo',id)
                },
                handleDelete(id,title){
                    if(confirm("确定删除任务:"+title+"吗?")){
                        this.$bus.$emit('deleteTodo',id)
                    }
                }
            }
        }
    </script>
    
    <style scoped>
        li {
            list-style: none;
            height: 36px;
            line-height: 36px;
            padding: 0 5px;
            border-bottom: 1px solid #ddd;
        }
    
        li label {
            float: left;
            cursor: pointer;
        }
    
        li label li input {
            vertical-align: middle;
            margin-right: 6px;
            position: relative;
            top: -1px;
        }
    
        li button {
            float: right;
            display: none;
            margin-top: 3px;
        }
    
        li:before {
            content: initial;
        }
    
        li:last-child {
            border-bottom: none;
        }
    
        li:hover {
            background-color: #eee;
        }
    
        li:hover button{
            display: block;
        }
    </style>
    

2.14 消息订阅与发布(pubsub)

  • src/components/School.vue

    <template>
    	<div class="school">
    		<h2>学校名称:{{name}}</h2>
    		<h2>学校地址:{{address}}</h2>
    	</div>
    </template>
    
    <script>
    	import pubsub from 'pubsub-js'
    
    	export default {
    		name:'School',
    		data() {
    			return {
    				name:'光明学校',
    				address:'广州',
    			}
    		},
    		methods:{
    			demo(msgName,data) {
    				console.log('我是School组件,收到了数据:',data)
    			}
    		},
    		mounted() {
    			this.pubId = pubsub.subscribe('demo',this.demo) //订阅消息
    		},
    		beforeDestroy() {
    			pubsub.unsubscribe(this.pubId) //取消订阅
    		}
    	}
    </script>
    
    <style scoped>
    	.school{
    		background-color: skyblue;
    		padding: 5px;
    	}
    </style>
    
    
  • src/components/Student.vue

    <template>
    	<div class="student">
    		<h2>学生姓名:{{name}}</h2>
    		<h2>学生性别:{{sex}}</h2>
    		<button @click="sendStudentName">把学生名给School组件</button>
    	</div>
    </template>
    
    <script>
    	import pubsub from 'pubsub-js'
    
    	export default {
    		name:'Student',
    		data() {
    			return {
    				name:'张三',
    				sex:'男',
    			}
    		},
    		methods: {
    			sendStudentName(){
    				pubsub.publish('demo',this.name) //发布消息
    			}
    		}
    	}
    </script>
    
    <style scoped>
    	.student{
    		background-color: pink;
    		padding: 5px;
    		margin-top: 30px;
    	}
    </style>
    
    

效果:
在这里插入图片描述


总结:

  1. 一种组件间通信的方式,适用于 任意组件间通信

  2. 使用步骤:

    1. 安装pubsub:npm i pubsub-js

    2. 引入: import pubsub from 'pubsub-js'

    3. 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。

      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
      }
      
    4. 提供数据:pubsub.publish('xxx',数据)

    5. 最好在 beforeDestroy 钩子中,用 PubSub.unsubscribe(pid) 去取消订阅。


2.15 使用消息的订阅与发布优化Todo-List

  • src/App.vue

    <template>
        <div id="root">
            <div class="todo-container">
                <div class="todo-wrap">
                <MyHeader @addTodo="addTodo"/>
                <MyList :todos="todos"/>
                <MyFooter :todos="todos" @checkAllTodo="checkAllTodo" @clearAllTodo="clearAllTodo"/>
                </div>
            </div>
        </div>
    </template>
    
    <script>
        import pubsub from 'pubsub-js'
        import MyHeader from './components/MyHeader.vue'
        import MyList from './components/MyList.vue'
        import MyFooter from './components/MyFooter.vue'
    
    
        export default {
            name:'App',
            components: { MyHeader,MyList,MyFooter },
            data() {
                return {
                    todos:JSON.parse(localStorage.getItem('todos')) || []
                }
            },
            methods:{
                //添加一个todo
                addTodo(todoObj){
                    this.todos.unshift(todoObj)
                },
                //勾选or取消勾选一个todo
                checkTodo(_,id){
                    this.todos.forEach((todo)=>{
                        if(todo.id === id) todo.done = !todo.done
                    })
                },
                //删除一个todo
                deleteTodo(id){
                    this.todos = this.todos.filter(todo => todo.id !== id)
                },
                //全选or取消勾选
                checkAllTodo(done){
                    this.todos.forEach(todo => todo.done = done)
                },
                //删除已完成的todo
                clearAllTodo(){
                    this.todos = this.todos.filter(todo => !todo.done)
                }
            },
            watch:{
                todos:{
                    deep:true,
                    handler(value){
                        localStorage.setItem('todos',JSON.stringify(value))
                    }
                }
            },
            mounted(){
                this.pubId = pubsub.subscribe('checkTodo',this.checkTodo)
                this.$bus.$on('deleteTodo',this.deleteTodo)
            },
            beforeDestroy(){
                pubsub.unsubscribe(this.pubId)
                this.$bus.$off('deleteTodo')
            }
        }
    </script>
    
    <style>
        body {
            background: #fff;
        }
    
        .btn {
            display: inline-block;
            padding: 4px 12px;
            margin-bottom: 0;
            font-size: 14px;
            line-height: 20px;
            text-align: center;
            vertical-align: middle;
            cursor: pointer;
            box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
            border-radius: 4px;
        }
    
        .btn-danger {
            color: #fff;
            background-color: #da4f49;
            border: 1px solid #bd362f;
        }
    
        .btn-danger:hover {
            color: #fff;
            background-color: #bd362f;
        }
    
        .btn:focus {
            outline: none;
        }
    
        .todo-container {
            width: 600px;
            margin: 0 auto;
        }
        .todo-container .todo-wrap {
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
    </style>
    
  • src/components/myItem.vue

    <template>
        <li>
            <label>
                <input type="checkbox" :checked="todo.done" @click="handleCheck(todo.id)"/>
                <span>{{todo.title}}</span>
            </label>
            <button class="btn btn-danger" @click="handleDelete(todo.id,todo.title)">删除</button>
        </li>
    </template>
    
    <script>
        import pubsub from 'pubsub-js'
        export default {
            name:'MyItem',
            props:['todo'],
            methods:{
                handleCheck(id){                    
                    pubsub.publish('checkTodo',id)
                },
                handleDelete(id,title){
                    if(confirm("确定删除任务:"+title+"吗?")){
                        this.$bus.$emit('deleteTodo',id)
                    }
                }
            }
        }
    </script>
    
    <style scoped>
        li {
            list-style: none;
            height: 36px;
            line-height: 36px;
            padding: 0 5px;
            border-bottom: 1px solid #ddd;
        }
    
        li label {
            float: left;
            cursor: pointer;
        }
    
        li label li input {
            vertical-align: middle;
            margin-right: 6px;
            position: relative;
            top: -1px;
        }
    
        li button {
            float: right;
            display: none;
            margin-top: 3px;
        }
    
        li:before {
            content: initial;
        }
    
        li:last-child {
            border-bottom: none;
        }
    
        li:hover {
            background-color: #eee;
        }
    
        li:hover button{
            display: block;
        }
    </style>
    

2.16 nextTick(回调函数)

  1. 语法:this.$nextTick(回调函数)
  2. 作用:在下一次 DOM 更新结束后执行其指定的回调。
  3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。

2.17 过度与动画

  1. 作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。

  2. 写法:

    1. 准备好样式:

      • 元素进入的样式:
        1. v-enter:进入的起点
        2. v-enter-active:进入过程中
        3. v-enter-to:进入的终点
      • 元素离开的样式:
        1. v-leave:离开的起点
        2. v-leave-active:离开过程中
        3. v-leave-to:离开的终点
    2. 使用<transition>包裹要过度的元素,并配置name属性:

      <transition name="hello">
      	<h1 v-show="isShow">你好啊!</h1>
      </transition>
      
    3. 备注:若有多个元素需要过度,则需要使用:<transition-group>,且每个元素都要指定key值。


 
非常感谢您阅读到这里,如果这篇文章对您有帮助,希望能留下您的点赞👍 关注💖 分享👥 留言💬thanks!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1120171.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VMwarePlayer安装Ubuntu,切换中文并安装中文输入法

1.下载和安装 虚拟机使用的免费版官网链接&#xff1a;VMwarePlayer Ubuntu镜像下载官网链接&#xff1a;Ubuntu桌面版 自己学习使用&#xff0c;不需要考虑迁移之类的。选择单个磁盘IO性能会更高 安装过程中如果出现如下报错&#xff0c;则用系统管理员身份运行 右击VMwa…

造车先做三蹦子220101--机器学习字符(字母、和数字识别)的“小白鼠”与“果蝇”

“0”数字字符零 的图片(16*16点阵)&#xff1a; import torch import torch.nn as nn import torch.optim as optim from PIL import Image, ImageDraw, ImageFont from torchvision import transforms import matplotlib.pyplot as pltTimes20001000# 参数设置 font_path &q…

嵌入式实时操作系统的设计与开发(内存资源池存储管理)

内存资源池存储管理 内存资源池存储管理属于固定大小内存管理系统&#xff0c;内存池中内存块的分配和回收是基于第一级内存管理系统的&#xff0c;因为内存池中内存块是由第一级内存管理的算法所确定的。 内存池存储管理系统主要用于操作系统的一些常用结构的内存管理。例如…

位操作符^以及正负数在计算机中的存储

(数据是怎么在计算机中存储的)​ 正数和负数在内存中都是以补码的形式存储的&#xff0c;但不同的是正数的原码&#xff0c;补码&#xff0c;反码都是相同的&#xff0c;而负数的原码&#xff0c;补码和反码是不同的。 负数的原码&#xff0c;补码&#xff0c;反码之间存在什么…

神仙级价格:腾讯云双十一服务器优惠价格表来了

2023腾讯云双十一服务器优惠价格表多少钱一年&#xff1f;轻量服务器2核2G3M、2核2G4M、2核4G5M、4核8G12M、8核16G18M、16核32G28M和云服务器CVM标准型S5实例优惠价格&#xff0c;腾讯云百科今年双11服务器价格会在当前的价格基础上享受个9折优惠&#xff0c;可领券 https://c…

【Java】一只小菜坤的编程题之旅【4】

文章目录 1丶合并两个有序链表2丶栈的压入、弹出序列3丶设计循环队列4丶最小栈 1丶合并两个有序链表 小菜坤的答案&#xff1a; class Solution {public ListNode mergeTwoLists(ListNode list1, ListNode list2) {ListNode newHeadnew ListNode(0);ListNode tmpnewHead;while…

Git的介绍和命令汇总

目录 一、git介绍 1、git的工作区域 2、git中文件的四种状态 二、常用命令 1、基础命令 2、提交类命令 3、删除类命令 4、分支类相关命令 5、 查看类相关命令 6、撤销类命令 一、git介绍 1、git的工作区域 在Git中&#xff0c;有四个工作区域&#xff1a;工作区域&am…

k8s认证

1. 证书介绍 服务端保留公钥和私钥&#xff0c;客户端使用root CA认证服务端的公钥 一共有多少证书&#xff1a; *Etcd&#xff1a; Etcd对外提供服务&#xff0c;要有一套etcd server证书Etcd各节点之间进行通信&#xff0c;要有一套etcd peer证书Kube-APIserver访问Etcd&a…

算法学习之 背包01问题 , 备战leecode

来看题目 我们分析一下题目&#xff0c;首先我们要排序&#xff0c;这有助于我们得到最大的值&#xff0c;我们要得到一个递推公式 代码如下: class Solution { public:int maxSatisfaction(vector<int>& satisfaction) {int n satisfaction.size();vector<v…

【数据结构复习之路】串 (超详细讲解) 严蔚敏版

专栏&#xff1a;数据结构复习之路 复习完上面一章【线性表】【栈和队列】&#xff0c;我们接着复习串&#xff0c;这篇文章我写的非常详细且通俗易懂&#xff0c;看完保证会带给你不一样的收获。如果对你有帮助&#xff0c;看在我这么辛苦整理的份上&#xff0c;三连一下啦 目…

42917-2023 消光制品用聚氯乙烯树脂

1 范围 本文件规定了消光制品用聚氯乙烯树脂的分类、技术要求、取样、试验方法、检验规则及标志、随行 文件、包装、运输和贮存。 本文件适用于氯乙烯与交联剂悬浮共聚所制得的用于生产消光制品的聚氯乙烯树脂。 2 规范性引用文件 下列文件中的内容通过文中的规范性引用而…

通过高通量测序评估金针菇(双孢蘑菇)生产过程中的微生物演替

1.1 Title:Microbial succession during button mushroom (Agaricus bisporus) production evaluated via high-throughput sequencing 1.2 作者&#xff1a;Ban Ga-Hee 1.3 机构&#xff1a;Ewha Womans University 1.4 期刊&#xff1a;Food Microbiology 1.5 分区/影响因…

连接器信号完整性仿真教程 八

连接器信号完整性仿真主要是解算S参数及与之相关的参数&#xff0c;查看仿真结果相对于HFSS&#xff0c;其操作要简单得多。不需要复杂的操作&#xff0c;基本上左边导航树中&#xff0c;就可直接打开需要查看的仿真结果。下面以B to B Connector仿真结果实例演示&#xff0c;详…

何为心理承受能力?如何提高心理承受能力?

心理承受能力&#xff0c;也可以理解为人的抗压能力&#xff0c;指的是承受压力&#xff0c;承受逆境的能力。人的一生其实就是在不断的解决问题&#xff0c;见招拆招&#xff0c;遇到问题解决问题&#xff0c;在我们不断学习和锻炼的过程中&#xff0c;提高了我们解决问题的效…

Python之解析式和生成器表达式

Python之解析式和生成器表达式 列表解析式 列表解析式List Comprehension&#xff0c;也叫列表推导式。 语法 [返回值 for 元素 in 可迭代对象 if 条件]使用中括号[]&#xff0c;内部是for循环&#xff0c;if条件语句可选返回一个新的列表 列表解析式是一种语法糖 编译器…

Vue中如何处理表单输入验证?

在Vue中,能使用多种方式处理表单输入验证。以下是几种常见的方法: 1:使用Vue的指令和表达式: Vue提供了一些内置的指令和表达式,可以直接在模板中进行表单验证。例如,你可以使用v-model指令结合条件表达式来验证输入内容。 <template><div><input v-mod…

微软官方推出的四款工具,太实用了,值得收藏

目录 一、Officeplus——丰富的办公资源库 二、微软数学求解器 三、微软内置edge浏览器 四、Microsoft To-Do 办公待办神器 所以今天小编给大家分享4个微软官方推出的实用工具&#xff0c;每一个都非常好用&#xff0c;对于大家日常办公&#xff0c;非常有必要&#xff0c;感兴…

【C++深入浅出】C/C++内存管理(教你如何new到对象)

一. 前言 前面我们学习了有关C类和对象的知识&#xff0c;学会了如何构建一个完整的类&#xff0c;这些类都是存储在栈空间上的。在C语言中&#xff0c;我们不仅可以在栈上定义变量&#xff0c;也可以对堆上的空间进行管理&#xff0c;在接下来的几期中&#xff0c;我们的目标就…

idea + Docker-Compose 实现自动化打包部署(仅限测试环境)

一、修改docker.service文件&#xff0c;添加监听端口 vi /usr/lib/systemd/system/docker.service ExecStart/usr/bin/dockerd -H fd:// --containerd/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock重启docker服务 systemctl daemo…

一个进程最多可以创建多少个线程基本分析

前言 ​话不多说&#xff0c;先来张脑图~ linux 虚拟内存知识回顾 虚拟内存空间长啥样 在 Linux 操作系统中&#xff0c;虚拟地址空间的内部又被分为内核空间和用户空间两部分&#xff0c;不同位数的系统&#xff0c;地址空间的范围也不同。比如最常见的 32 位和 64 位系统&…