Kaynağa Gözat

修复了云平台安装文档的若干问题
增加了vue的学习笔记

seamew 3 yıl önce
ebeveyn
işleme
8edbffda73

+ 1074 - 0
前端/vue/vue2.md

@@ -0,0 +1,1074 @@
+# 笔记
+
+## 脚手架文件结构
+
+	├── 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:包版本控制文件
+
+## 关于不同版本的Vue
+
+1. vue.js与vue.runtime.xxx.js的区别:
+    1. vue.js是完整版的Vue,包含:核心功能 + 模板解析器。
+    2. vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。
+2. 因为vue.runtime.xxx.js没有模板解析器,所以不能使用template这个配置项,需要使用render函数接收到的createElement函数去指定具体内容。
+
+## vue.config.js配置文件
+
+1. 使用vue inspect > output.js可以查看到Vue脚手架的默认配置。
+2. 使用vue.config.js可以对脚手架进行个性化定制,详情见:https://cli.vuejs.org/zh
+
+## ref属性
+
+1. 被用来给元素或子组件注册引用信息(id的替代者)
+2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
+3. 使用方式:
+    1. 打标识:```<h1 ref="xxx">.....</h1>``` 或 ```<School ref="xxx"></School>```
+    2. 获取:```this.$refs.xxx```
+
+## props配置项
+
+1. 功能:让组件接收外部传过来的数据
+
+2. 传递数据:```<Demo name="xxx"/>```
+
+3. 接收数据:
+
+    1. 第一种方式(只接收):```props:['name'] ```
+
+    2. 第二种方式(限制类型):```props:{name:String}```
+
+    3. 第三种方式(限制类型、限制必要性、指定默认值):
+
+        ```js
+        props:{
+        	name:{
+        	type:String, //类型
+        	required:true, //必要性
+        	default:'老王' //默认值
+        	}
+        }
+        ```
+
+    > 备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。
+
+## mixin(混入)
+
+1. 功能:可以把多个组件共用的配置提取成一个混入对象
+
+2. 使用方式:
+
+    第一步定义混合:
+
+    ```
+    {
+        data(){....},
+        methods:{....}
+        ....
+    }
+    ```
+
+    第二步使用混入:
+
+    ​	全局混入:```Vue.mixin(xxx)```
+    ​	局部混入:```mixins:['xxx']	```
+
+## 插件
+
+1. 功能:用于增强Vue
+
+2. 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
+
+3. 定义插件:
+
+    ```js
+    对象.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()```
+
+## scoped样式
+
+1. 作用:让样式在局部生效,防止冲突。
+2. 写法:```<style scoped>```
+
+## 总结TodoList案例
+
+1. 组件化编码流程:
+
+    ​	(1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
+
+    ​	(2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:
+
+    ​			1).一个组件在用:放在组件自身即可。
+
+    ​			2). 一些组件在用:放在他们共同的父组件上(<span style="color:red">状态提升</span>)。
+
+    ​	(3).实现交互:从绑定事件开始。
+
+2. props适用于:
+
+    ​	(1).父组件 ==> 子组件 通信
+
+    ​	(2).子组件 ==> 父组件 通信(要求父先给子一个函数),传递的函数归根到底还是父组件调用,其中的this指向是父组件
+
+3. 使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!
+
+4. props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。
+
+## webStorage
+
+1. 存储内容大小一般支持5MB左右(不同浏览器可能还不一样)
+
+2. 浏览器端通过 Window.sessionStorage 和 Window.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。
+
+## 组件的自定义事件
+
+1. 一种组件间通信的方式,适用于:<strong style="color:red">子组件 ===> 父组件</strong>
+
+2. 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(<span style="color:red">事件的回调在A中</span>)。
+
+3. 绑定自定义事件:
+
+    1. 第一种方式,在父组件中:```<Demo @atguigu="test"/>```  或 ```<Demo v-on:atguigu="test"/>```
+
+    2. 第二种方式,在父组件中:
+
+        ```js
+        <Demo ref="demo"/>
+        ......
+        mounted(){
+           this.$refs.xxx.$on('atguigu',this.test)
+        }
+        ```
+
+    3. 若想让自定义事件只能触发一次,可以使用```once```修饰符,或```$once```方法。
+
+4. 触发自定义事件:```this.$emit('atguigu',数据)```	,本质是子组件使用函数	
+
+5. 解绑自定义事件```this.$off('atguigu')```
+
+6. 组件上也可以绑定原生DOM事件,需要使用```native```修饰符。
+
+7. 注意:通过```this.$refs.xxx.$on('atguigu',回调)```绑定自定义事件时,回调<span style="color:red">要么配置在methods中</span>,<span style="color:red">要么用箭头函数</span>,否则this指向会出问题!
+
+## 全局事件总线(GlobalEventBus)
+
+1. 一种组件间通信的方式,适用于<span style="color:red">任意组件间通信</span>。
+
+2. 安装全局事件总线:
+
+   ```js
+   new Vue({
+   	......
+   	beforeCreate() {
+   		Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
+   	},
+       ......
+   }) 
+   ```
+
+3. 使用事件总线:
+
+   1. 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的<span style="color:red">回调留在A组件自身。</span>
+
+      ```js
+      methods(){
+        demo(data){......}
+      }
+      ......
+      mounted() {
+        this.$bus.$on('xxxx',this.demo)
+      }
+      ```
+
+   2. 提供数据:```this.$bus.$emit('xxxx',数据)```
+
+4. 最好在beforeDestroy钩子中,用$off去解绑<span style="color:red">当前组件所用到的</span>事件。
+
+## 消息订阅与发布(pubsub)
+
+1.   一种组件间通信的方式,适用于<span style="color:red">任意组件间通信</span>。
+
+2. 使用步骤:
+
+   1. 安装pubsub:```npm i pubsub-js```
+
+   2. 引入: ```import pubsub from 'pubsub-js'```
+
+   3. 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的<span style="color:red">回调留在A组件自身。</span>
+
+      ```js
+      methods(){
+        demo(data){......}
+      }
+      ......
+      mounted() {
+        this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
+      }
+      ```
+
+   4. 提供数据:```pubsub.publish('xxx',数据)```
+
+   5. 最好在beforeDestroy钩子中,用```PubSub.unsubscribe(pid)```去<span style="color:red">取消订阅。</span>
+	
+## nextTick
+
+1. 语法:```this.$nextTick(回调函数)```
+2. 作用:在下一次 DOM 更新结束后执行其指定的回调。
+3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
+
+## Vue封装的过度与动画
+
+1. 作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。
+
+2. 图示:<img src="https://img04.sogoucdn.com/app/a/100520146/5990c1dff7dc7a8fb3b34b4462bd0105" style="width:60%" />
+
+3. 写法:
+
+   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属性:
+
+      ```vue
+      <transition name="hello">
+      	<h1 v-show="isShow">你好啊!</h1>
+      </transition>
+      ```
+
+   3. 备注:若有多个元素需要过度,则需要使用:```<transition-group>```,且每个元素都要指定```key```值。
+
+## vue脚手架配置代理
+
+### 方法一
+
+​	在vue.config.js中添加如下配置:
+
+```js
+devServer:{
+  proxy:"http://localhost:5000"
+}
+```
+
+说明:
+
+1. 优点:配置简单,请求资源时直接发给前端(8080)即可。
+2. 缺点:不能配置多个代理,不能灵活的控制请求是否走代理。
+3. 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)
+
+### 方法二
+
+​	编写vue.config.js配置具体代理规则:
+
+```js
+module.exports = {
+	devServer: {
+      proxy: {
+      '/api1': {// 匹配所有以 '/api1'开头的请求路径
+        target: 'http://localhost:5000',// 代理目标的基础路径
+        changeOrigin: true,
+        pathRewrite: {'^/api1': ''}
+      },
+      '/api2': {// 匹配所有以 '/api2'开头的请求路径
+        target: 'http://localhost:5001',// 代理目标的基础路径
+        changeOrigin: true,
+        pathRewrite: {'^/api2': ''}
+      }
+    }
+  }
+}
+/*
+   changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
+   changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
+   changeOrigin默认值为true
+*/
+```
+
+说明:
+
+1. 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
+2. 缺点:配置略微繁琐,请求资源时必须加前缀。
+
+## 插槽
+
+1. 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 <strong style="color:red">父组件 ===> 子组件</strong> 。
+
+2. 分类:默认插槽、具名插槽、作用域插槽
+
+3. 使用方式:
+
+   1. 默认插槽:
+
+      ```vue
+      父组件中:
+              <Category>
+                 <div>html结构1</div>
+              </Category>
+      子组件中:
+              <template>
+                  <div>
+                     <!-- 定义插槽 -->
+                     <slot>插槽默认内容...</slot>
+                  </div>
+              </template>
+      ```
+
+   2. 具名插槽:
+
+      ```vue
+      父组件中:
+      注意第一种写法已经被废弃,使用v-slot:name写法,若只有一个插槽可以缩写,v-slot
+              <Category>
+                  <template slot="center">
+                    <div>html结构1</div>
+                  </template>
+      
+                  <template v-slot:footer>
+                     <div>html结构2</div>
+                  </template>
+              </Category>
+      子组件中:
+              <template>
+                  <div>
+                     <!-- 定义插槽 -->
+                     <slot name="center">插槽默认内容...</slot>
+                     <slot name="footer">插槽默认内容...</slot>
+                  </div>
+              </template>
+      ```
+   
+   3. 作用域插槽:
+   
+      1. 理解:<span style="color:red">数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。</span>(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)
+   
+      2. 具体编码:
+   
+         ```vue
+         父组件中:
+         注意scope写法已经被弃用
+         		<Category>
+         			<template scope="scopeData">
+         				<!-- 生成的是ul列表 -->
+         				<ul>
+         					<li v-for="g in scopeData.games" :key="g">{{g}}</li>
+         				</ul>
+         			</template>
+         		</Category>
+         使用v-slot:name="prop",或者缩写#name="prop"
+         		<Category>
+         			<template slot-scope="scopeData">
+         				<!-- 生成的是h4标题 -->
+         				<h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
+         			</template>
+         		</Category>
+         子组件中:
+                 <template>
+                     <div>
+                         <slot :games="games"></slot>
+                     </div>
+                 </template>
+         		
+                 <script>
+                     export default {
+                         name:'Category',
+                         props:['title'],
+                         //数据在子组件自身
+                         data() {
+                             return {
+                                 games:['红色警戒','穿越火线','劲舞团','超级玛丽']
+                             }
+                         },
+                     }
+                 </script>
+         ```
+   ```
+   
+   ```
+
+## Vuex
+
+### 1.概念
+
+​		在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
+
+### 2.何时使用?
+
+​		多个组件需要共享数据时
+
+### 3.搭建vuex环境
+
+1. 创建文件:```src/store/index.js```
+
+   ```js
+   //引入Vue核心库
+   import Vue from 'vue'
+   //引入Vuex
+   import Vuex from 'vuex'
+   //应用Vuex插件
+   Vue.use(Vuex)
+   
+   //准备actions对象——响应组件中用户的动作
+   const actions = {}
+   //准备mutations对象——修改state中的数据
+   const mutations = {}
+   //准备state对象——保存具体的数据
+   const state = {}
+   
+   //创建并暴露store
+   export default new Vuex.Store({
+   	actions,
+   	mutations,
+   	state
+   })
+   ```
+
+2. 在```main.js```中创建vm时传入```store```配置项
+
+   ```js
+   ......
+   //引入store
+   import store from './store'
+   ......
+   
+   //创建vm
+   new Vue({
+   	el:'#app',
+   	render: h => h(App),
+   	store
+   })
+   ```
+
+###    4.基本使用
+
+1. 初始化数据、配置```actions```、配置```mutations```,操作文件```store.js```
+
+   ```js
+   //引入Vue核心库
+   import Vue from 'vue'
+   //引入Vuex
+   import Vuex from 'vuex'
+   //引用Vuex
+   Vue.use(Vuex)
+   
+   const actions = {
+       //响应组件中加的动作
+   	jia(context,value){
+   		// console.log('actions中的jia被调用了',miniStore,value)
+   		context.commit('JIA',value)
+   	},
+   }
+   
+   const mutations = {
+       //执行加
+   	JIA(state,value){
+   		// console.log('mutations中的JIA被调用了',state,value)
+   		state.sum += value
+   	}
+   }
+   
+   //初始化数据
+   const state = {
+      sum:0
+   }
+   
+   //创建并暴露store
+   export default new Vuex.Store({
+   	actions,
+   	mutations,
+   	state,
+   })
+   ```
+
+2. 组件中读取vuex中的数据:```$store.state.sum```
+
+3. 组件中修改vuex中的数据:```$store.dispatch('action中的方法名',数据)``` 或 ```$store.commit('mutations中的方法名',数据)```
+
+   >  备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写```dispatch```,直接编写```commit```
+
+### 5.getters的使用
+
+1. 概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。
+
+2. 在```store.js```中追加```getters```配置
+
+   ```js
+   ......
+   
+   const getters = {
+   	bigSum(state){
+   		return state.sum * 10
+   	}
+   }
+   
+   //创建并暴露store
+   export default new Vuex.Store({
+   	......
+   	getters
+   })
+   ```
+
+3. 组件中读取数据:```$store.getters.bigSum```
+
+### 6.四个map方法的使用
+
+1. <strong>mapState方法:</strong>用于帮助我们映射```state```中的数据为计算属性
+
+   ```js
+   computed: {
+       //借助mapState生成计算属性:sum、school、subject(对象写法)
+        ...mapState({sum:'sum',school:'school',subject:'subject'}),
+            
+       //借助mapState生成计算属性:sum、school、subject(数组写法)
+       ...mapState(['sum','school','subject']),
+   },
+   ```
+
+2. <strong>mapGetters方法:</strong>用于帮助我们映射```getters```中的数据为计算属性
+
+   ```js
+   computed: {
+       //借助mapGetters生成计算属性:bigSum(对象写法)
+       ...mapGetters({bigSum:'bigSum'}),
+   
+       //借助mapGetters生成计算属性:bigSum(数组写法)
+       ...mapGetters(['bigSum'])
+   },
+   ```
+
+3. <strong>mapActions方法:</strong>用于帮助我们生成与```actions```对话的方法,即:包含```$store.dispatch(xxx)```的函数
+
+   ```js
+   methods:{
+       //靠mapActions生成:incrementOdd、incrementWait(对象形式)
+       ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
+   
+       //靠mapActions生成:incrementOdd、incrementWait(数组形式)
+       ...mapActions(['jiaOdd','jiaWait'])
+   }
+   ```
+
+4. <strong>mapMutations方法:</strong>用于帮助我们生成与```mutations```对话的方法,即:包含```$store.commit(xxx)```的函数
+
+   ```js
+   methods:{
+       //靠mapActions生成:increment、decrement(对象形式)
+       ...mapMutations({increment:'JIA',decrement:'JIAN'}),
+       
+       //靠mapMutations生成:JIA、JIAN(对象形式)
+       ...mapMutations(['JIA','JIAN']),
+   }
+   ```
+
+> 备注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。
+
+### 7.模块化+命名空间
+
+1. 目的:让代码更好维护,让多种数据分类更加明确。
+
+2. 修改```store.js```
+
+   ```javascript
+   const countAbout = {
+     namespaced:true,//开启命名空间
+     state:{x:1},
+     mutations: { ... },
+     actions: { ... },
+     getters: {
+       bigSum(state){
+          return state.sum * 10
+       }
+     }
+   }
+   
+   const personAbout = {
+     namespaced:true,//开启命名空间
+     state:{ ... },
+     mutations: { ... },
+     actions: { ... }
+   }
+   
+   const store = new Vuex.Store({
+     modules: {
+       countAbout,
+       personAbout
+     }
+   })
+   ```
+
+3. 开启命名空间后,组件中读取state数据:
+
+   ```js
+   //方式一:自己直接读取
+   this.$store.state.personAbout.list
+   //方式二:借助mapState读取:
+   ...mapState('countAbout',['sum','school','subject']),
+   ```
+
+4. 开启命名空间后,组件中读取getters数据:
+
+   ```js
+   //方式一:自己直接读取
+   this.$store.getters['personAbout/firstPersonName']
+   //方式二:借助mapGetters读取:
+   ...mapGetters('countAbout',['bigSum'])
+   ```
+
+5. 开启命名空间后,组件中调用dispatch
+
+   ```js
+   //方式一:自己直接dispatch
+   this.$store.dispatch('personAbout/addPersonWang',person)
+   //方式二:借助mapActions:
+   ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
+   ```
+
+6. 开启命名空间后,组件中调用commit
+
+   ```js
+   //方式一:自己直接commit
+   this.$store.commit('personAbout/ADD_PERSON',person)
+   //方式二:借助mapMutations:
+   ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
+   ```
+
+ ## 路由
+
+1. 理解: 一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。
+2. 前端路由:key是路径,value是组件。
+
+### 1.基本使用
+
+1. 安装vue-router,命令:```npm i vue-router```
+
+2. 应用插件:```Vue.use(VueRouter)```
+
+3. 编写router配置项:
+
+   ```js
+   //引入VueRouter
+   import VueRouter from 'vue-router'
+   //引入Luyou 组件
+   import About from '../components/About'
+   import Home from '../components/Home'
+   
+   //创建router实例对象,去管理一组一组的路由规则
+   const router = new VueRouter({
+   	routes:[
+   		{
+   			path:'/about',
+   			component:About
+   		},
+   		{
+   			path:'/home',
+   			component:Home
+   		}
+   	]
+   })
+   
+   //暴露router
+   export default router
+   ```
+
+4. 实现切换(active-class可配置高亮样式)
+
+   ```vue
+   <router-link active-class="active" to="/about">About</router-link>
+   ```
+
+5. 指定展示位置
+
+   ```vue
+   <router-view></router-view>
+   ```
+
+### 2.几个注意点
+
+1. 路由组件通常存放在```pages```文件夹,一般组件通常存放在```components```文件夹。
+2. 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
+3. 每个组件都有自己的```$route```属性,里面存储着自己的路由信息。
+4. 整个应用只有一个router,可以通过组件的```$router```属性获取到。
+
+### 3.多级路由(多级路由)
+
+1. 配置路由规则,使用children配置项:
+
+   ```js
+   routes:[
+   	{
+   		path:'/about',
+   		component:About,
+   	},
+   	{
+   		path:'/home',
+   		component:Home,
+   		children:[ //通过children配置子级路由
+   			{
+   				path:'news', //此处一定不要写:/news
+   				component:News
+   			},
+   			{
+   				path:'message',//此处一定不要写:/message
+   				component:Message
+   			}
+   		]
+   	}
+   ]
+   ```
+
+2. 跳转(要写完整路径):
+
+   ```vue
+   <router-link to="/home/news">News</router-link>
+   ```
+
+### 4.路由的query参数
+
+1. 传递参数
+
+   ```vue
+   <!-- 跳转并携带query参数,to的字符串写法 -->
+   <router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>
+   				
+   <!-- 跳转并携带query参数,to的对象写法 -->
+   <router-link 
+   	:to="{
+   		path:'/home/message/detail',
+   		query:{
+   		   id:666,
+               title:'你好'
+   		}
+   	}"
+   >跳转</router-link>
+   ```
+
+2. 接收参数:
+
+   ```js
+   $route.query.id
+   $route.query.title
+   ```
+
+### 5.命名路由
+
+1. 作用:可以简化路由的跳转。
+
+2. 如何使用
+
+   1. 给路由命名:
+
+      ```js
+      {
+      	path:'/demo',
+      	component:Demo,
+      	children:[
+      		{
+      			path:'test',
+      			component:Test,
+      			children:[
+      				{
+                            name:'hello' //给路由命名
+      					path:'welcome',
+      					component:Hello,
+      				}
+      			]
+      		}
+      	]
+      }
+      ```
+
+   2. 简化跳转:
+
+      ```vue
+      <!--简化前,需要写完整的路径 -->
+      <router-link to="/demo/test/welcome">跳转</router-link>
+      
+      <!--简化后,直接通过名字跳转 -->
+      <router-link :to="{name:'hello'}">跳转</router-link>
+      
+      <!--简化写法配合传递参数 -->
+      <router-link 
+      	:to="{
+      		name:'hello',
+      		query:{
+      		   id:666,
+                  title:'你好'
+      		}
+      	}"
+      >跳转</router-link>
+      ```
+
+### 6.路由的params参数
+
+1. 配置路由,声明接收params参数
+
+   ```js
+   {
+   	path:'/home',
+   	component:Home,
+   	children:[
+   		{
+   			path:'news',
+   			component:News
+   		},
+   		{
+   			component:Message,
+   			children:[
+   				{
+   					name:'xiangqing',
+   					path:'detail/:id/:title', //使用占位符声明接收params参数
+   					component:Detail
+   				}
+   			]
+   		}
+   	]
+   }
+   ```
+
+2. 传递参数
+
+   ```vue
+   <!-- 跳转并携带params参数,to的字符串写法 -->
+   <router-link :to="/home/message/detail/666/你好">跳转</router-link>
+   				
+   <!-- 跳转并携带params参数,to的对象写法 -->
+   <router-link 
+   	:to="{
+   		name:'xiangqing',
+   		params:{
+   		   id:666,
+               title:'你好'
+   		}
+   	}"
+   >跳转</router-link>
+   ```
+
+   > 特别注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!,如果是quary参数则不需要
+
+3. 接收参数:
+
+   ```js
+   $route.params.id
+   $route.params.title
+   ```
+
+### 7.路由的props配置
+
+​	作用:让路由组件更方便的收到参数
+
+```js
+{
+	name:'xiangqing',
+	path:'detail/:id',
+	component:Detail,
+
+	//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
+	// props:{a:900}
+
+	//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
+	// props:true
+	
+	//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
+	props(route){
+		return {
+			id:route.query.id,
+			title:route.query.title
+		}
+	}
+}
+```
+
+### 8.```<router-link>```的replace属性
+
+1. 作用:控制路由跳转时操作浏览器历史记录的模式
+2. 浏览器的历史记录有两种写入方式:分别为```push```和```replace```,```push```是追加历史记录,```replace```是替换当前记录。路由跳转时候默认为```push```
+3. 如何开启```replace```模式:```<router-link replace .......>News</router-link>```
+
+### 9.编程式路由导航
+
+1. 作用:不借助```<router-link> ```实现路由跳转,让路由跳转更加灵活
+
+2. 具体编码:
+
+   ```js
+   //$router的两个API
+   this.$router.push({
+   	name:'xiangqing',
+   		params:{
+   			id:xxx,
+   			title:xxx
+   		}
+   })
+   
+   this.$router.replace({
+   	name:'xiangqing',
+   		params:{
+   			id:xxx,
+   			title:xxx
+   		}
+   })
+   this.$router.forward() //前进
+   this.$router.back() //后退
+   this.$router.go() //可前进也可后退
+   ```
+
+### 10.缓存路由组件
+
+1. 作用:让不展示的路由组件保持挂载,不被销毁。
+
+2. 具体编码:
+
+   ```vue
+   <keep-alive include="News"> 
+       <router-view></router-view>
+   </keep-alive>
+   <!-- 缓存多个路由组件 -->
+   <!-- <keep-alive :include="['News','Message']"> -->
+   ```
+
+### 11.两个新的生命周期钩子
+
+1. 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
+2. 具体名字:
+   1. ```activated```路由组件被激活时触发。
+   2. ```deactivated```路由组件失活时触发。
+
+### 12.路由守卫
+
+1. 作用:对路由进行权限控制
+
+2. 分类:全局守卫、独享守卫、组件内守卫
+
+3. 全局守卫:
+
+   ```js
+   //全局前置守卫:初始化时执行、每次路由切换前执行
+   router.beforeEach((to,from,next)=>{
+   	console.log('beforeEach',to,from)
+   	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
+   		if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则
+   			next() //放行
+   		}else{
+   			alert('暂无权限查看')
+   			// next({name:'guanyu'})
+   		}
+   	}else{
+   		next() //放行
+   	}
+   })
+   
+   //全局后置守卫:初始化时执行、每次路由切换后执行
+   router.afterEach((to,from)=>{
+   	console.log('afterEach',to,from)
+   	if(to.meta.title){ 
+   		document.title = to.meta.title //修改网页的title
+   	}else{
+   		document.title = 'vue_test'
+   	}
+   })
+   ```
+
+4. 独享守卫:(只有前置没有后置)
+
+   ```js
+   // 在routes中使用,不用单独写在外面
+   beforeEnter(to,from,next){
+   	console.log('beforeEnter',to,from)
+   	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
+   		if(localStorage.getItem('school') === 'atguigu'){
+   			next()
+   		}else{
+   			alert('暂无权限查看')
+   			// next({name:'guanyu'})
+   		}
+   	}else{
+   		next()
+   	}
+   }
+   ```
+
+5. 组件内守卫:
+
+   ```js
+   //进入守卫:通过路由规则,进入该组件时被调用
+   beforeRouteEnter (to, from, next) {
+   },
+   //离开守卫:通过路由规则,离开该组件时被调用
+   beforeRouteLeave (to, from, next) {
+   }
+   ```
+
+### 13.路由器的两种工作模式
+
+
+
+1. 对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
+2. hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
+3. hash模式:
+   1. 地址中永远带着#号,不美观 。
+   2. 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
+   3. 兼容性较好。
+4. history模式:
+   1. 地址干净,美观 。
+   2. 兼容性和hash模式相比略差。
+   3. 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。
+	
+	 

+ 701 - 0
前端/vue/vue3快速上手.md

@@ -0,0 +1,701 @@
+# Vue3快速上手
+
+<img src="https://user-images.githubusercontent.com/499550/93624428-53932780-f9ae-11ea-8d16-af949e16a09f.png" style="width:200px" />
+
+
+
+## 1.Vue3简介
+
+- 2020年9月18日,Vue.js发布3.0版本,代号:One Piece(海贼王)
+- 耗时2年多、[2600+次提交](https://github.com/vuejs/vue-next/graphs/commit-activity)、[30+个RFC](https://github.com/vuejs/rfcs/tree/master/active-rfcs)、[600+次PR](https://github.com/vuejs/vue-next/pulls?q=is%3Apr+is%3Amerged+-author%3Aapp%2Fdependabot-preview+)、[99位贡献者](https://github.com/vuejs/vue-next/graphs/contributors) 
+- github上的tags地址:https://github.com/vuejs/vue-next/releases/tag/v3.0.0
+
+## 2.Vue3带来了什么
+
+### 1.性能的提升
+
+- 打包大小减少41%
+
+- 初次渲染快55%, 更新渲染快133%
+
+- 内存减少54%
+
+  ......
+
+### 2.源码的升级
+
+- 使用Proxy代替defineProperty实现响应式
+
+- 重写虚拟DOM的实现和Tree-Shaking
+
+  ......
+
+### 3.拥抱TypeScript
+
+- Vue3可以更好的支持TypeScript
+
+### 4.新的特性
+
+1. Composition API(组合API)
+
+   - setup配置
+   - ref与reactive
+   - watch与watchEffect
+   - provide与inject
+   - ......
+2. 新的内置组件
+   - Fragment 
+   - Teleport
+   - Suspense
+3. 其他改变
+
+   - 新的生命周期钩子
+   - data 选项应始终被声明为一个函数
+   - 移除keyCode支持作为 v-on 的修饰符
+   - ......
+
+# 一、创建Vue3.0工程
+
+## 1.使用 vue-cli 创建
+
+官方文档:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create
+
+```bash
+## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
+vue --version
+## 安装或者升级你的@vue/cli
+npm install -g @vue/cli
+## 创建
+vue create vue_test
+## 启动
+cd vue_test
+npm run serve
+```
+
+## 2.使用 vite 创建
+
+官方文档:https://v3.cn.vuejs.org/guide/installation.html#vite
+
+vite官网:https://vitejs.cn
+
+- 什么是vite?—— 新一代前端构建工具。
+- 优势如下:
+  - 开发环境中,无需打包操作,可快速的冷启动。
+  - 轻量快速的热重载(HMR)。
+  - 真正的按需编译,不再等待整个应用编译完成。
+- 传统构建 与 vite构建对比图
+
+<img src="https://cn.vitejs.dev/assets/bundler.37740380.png" style="width:500px;height:280px;float:left" /><img src="https://cn.vitejs.dev/assets/esm.3070012d.png" style="width:480px;height:280px" />
+
+```bash
+## 创建工程
+npm init vite-app <project-name>
+## 进入工程目录
+cd <project-name>
+## 安装依赖
+npm install
+## 运行
+npm run dev
+```
+
+# 二、常用 Composition API
+
+官方文档: https://v3.cn.vuejs.org/guide/composition-api-introduction.html
+
+## 1.拉开序幕的setup
+
+1. 理解:Vue3.0中一个新的配置项,值为一个函数。
+2. setup是所有<strong style="color:#DD5145">Composition API(组合API)</strong><i style="color:gray;font-weight:bold">“ 表演的舞台 ”</i>。
+4. 组件中所用到的:数据、方法等等,均要配置在setup中。
+5. setup函数的两种返回值:
+   1. 若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。(重点关注!)
+   2. <span style="color:#aad">若返回一个渲染函数:则可以自定义渲染内容。(了解)</span>
+6. 注意点:
+   1. 尽量不要与Vue2.x配置混用
+      - Vue2.x配置(data、methos、computed...)中<strong style="color:#DD5145">可以访问到</strong>setup中的属性、方法。
+      - 但在setup中<strong style="color:#DD5145">不能访问到</strong>Vue2.x配置(data、methos、computed...)。
+      - 如果有重名, setup优先。
+   2. setup不能是一个async函数,因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)
+
+##  2.ref函数
+
+- 作用: 定义一个响应式的数据
+- 语法: ```const xxx = ref(initValue)``` 
+  - 创建一个包含响应式数据的<strong style="color:#DD5145">引用对象(reference对象,简称ref对象)</strong>。
+  - JS中操作数据: ```xxx.value```
+  - 模板中读取数据: 不需要.value,直接:```<div>{{xxx}}</div>```
+- 备注:
+  - 接收的数据可以是:基本类型、也可以是对象类型。
+  - 基本类型的数据:响应式依然是靠``Object.defineProperty()``的```get```与```set```完成的。
+  - 对象类型的数据:内部 <i style="color:gray;font-weight:bold">“ 求助 ”</i> 了Vue3.0中的一个新函数—— ```reactive```函数。
+
+## 3.reactive函数
+
+- 作用: 定义一个<strong style="color:#DD5145">对象类型</strong>的响应式数据(基本类型不要用它,要用```ref```函数)
+- 语法:```const 代理对象= reactive(源对象)```接收一个对象(或数组),返回一个<strong style="color:#DD5145">代理对象(Proxy的实例对象,简称proxy对象)</strong>
+- reactive定义的响应式数据是“深层次的”。
+- 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。
+
+## 4.Vue3.0中的响应式原理
+
+### vue2.x的响应式
+
+- 实现原理:
+  - 对象类型:通过```Object.defineProperty()```对属性的读取、修改进行拦截(数据劫持)。
+  
+  - 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
+  
+    ```js
+    Object.defineProperty(data, 'count', {
+        get () {}, 
+        set () {}
+    })
+    ```
+
+- 存在问题:
+  - 新增属性、删除属性, 界面不会更新。
+  - 直接通过下标修改数组, 界面不会自动更新。
+
+### Vue3.0的响应式
+
+- 实现原理: 
+  - 通过Proxy(代理):  拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
+  - 通过Reflect(反射):  对源对象的属性进行操作。
+  - MDN文档中描述的Proxy与Reflect:
+    - Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
+    
+    - Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
+    
+      ```js
+      new Proxy(data, {
+      	// 拦截读取属性值
+          get (target, prop) {
+          	return Reflect.get(target, prop)
+          },
+          // 拦截设置属性值或添加新属性
+          set (target, prop, value) {
+          	return Reflect.set(target, prop, value)
+          },
+          // 拦截删除属性
+          deleteProperty (target, prop) {
+          	return Reflect.deleteProperty(target, prop)
+          }
+      })
+      
+      proxy.name = 'tom'   
+      ```
+
+## 5.reactive对比ref
+
+-  从定义数据角度对比:
+   -  ref用来定义:<strong style="color:#DD5145">基本类型数据</strong>。
+   -  reactive用来定义:<strong style="color:#DD5145">对象(或数组)类型数据</strong>。
+   -  备注:ref也可以用来定义<strong style="color:#DD5145">对象(或数组)类型数据</strong>, 它内部会自动通过```reactive```转为<strong style="color:#DD5145">代理对象</strong>。
+-  从原理角度对比:
+   -  ref通过``Object.defineProperty()``的```get```与```set```来实现响应式(数据劫持)。
+   -  reactive通过使用<strong style="color:#DD5145">Proxy</strong>来实现响应式(数据劫持), 并通过<strong style="color:#DD5145">Reflect</strong>操作<strong style="color:orange">源对象</strong>内部的数据。
+-  从使用角度对比:
+   -  ref定义的数据:操作数据<strong style="color:#DD5145">需要</strong>```.value```,读取数据时模板中直接读取<strong style="color:#DD5145">不需要</strong>```.value```。
+   -  reactive定义的数据:操作数据与读取数据:<strong style="color:#DD5145">均不需要</strong>```.value```。
+
+## 6.setup的两个注意点
+
+- setup执行的时机
+  - 在beforeCreate之前执行一次,this是undefined。
+  
+- setup的参数
+  - props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
+  - context:上下文对象
+    - attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 ```this.$attrs```。
+    - slots: 收到的插槽内容, 相当于 ```this.$slots```。
+    - emit: 分发自定义事件的函数, 相当于 ```this.$emit```。
+
+
+## 7.计算属性与监视
+
+### 1.computed函数
+
+- 与Vue2.x中computed配置功能一致
+
+- 写法
+
+  ```js
+  import {computed} from 'vue'
+  
+  setup(){
+      ...
+  	//计算属性——简写
+      let fullName = computed(()=>{
+          return person.firstName + '-' + person.lastName
+      })
+      //计算属性——完整
+      let fullName = computed({
+          get(){
+              return person.firstName + '-' + person.lastName
+          },
+          set(value){
+              const nameArr = value.split('-')
+              person.firstName = nameArr[0]
+              person.lastName = nameArr[1]
+          }
+      })
+  }
+  ```
+
+### 2.watch函数
+
+- 与Vue2.x中watch配置功能一致
+
+- 两个小“坑”:
+
+  - 监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)。
+  - 监视reactive定义的响应式数据中某个属性时:deep配置有效。
+  
+  ```js
+  //情况一:监视ref定义的响应式数据
+  watch(sum,(newValue,oldValue)=>{
+  	console.log('sum变化了',newValue,oldValue)
+  },{immediate:true})
+  
+  //情况二:监视多个ref定义的响应式数据
+  watch([sum,msg],(newValue,oldValue)=>{
+  	console.log('sum或msg变化了',newValue,oldValue)
+  }) 
+  
+  /* 情况三:监视reactive定义的响应式数据
+  			若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!!
+  			若watch监视的是reactive定义的响应式数据,则强制开启了深度监视 
+  */
+  watch(person,(newValue,oldValue)=>{
+  	console.log('person变化了',newValue,oldValue)
+  },{immediate:true,deep:false}) //此处的deep配置不再奏效
+  
+  //情况四:监视reactive定义的响应式数据中的某个属性
+  watch(()=>person.job,(newValue,oldValue)=>{
+  	console.log('person的job变化了',newValue,oldValue)
+  },{immediate:true,deep:true}) 
+  
+  //情况五:监视reactive定义的响应式数据中的某些属性
+  watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
+  	console.log('person的job变化了',newValue,oldValue)
+  },{immediate:true,deep:true})
+  
+  //特殊情况
+  watch(()=>person.job,(newValue,oldValue)=>{
+      console.log('person的job变化了',newValue,oldValue)
+  },{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
+  ```
+
+### 3.watchEffect函数
+
+- watch的套路是:既要指明监视的属性,也要指明监视的回调。
+
+- watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
+
+- watchEffect有点像computed:
+
+  - 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。
+  - 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
+
+  ```js
+  //watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
+  watchEffect(()=>{
+      const x1 = sum.value
+      const x2 = person.age
+      console.log('watchEffect配置的回调执行了')
+  })
+  ```
+
+## 8.生命周期
+
+<div style="border:1px solid black;width:380px;float:left;margin-right:20px;"><strong>vue2.x的生命周期</strong><img src="https://cn.vuejs.org/images/lifecycle.png" alt="lifecycle_2" style="zoom:33%;width:1200px" /></div><div style="border:1px solid black;width:510px;height:985px;float:left"><strong>vue3.0的生命周期</strong><img src="https://v3.cn.vuejs.org/images/lifecycle.svg" alt="lifecycle_2" style="zoom:33%;width:2500px" /></div>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1
+
+- Vue3.0中可以继续使用Vue2.x中的生命周期钩子,但有有两个被更名:
+  - ```beforeDestroy```改名为 ```beforeUnmount```
+  - ```destroyed```改名为 ```unmounted```
+- Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:
+  - `beforeCreate`===>`setup()`
+  - `created`=======>`setup()`
+  - `beforeMount` ===>`onBeforeMount`
+  - `mounted`=======>`onMounted`
+  - `beforeUpdate`===>`onBeforeUpdate`
+  - `updated` =======>`onUpdated`
+  - `beforeUnmount` ==>`onBeforeUnmount`
+  - `unmounted` =====>`onUnmounted`
+
+## 9.自定义hook函数
+
+- 什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装。
+
+- 类似于vue2.x中的mixin。
+
+- 自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。
+
+
+
+## 10.toRef
+
+- 作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性。
+- 语法:```const name = toRef(person,'name')```
+- 应用:   要将响应式对象中的某个属性单独提供给外部使用时。
+
+
+- 扩展:```toRefs``` 与```toRef```功能一致,但可以批量创建多个 ref 对象,语法:```toRefs(person)```
+
+
+# 三、其它 Composition API
+
+## 1.shallowReactive 与 shallowRef
+
+- shallowReactive:只处理对象最外层属性的响应式(浅响应式)。
+- shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。
+
+- 什么时候使用?
+  -  如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===> shallowReactive。
+  -  如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===> shallowRef。
+
+## 2.readonly 与 shallowReadonly
+
+- readonly: 让一个响应式数据变为只读的(深只读)。
+- shallowReadonly:让一个响应式数据变为只读的(浅只读)。
+- 应用场景: 不希望数据被修改时。
+
+## 3.toRaw 与 markRaw
+
+- toRaw:
+  - 作用:将一个由```reactive```生成的<strong style="color:orange">响应式对象</strong>转为<strong style="color:orange">普通对象</strong>。
+  - 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。
+- markRaw:
+  - 作用:标记一个对象,使其永远不会再成为响应式对象。
+  - 应用场景:
+    1. 有些值不应被设置为响应式的,例如复杂的第三方类库等。
+    2. 当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。
+
+## 4.customRef
+
+- 作用:创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。
+
+- 实现防抖效果:
+
+  ```vue
+  <template>
+  	<input type="text" v-model="keyword">
+  	<h3>{{keyword}}</h3>
+  </template>
+  
+  <script>
+  	import {ref,customRef} from 'vue'
+  	export default {
+  		name:'Demo',
+  		setup(){
+  			// let keyword = ref('hello') //使用Vue准备好的内置ref
+  			//自定义一个myRef
+  			function myRef(value,delay){
+  				let timer
+  				//通过customRef去实现自定义
+  				return customRef((track,trigger)=>{
+  					return{
+  						get(){
+  							track() //告诉Vue这个value值是需要被“追踪”的
+  							return value
+  						},
+  						set(newValue){
+  							clearTimeout(timer)
+  							timer = setTimeout(()=>{
+  								value = newValue
+  								trigger() //告诉Vue去更新界面
+  							},delay)
+  						}
+  					}
+  				})
+  			}
+  			let keyword = myRef('hello',500) //使用程序员自定义的ref
+  			return {
+  				keyword
+  			}
+  		}
+  	}
+  </script>
+  ```
+
+  
+
+## 5.provide 与 inject
+
+<img src="https://v3.cn.vuejs.org/images/components_provide.png" style="width:300px" />
+
+- 作用:实现<strong style="color:#DD5145">祖与后代组件间</strong>通信
+
+- 套路:父组件有一个 `provide` 选项来提供数据,后代组件有一个 `inject` 选项来开始使用这些数据
+
+- 具体写法:
+
+  1. 祖组件中:
+
+     ```js
+     setup(){
+     	......
+         let car = reactive({name:'奔驰',price:'40万'})
+         provide('car',car)
+         ......
+     }
+     ```
+
+  2. 后代组件中:
+
+     ```js
+     setup(props,context){
+     	......
+         const car = inject('car')
+         return {car}
+     	......
+     }
+     ```
+
+## 6.响应式数据的判断
+
+- isRef: 检查一个值是否为一个 ref 对象
+- isReactive: 检查一个对象是否是由 `reactive` 创建的响应式代理
+- isReadonly: 检查一个对象是否是由 `readonly` 创建的只读代理
+- isProxy: 检查一个对象是否是由 `reactive` 或者 `readonly` 方法创建的代理
+
+# 四、Composition API 的优势
+
+## 1.Options API 存在的问题
+
+使用传统OptionsAPI中,新增或者修改一个需求,就需要分别在data,methods,computed里修改 。
+
+<div style="width:600px;height:370px;overflow:hidden;float:left">
+    <img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f84e4e2c02424d9a99862ade0a2e4114~tplv-k3u1fbpfcp-watermark.image" style="width:600px;float:left" />
+</div>
+<div style="width:300px;height:370px;overflow:hidden;float:left">
+    <img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e5ac7e20d1784887a826f6360768a368~tplv-k3u1fbpfcp-watermark.image" style="zoom:50%;width:560px;left" /> 
+</div>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## 2.Composition API 的优势
+
+我们可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。
+
+<div style="width:500px;height:340px;overflow:hidden;float:left">
+    <img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bc0be8211fc54b6c941c036791ba4efe~tplv-k3u1fbpfcp-watermark.image"style="height:360px"/>
+</div>
+<div style="width:430px;height:340px;overflow:hidden;float:left">
+    <img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6cc55165c0e34069a75fe36f8712eb80~tplv-k3u1fbpfcp-watermark.image"style="height:360px"/>
+</div>
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 五、新的组件
+
+## 1.Fragment
+
+- 在Vue2中: 组件必须有一个根标签
+- 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
+- 好处: 减少标签层级, 减小内存占用
+
+## 2.Teleport
+
+- 什么是Teleport?—— `Teleport` 是一种能够将我们的<strong style="color:#DD5145">组件html结构</strong>移动到指定位置的技术。
+
+  ```vue
+  <teleport to="移动位置">
+  	<div v-if="isShow" class="mask">
+  		<div class="dialog">
+  			<h3>我是一个弹窗</h3>
+  			<button @click="isShow = false">关闭弹窗</button>
+  		</div>
+  	</div>
+  </teleport>
+  ```
+
+## 3.Suspense
+
+- 等待异步组件时渲染一些额外内容,让应用有更好的用户体验
+
+- 使用步骤:
+
+  - 异步引入组件
+
+    ```js
+    import {defineAsyncComponent} from 'vue'
+    const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
+    ```
+
+  - 使用```Suspense```包裹组件,并配置好```default``` 与 ```fallback```
+
+    ```vue
+    <template>
+    	<div class="app">
+    		<h3>我是App组件</h3>
+    		<Suspense>
+    			<template v-slot:default>
+    				<Child/>
+    			</template>
+    			<template v-slot:fallback>
+    				<h3>加载中.....</h3>
+    			</template>
+    		</Suspense>
+    	</div>
+    </template>
+    ```
+
+# 六、其他
+
+## 1.全局API的转移
+
+- Vue 2.x 有许多全局 API 和配置。
+  - 例如:注册全局组件、注册全局指令等。
+
+    ```js
+    //注册全局组件
+    Vue.component('MyButton', {
+      data: () => ({
+        count: 0
+      }),
+      template: '<button @click="count++">Clicked {{ count }} times.</button>'
+    })
+    
+    //注册全局指令
+    Vue.directive('focus', {
+      inserted: el => el.focus()
+    }
+    ```
+
+- Vue3.0中对这些API做出了调整:
+
+  - 将全局的API,即:```Vue.xxx```调整到应用实例(```app```)上
+
+    | 2.x 全局 API(```Vue```) | 3.x 实例 API (`app`)                        |
+    | ------------------------- | ------------------------------------------- |
+    | Vue.config.xxxx           | app.config.xxxx                             |
+    | Vue.config.productionTip  | <strong style="color:#DD5145">移除</strong> |
+    | Vue.component             | app.component                               |
+    | Vue.directive             | app.directive                               |
+    | Vue.mixin                 | app.mixin                                   |
+    | Vue.use                   | app.use                                     |
+    | Vue.prototype             | app.config.globalProperties                 |
+  
+
+## 2.其他改变
+
+- data选项应始终被声明为一个函数。
+
+- 过度类名的更改:
+
+  - Vue2.x写法
+
+    ```css
+    .v-enter,
+    .v-leave-to {
+      opacity: 0;
+    }
+    .v-leave,
+    .v-enter-to {
+      opacity: 1;
+    }
+    ```
+
+  - Vue3.x写法
+
+    ```css
+    .v-enter-from,
+    .v-leave-to {
+      opacity: 0;
+    }
+    
+    .v-leave-from,
+    .v-enter-to {
+      opacity: 1;
+    }
+    ```
+
+- <strong style="color:#DD5145">移除</strong>keyCode作为 v-on 的修饰符,同时也不再支持```config.keyCodes```
+
+- <strong style="color:#DD5145">移除</strong>```v-on.native```修饰符
+
+  - 父组件中绑定事件
+
+    ```vue
+    <my-component
+      v-on:close="handleComponentEvent"
+      v-on:click="handleNativeClickEvent"
+    />
+    ```
+
+  - 子组件中声明自定义事件
+
+    ```vue
+    <script>
+      export default {
+        emits: ['close']
+      }
+    </script>
+    ```
+
+- <strong style="color:#DD5145">移除</strong>过滤器(filter)
+
+  > 过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设,这不仅有学习成本,而且有实现成本!建议用方法调用或计算属性去替换过滤器。
+
+- ......

+ 1 - 1
前端/前端部署问题/nginx部署的问题.md

@@ -28,7 +28,7 @@ server {
  
         location / {
         	# 不修改此处,确保用户直接输入ip+端口无法访问到系统
-            root   html;
+            root   html/in;
             index  index.html index.htm;
         }
         location /dist {

+ 7 - 7
后端/JAVA高阶/HashMap/第三节ConcurrentHashMap1.7.md

@@ -33,7 +33,7 @@ segment的加载因子,就是table的加载因子
 
 ## 无参构造源码分析
 
-```
+```java
     public ConcurrentHashMap(int initialCapacity,
                              float loadFactor, int concurrencyLevel) {
         if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
@@ -42,7 +42,7 @@ segment的加载因子,就是table的加载因子
         if (concurrencyLevel > MAX_SEGMENTS)
             concurrencyLevel = MAX_SEGMENTS;
         // Find power-of-two sizes best matching arguments
-        // 计算出ssize2的平的个数
+        // 计算出ssize2的平的个数
         int sshift = 0;
         // segment数组容量
         int ssize = 1;
@@ -66,7 +66,7 @@ segment的加载因子,就是table的加载因子
         while (cap < c)
             cap <<= 1;
         // create segments and segments[0]
-        // 创建一个segment s0对象,放入下标为0的位置。默认大小为2,默认扩容大小为1,加载因子为075f
+        // 创建一个segment s0对象,放入下标为0的位置。默认大小为2,默认扩容大小为1,加载因子为0.75f
         // 为什么在构造函数初始化s0?  方便后期其他key落到不同的segment中,能够知道加载因子,和默认容量一些基本参数,就是相当于提供了一个模板
         Segment<K,V> s0 =
             new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
@@ -80,7 +80,7 @@ segment的加载因子,就是table的加载因子
 
 ## 1.7put源码解析
 
-```
+```java
     @SuppressWarnings("unchecked")
     public V put(K key, V value) {
         Segment<K,V> s;
@@ -105,7 +105,7 @@ segment的加载因子,就是table的加载因子
 
 
 ## ensureSegment函数解析
-```
+```java
     @SuppressWarnings("unchecked")
     private Segment<K,V> ensureSegment(int k) {
         final Segment<K,V>[] ss = this.segments;
@@ -146,7 +146,7 @@ seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null
 
 解析``` return s.put(key, hash, value, false);```这一句话
 
-```
+```java
 final V put(K key, int hash, V value, boolean onlyIfAbsent) {
     HashEntry<K,V> node = tryLock() ? null :
             scanAndLockForPut(key, hash, value);
@@ -206,7 +206,7 @@ final V put(K key, int hash, V value, boolean onlyIfAbsent) {
 
 ## put方法没有抢到锁
 
-```
+```java
 private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
 	// 找到链表的位置
     HashEntry<K,V> first = entryForHash(this, hash);

+ 6 - 5
后端/JAVA高阶/HashMap/第二节课HashMap源码分析.md

@@ -16,7 +16,7 @@ static final int UNTREEIFY_THRESHOLD = 6;
 static final int MIN_TREEIFY_CAPACITY = 64;
 
 底层采用单向链表
-```
+```java
 final int hash;
 final K key;
 V value;
@@ -24,7 +24,8 @@ Node<K,V> next;
 ```
 为什么要将key的hash值保存起来?
 下次扩容的时候,能够计算该key在新的table中index值
-```
+
+```java
 // transient不能被序列化
 transient Node<K,V>[] table;
 transient int size;
@@ -36,7 +37,7 @@ final float loadFactor;
 
 ## 分析hashmap的put方法底层实现原理
 
-```
+```java
 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                    boolean evict) {
         // n是当前table数组的长度,i就是index下标位。table和p临时table大小接受
@@ -129,7 +130,7 @@ resize();
 
 ### 1.7版本的扩容
 
-```
+```java
 void transfer(Entry[] newTable, boolean rehash) {
     int newCapacity = newTable.length;
     // 遍历原来宿主中所有的链表
@@ -165,7 +166,7 @@ hashmap1.8	16<<1=32
 
 ### 1.8版本的扩容
 
-```
+```java
 // 查找所有链表
 for (int j = 0; j < oldCap; ++j) {
 	Node<K,V> e;

+ 3 - 3
后端/JAVA高阶/HashMap/第四节ConcurrentHashMap1.8.md

@@ -15,7 +15,7 @@ ConcurrentHashMap:对node节点上锁
 
 ## put方法详解 
 
-```
+```java
 final V putVal(K key, V value, boolean onlyIfAbsent) {
 	// 不支持key为空
     if (key == null || value == null) throw new NullPointerException();
@@ -98,7 +98,7 @@ synchronized使用:index发生冲突的时候
 
 ## 初始化table原理
 
-```
+```java
     private final Node<K,V>[] initTable() {
         Node<K,V>[] tab; int sc;
         // 自旋
@@ -138,7 +138,7 @@ N:表示有N-1个线程正在进行扩容操作
 
 ## addCount分析
 
-```
+```java
 private final void addCount(long x, int check) {
     CounterCell[] as; long b, s;
     // basecount就是size的大小

+ 2 - 2
后端/JAVA高阶/JUC编程/Threadlocal.md

@@ -31,7 +31,7 @@ B. Threadlocal在每个线程中都有自己独立的局部变量,空间换时
 Key 为 当前 new ThreadLocal 对象,value 就是为 object 变量值。
 ![image-20211101152903627](../../../照片/image-20211101152903627.png)
 
-```
+```java
 	// Threadlocal的set方法
     public void set(T value) {
         Thread t = Thread.currentThread();
@@ -85,7 +85,7 @@ threadLocalMap.get(ThreadLocal)-----缓存变量值
 
 1. 可以自己调用 remove 方法将不要的数据移除避免内存泄漏的问题;
 2. 每次在做 set 方法的时候会清除之前 key 为 null;
-```
+```java
             for (Entry e = tab[i];
                  e != null;
                  e = tab[i = nextIndex(i, len)]) {

+ 50 - 24
大数据/云平台安装文档/安装云平台环境.md

@@ -128,14 +128,14 @@ docker-compose --version
 
 ## 3.1安装Harbor
 
-1. 将压缩包harbor-offline-installer-v2.3.2.tgz上传到
+1. 将压缩包harbor-offline-installer-v2.1.5.tgz上传到
 ```
 /opt/package/
 ```
 目录下
 2. 解压该压缩包
 ```
-tar xf harbor-offline-installer-v2.3.2.tgz
+tar xf harbor-offline-installer-v2.1.5.tgz
 ```
 3. 修改harbor安装的配置文件
 
@@ -144,10 +144,10 @@ tar xf harbor-offline-installer-v2.3.2.tgz
 # 复制配置文件内容到harbor.yml 中(安装时只识别harbor.yml)
 cp harbor.yml.tmpl  harbor.yml         
 # 用于存放harbor的持久化数据
-mkdir -p /home/mkcloud/software/harbor/data       
+mkdir -p /opt/package/harbor/data       
 
 # 用于存放harbor的日志
-mkdir -p /home/mkcloud/software/harbor/log
+mkdir -p /opt/package/harbor/log
 ```
 
 其次对harbor.yml文件进行修改配置
@@ -168,10 +168,10 @@ http:
   # certificate: /your/certificate/path
   # private_key: /your/private/key/path
   
-data_volume: /home/mkcloud/software/harbor/data   # 需要添加一个自己的目录
+data_volume: /opt/package/harbor/data     # 需要添加一个自己的目录
 
 log:
-    location: /home/mkcloud/software/harbor/log  # 需要添加一个自己的目录
+    location:  /opt/package/harbor/log  # 需要添加一个自己的目录
 ```
 
 4. 安装并启动Harbor
@@ -196,7 +196,7 @@ echo "10.168.59.60  server.harbor.com">> /etc/hosts
 ```
 
 docker添加harbor配置-----注意这里要加harbor的端口号,这里配置的端口号为上述harbor配置文件的端口号
-```
+```shell
 mkdir -p /etc/docker
 
 tee /etc/docker/daemon.json <<-'EOF'
@@ -205,6 +205,17 @@ tee /etc/docker/daemon.json <<-'EOF'
 }
 EOF
 
+systemctl daemon-reload && systemctl restart docker
+
+# 如果是ip方式
+mkdir -p /etc/docker
+
+tee /etc/docker/daemon.json <<-'EOF'
+{
+  "insecure-registries": ["192.168.238.20:80"]
+}
+EOF
+
 systemctl daemon-reload && systemctl restart docker
 ```
 
@@ -233,7 +244,7 @@ scp -r kube1.9.0.tar.gz root@192.168.238.22:/opt/package/k8s
 
 ## 4.2 解压安装主从
 
-```
+```shell
 # 1.master下,进入/opt/package/k8s目录下解压,执行脚本
 tar -zxvf kube1.9.0.tar.gz
 cd kube/shell 
@@ -248,9 +259,9 @@ tar -zxvf kube1.9.0.tar.gz
 cd kube/shell 
 init.sh
 
-# 4. 进入master将/etc/kubernetes/admin.conf文件复制到node1节点和node2节点
-scp -r /etc/kubernetes/admin.conf root@192.168.238.21:/etc/kubernetes
-scp -r /etc/kubernetes/admin.conf root@192.168.238.22:/etc/kubernetes
+# 4. 进入master节点将/etc/kubernetes/admin.conf文件复制到node1节点和node2节点
+scp -r /etc/kubernetes/admin.conf node1:/etc/kubernetes/
+scp -r /etc/kubernetes/admin.conf node2:/etc/kubernetes/
    
 ```
 
@@ -298,6 +309,20 @@ scp -r /etc/kubernetes/admin.conf root@192.168.238.22:/etc/kubernetes
       
       Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
       ```
+      
+3. 给node1和node2添加执行权限
+
+```shell
+# 在node1和node2执行一下命令
+mkdir -p $HOME/.kube
+sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
+sudo chown $(id -u):$(id -g) $HOME/.kube/config
+kubectl get nodes
+# 注意上面的admin.conf是从master节点复制过来的
+```
+
+   
+
 
 ## 4.4 验证集群pod是否running,各节点是否ready
 
@@ -344,9 +369,9 @@ kubectl get nodes
 1. 将本地nfs离线包上传至服务器及各个节点的/opt/package/nfs文件夹下
 
    ```shell
-   scp -r nfs root@192.168.238.20:/opt/package
-   scp -r nfs root@192.168.238.21:/opt/package
-   scp -r nfs root@192.168.238.22:/opt/package
+   scp -r nfs master:/opt/package
+   scp -r nfs node1:/opt/package
+   scp -r nfs n:/opt/package
    ```
    
 2. 安装服务端(master节点操作)
@@ -356,7 +381,7 @@ kubectl get nodes
    # 进入/opt/package/nfs
    cd /opt/package/nfs
    # 安装nfs
-   yum rpm -ivh nfs-utils-1.3.0-0.68.el7.2.x86_64.rpm
+   rpm -ivh nfs-utils-1.3.0-0.68.el7.2.x86_64.rpm
    # 执行命令 vi /etc/exports,创建 exports 文件,文件内容如下:
    echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports
    # 执行以下命令,启动 nfs 服务
@@ -370,13 +395,13 @@ kubectl get nodes
    # 检查配置是否生效
    exportfs
    # 输出结果如下所示
-   /nfs/data * 
+   /nfs/data     	<world>
    ```
 3. 安装NFS客户端(三台服务机操作)
 ```shell
 # 进入node1,node2节点内/opt/package/nfs文件夹内执行以下命令
 cd /opt/package/nfs
-yum rpm -ivh nfs-utils-1.3.0-0.68.el7.2.x86_64.rpm
+rpm -ivh nfs-utils-1.3.0-0.68.el7.2.x86_64.rpm
 systemctl start nfs && systemctl enable nfs
 ```
 
@@ -387,7 +412,7 @@ cd /opt/package/nfs
 # 2.载入docker镜像
 docker load < nfs-client-provisioner.tar.gz
 # 3.修改deployment.yaml文件
-vim /root/nfs/deployment.yaml
+vim /opt/package/nfs/deployment.yaml
 
 apiVersion: apps/v1
 kind: Deployment
@@ -467,13 +492,14 @@ managed-nfs-storage (default)   fuseim.pri/ifs   Delete          Immediate
 新建一个kubesphere项目
 ![image-20211111101212415](assets/image-20211111101212415.png)
 
-```
+```shell
 # 在服务机master节点中执行命令
 
 # 进入该路径
 cd /opt/package/kubesphere/
 
 # 上传安装包 这里的最后一行改成自己harbor仓库的ip+端口号+项目名称
+chmod +x offline-installation-tool.sh
 ./offline-installation-tool.sh -l images-list.txt -d ./kubesphere-images -r server.harbor.com:80/kubesphere
 # 等待上传完毕
 ```
@@ -481,7 +507,7 @@ cd /opt/package/kubesphere/
 
 ## 5.2最小化安装kubesphere
 
-```
+```shell
 # 执行以下命令
 # 1.编辑cluster-configuration.yaml添加您的私有镜像仓库
 vim cluster-configuration.yaml
@@ -502,14 +528,14 @@ kubectl get pods -A
 ![image-20211110231108730](assets/image-20211110231108730-16365570741011.png)
 ![image-20211110231233626](assets/image-20211110231233626.png)
 
-```
+```shell
 # 4.等待ks-installer容器运行完毕,执行
 kubectl apply -f cluster-configuration.yaml
 ```
 
 ## 5.3检查安装日志
 
-```
+```shell
 # 检查安装日志等待安装成功
 kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l app=ks-install -o jsonpath='{.items[0].metadata.name}') -f
 ```
@@ -596,7 +622,7 @@ Error response from daemon: login attempt to https://server.harbor.com/v2/ faile
 ```shell
 #修改方式如下
 #1.进入harbor仓库位置
-cd /home/mkcloud/software/harbor
+cd /opt/package/software/harbor
 #2.修改配置文件
 vim ./common/config/portal/nginx.conf
 #3.增加一个字段
@@ -624,7 +650,7 @@ docker restart e39629e9c2c4
 | centos         | 7.7     |
 | docker         | 19.03.7 |
 | docker-compose | 2.1.0   |
-| Harbor         | 2.3.2   |
+| Harbor         | 2.1.5   |
 | kubernetes,    | 1.19.0  |
 | kubesphere     | 3.1.1   |