# vue3-dome
**Repository Path**: Xbaiss/vue3-dome
## Basic Information
- **Project Name**: vue3-dome
- **Description**: 学习vue3的特性
- **Primary Language**: JavaScript
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2021-02-03
- **Last Updated**: 2022-04-28
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# vue3-dome
# 介绍
学习vue3的特性。vue3.x bate(测试版本) 发布2020年9月19日,在vue2.x的基础上进行一些优化,对typescript有更好的支持。
vue3.x语法和vue2.x非常相似。
vue3.x git地址:https://github.com/vuejs/vue-next
vue3.x 文档地址:https://v3.vuejs.org
# 安装vue官方脚手架以及创建项目
提供2个脚手架 创建方式,vue-cli 和vite等脚手架,推荐vue-cli
vue-cli 创建项目
vue create study-vue3 (@vue/cli版本是4.5.8就有选择 vue3的默认项目 )
# 视频教程
https://www.bilibili.com/video/BV1ra4y1H7ih?p=48[尚硅谷]
https://www.bilibili.com/video/BV1j5411n7m5?p=6[黑马程序员]
https://www.bilibili.com/video/BV1nz4y1k7eb?p=23[it]
文档:
https://www.cnblogs.com/wjlynew/p/13929818.html[深入 Vue 3 响应性原理]
# vue的基本语法
## 绑定数据,绑定html,绑定属性,循环数据
1. 绑定数据
{{mgs}}
2. 绑定HTML
data(){
return {
h2:"
this.$refs.ss
## 表达式
1. 三元
{{flag=='false'?" this is false":"this is true"}}
:class="[lineAnimated==false?'tab__item-title':'item']"
:class="{active: (selectedCourse === c)}"
:style="{backgroundColor: (selectedCourse === c)?'#ddd':'transparent'}"
:style="{backgroundImage: 'url('+require(`${item}`) +')' }"
![]()
:style="{transform:'rotate('+deg+'deg)'}"
:style="{marginTop:$pxToRem(40),backgroundImage:'linear-gradient(#929396, #86878a)'}"
2. v-if v-else-if v-else 和v-show 区别
v-if dom 是不存在,v-show 是存在,只是隐藏而已
v-if 是dom 操作,v-show 只是css的隐藏,一般来说说,v-if有更好的切换开销,而v-show 有更高的初始渲染开销,因此,如果是需要非常频繁的切换,则使用v-show 比较好
## 计算属性
A值的改变 是因B值,或是更多的值的改变而改变 ,这时可以采用 计算属性
## watch 监听数据变化
观察vue实例上的数据变动, 简单的理解就是监听data,props的里面值的前后变化
## watch,computed区别
1. computed 定义了就不能定义在data,props,所以一般是vuex中的state用,watch是针对data,props的变量进行监听
2. computed是针对新变量,watch是针对已经存在的变量
3. computed是 A值的改变 是因B值,或是更多的值的改变而改变;watch 是观察vue实例上的数据变动, 简单的理解就是监听data,props的里面值的前后变化
## 组件
单文件组件:就是模块的组件,my-home
定义组件
注册组件/挂载组件
components: {
my-home
}
## vue 传值
A. 父 子 传值 使用props接受
props 可以直接用 默认类型
props:{
list:{
type:Array ,
default: () => [1, 2, 3, 4, 5]
}
}
或是:
props:['list']
vue props 传递函数:
methods: {
childrenClick(c){
console.log(c,'子组件传递过来')
}
},
// 子组件
export default {
data() {
return {
count:1,
}
},
props:{
add:{
type: Function
}
},
methods: {
handClick(){
this.add( ++this.count); // 父组件方法
}
},
}
this 传值:
home:
data() {
return {
count:1,
name:"黄小"
}
},
methods: {
handClick(){
this.add( ++this.count); // 父组件方法
}
},
header:
{{home.name}}
这边可以获取home组件 的data和methods
补充:props 验证
props:{
list:{
type:Array ,
default: () => [1, 2, 3, 4, 5]
},
num:{
type:String
}
}
// 如果 num 是字符串 如果传数字,那这样就会报错,只能传字符串
B.子 父 传值 父亲写事件函数 子 $emit触发 传值
父:
callValFn(item) {
console.log("items:", item);
},
子:
getName() {
let val ="$emit 传值";
this.$emit("call-val", val);
},
C.兄弟传值 $bus 中转站
D.如果组件之间 关系很远 是很多组件都要用的值 vuex
补充:
父组件主动获取子组件的数据,方法
base.vue
data() {
return {
msg: "父组件",
};
},
//父组件主动获取子组件的数据,方法
getChildFn() {
console.log(this.$refs.headerRef.name, "ssss ddd");
this.$refs.headerRef.getName();
},
fatherFn() {
console.log("父组件的方法");
},
子组件主动获取父组件的数据,方法
headers.vue
# vue3
## 非父子组件传值
使用mitt 插件 【https://github.com/developit/mitt】
1. 安装插件:npm install --save mitt
2. 引入插件: src/ model/event.js
// using ES6 modules
import mitt from 'mitt'
const event = mitt()
export default event
3. mitt 组件
使用mitt 插件 非父子组件传值
4. headers
## 新特性
## 组合式 API 也就是composition-api
(1) vue2 组件的局限性
1. 组件越大,可续性越差
2. 相同的代码逻辑很难在多个组件中复用
### composition-api优点
1. 提供了更完善的ts支持
2. 组件拥有了更加良好的代码组织结构
3. 相同的代码逻辑在不同的组件中进行了完整的复用
### 提供以下几个函数
1. setup :组合api 的方法都是写在这里面的
2. ref : 定义响应式数据 字符串 bool
3. reactive :定义响应式数据 对象
4. watchEffet :监听数据变化
5. watch :监听数据变化
6. computed :计算属性
7. toRefs :解构响应式对象数据
8. 生命周期的hooks
#### setup
https://v3.cn.vuejs.org/guide/composition-api-setup.html#%E5%8F%82%E6%95%B0
1. setup 函数会在 beforeCreate、created 之前执行,setup的生命周期 在 beforeCreate、created 之后执行
2. setup 有2个参数
props 的父组件传递过来的参数
ctx 上下文对象
ctx.attrs
ctx.slots
ctx.parent
ctx.root
ctx.emit
ctx.refs
3. 在 setup() 函数中无法访问到 this【没有 this。这意味着,除了 props 之外,你将无法访问组件中声明的任何属性——本地状态、计算属性或方法。】
4. 执行 setup 时,组件实例尚未被创建,你只能访问以下 property【props,attrs, slots, emit 】,你将无法访问以下组件选项【data,computed ,methods】
#### ref ,reactive 定义响应式数据
ref 【定义字符串,num,bool,数组】
reactive【定义对象】
使用 ref 还是 reactive 可以选择这样的准则
第一,就像刚才的原生 javascript 的代码一样,像你平常写普通的 js 代码选择原始类型和对象类型一样来选择是使用 ref 还是 reactive。
第二,所有场景都使用 reactive,但是要记得使用 toRefs 保证 reactive 对象属性保持响应性
第三, 一般ref定义字符串,num ,布尔型,数组;reactive 定义的是对象
reactive 相当于 Vue 2.x 中的 Vue.observable() API
ref
https://v3.cn.vuejs.org/guide/reactivity-fundamentals.html#ref-%E5%B1%95%E5%BC%80
声明响应式状态:
ref reactive
这就是 Vue 响应性系统的本质:
该 API 返回一个响应式的对象状态。该响应式转换是“深度转换”——它会影响嵌套对象传递的所有 property
#### toRefs 解构响应式对象数据
2.toRefs 解构响应式对象数据
{{worksName}}
setup() {
// 2.toRefs 解构响应式对象数据
var worksInfos = reactive({
worksName: "张三",
worksDesi: "到好多好好的"
});
return {
...toRefs(worksInfos) //...worksInfos 这样的话可以显示数据,但是不能双向绑定数据
};
}
#### computed 计算属性 【只能在setup】
{{fullName}}
setup() {
//3.computed :计算属性
var userInfos2 = reactive({
firstName: "王",
lastName: "一搏"
});
var fullName = computed(() => {
return userInfos2.firstName + userInfos2.lastName;
});
return {
...toRefs(userInfos2),
fullName
};
#### readonly "深层"的只读代理 (少用)
将响应式 数据(ref,reactive定义的数据),转正非响应式的数据(也就是原始数据)
readonly 传入一个对象(响应式对象),返回一个原始对象 只能读取不能修改。
var obj={
username:"李小英"
}
obj 就是原始数据, 可以渲染在页面中,但是不能双向绑定
var userInfos = reactive({
username: "张三",
age: 20
});
userInfos 响应式数据,
可以把响应式数据 转成非响应式数据,
const copy = readonly(userInfos) //copy.username 只能读取,不能修改
#### watchEffet 监听数据变化
在响应式地跟踪其依赖项时,立即运行一个函数,并在更改依赖项时重新运行它。
4.watchEffet 监听数据变化 --侦听器
{{data.count}}
const data = reactive({
count: 1,
num: 1
});
const stop = watchEffect(() => {
console.log("侦听器:", data.count);
});
setInterval(() => {
data.count++;
}, 1000);
#### watch , watch与watchEffect区别
(1).watch与watchEffect区别:
const data = reactive({
count: 10,
num: 1
});
1. 懒执行,也就是说只有侦听的值变更时才执行回调
watchEffect(() => {
console.log("侦听器:", data.count);// 可以输出1
});
watch(data, () => {
console.log("watch 监听:", data.count);// 输出2
});
watch 只有监听到值(data.count)发生变化 才执行,watchEffect都可以执行
2. 更明确哪些状态的改变会触发侦听器重新运行
watchEffect 可以监听具体的对象【如:data.count】,watch 只能监听ref或是reactive定义的对象【如: data】
3. 访问侦听状态变化前后的值
watch(numVal, (newVal, oldVal) => {
console.log("numVal新值跟旧值的变化:", newVal, oldVal);
});
(2). eg:
5.watch 监听数据变化 --侦听器
{{data.count}}
watch 双向数据绑定,前后数据
{{numVal}}
const data = reactive({
count: 10,
num: 1
});
// (1).简单的引用
// 要监听对象data ,但是不能监听对象里的值data.count
watch(data, () => {
console.log("watch 监听:", data.count);
});
setInterval(() => {
data.count++;
}, 1000);
var numVal = ref("1");
// (2).watch 的两个参数,代表新的值和旧的值
watch(numVal, (newVal, oldVal) => {
console.log("numVal新值跟旧值的变化:", newVal, oldVal);
});
//(3). watch 多个值,返回的也是多个值的数组
watch([numVal, data], (newValue, oldValue) => {
console.log("old", oldValue); //["13",Proxy {count: "144", num: 1}]
console.log("new", newValue); //["134",Proxy {count: "144", num: 1}]
});
// (4).使用 getter 的写法 watch reactive 对象中的一项
watch([numVal, () => data.count], (newValue, oldValue) => {
console.log("old", oldValue); //old (2) ["1", 10]
console.log("new", newValue); //new (2) ["1", "103"]
console.log("updated:" + numVal.value + data.count); //updated:1103
});
#### 生命周期
https://v3.cn.vuejs.org/guide/composition-api-lifecycle-hooks.html
都是 setup () 内部调用生命周期钩子,没有beforeCreate,created ,其他都是一样
在生命周期的vue3更新:
在vue3中对生命周期钩子的命名进行一些简单的命名更新,并且在setup函数中提供了新的生命周期函数钩子。
1. 命名改变:
vue3对beforeDestroy 和destroy进行命名的修改,分别修改为beforeUnmount,unmounted。这个是命名的改变,回调时机上并没有发生任何的改变。
2. setup函数中提供了新的生命周期函数钩子
https://v3.cn.vuejs.org/guide/composition-api-lifecycle-hooks.html
### Provide / Inject
https://v3.cn.vuejs.org/guide/composition-api-provide-inject.html#%E8%AE%BE%E6%83%B3%E5%9C%BA%E6%99%AF
不管组件层次 结构多深,都可以使用这个Provide(传递参数) / Inject (接受参数)
### 非组合api
app.vue
祖父组件:{{location}}
provides:
Provide / Inject
location.vue:
孙组件接受参数
祖父组件定义provide,孙组件inject接受:{{location}}
点击fn,不能改变location.vue的值,就是没有响应的效果
没有办法 双向绑定
### 组合api (重点)
https://v3.cn.vuejs.org/guide/composition-api-provide-inject.html#%E4%BD%BF%E7%94%A8-provide
祖父组件:{{location}}
双向数据绑定:
姓名 {{username}}:
provides:
Provide / Inject
location.vue:
孙组件接受参数
1.祖父组件定义provide,孙组件inject接受:{{location}}
用户信息: {{userInfos.username}}
2.provide inject实现父子组件传值的时候,子组件改变数据也会影响父组件
姓名:
### 总结:
1.祖父组件定义provide,孙组件inject接受
2.provide inject实现父子组件传值的时候,子组件改变数据也会影响父组件
### 不想子组件改变父组件的数据
最后,如果要确保通过 provide 传递的数据不会被 inject 的组件更改,我们建议对提供者的 property 使用 readonly
provide("userInfos", readonly(userInfos));
## 模板引用【template refs】
当使用组合式 API 时,响应式引用【reactive refs】 和 模板引用【template refs】 的概念已经是统一的。
## 响应性
### 比较vue2 和 vue3 响应式
#### vue2 的响应式:
核心:
对象:通过defineProperty对对象的已有属性值的读取和修改进行劫持(监视、拦截)
数组:通过重写数组更新数组一系列更新元素的方法实现元素修改的劫持【简单的理解:普通数组变成响应数组,对一个数组的元素进行更改的话,它会对这个更改的方法进行重新编写】
object.defineProperty(data,'count',{
get(){},
set(){}
})
问题:
1. 对象直接新添加的属性或删除已有属性,界面不会自动更新
2. 直接通过下标替换元素或更新length,界面不会自动更新 arr[1] ={}
所以后面才有$set,去响应数据
eg:
//因为vue2 是通过object.defineProperty 来操作数据,所以不能检测数据的变动(虽然打印出来的数据是更新的,但是界面的数据没更新)
export default {
data() {
return {
user: {
name: "王一博",
age: 20
}
};
},
methods: {
add() {
this.user.sex = "男";
console.log( this.user);
}
}
};
注意同样的代码在vue3 里面就可以。不旦数据更新,界面也更新。原因是vue3使用prory
#### vue3 的响应式:
核心:
1.通过proxy(代理):拦截对data任意属性的任意(13种)操作,包括属性值的读写,属性的添加,属性的删除等
2.通过reflect(反射):动态对被代理对象的相应属性进行特定的操作
### 什么是响应式
响应性是一种允许我们以声明式的方式去适应变化的一种编程范例。
简单的理解:对对象进行修改,对象数据会改变,界面上也会发生改变
### 深入vue3响应性原理
就是把目标对象变成代理对象(prory),然后通过代理对象对数据进行操作,通过reflect在反射回来。
### 什么是prory
proxy 是一个对象,可以代理一个对象或函数,允许拦截被代理的对象或函数
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy[proxy]
### Reflect
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect[reflect]
## 有意思的Teleport
https://v3.cn.vuejs.org/guide/teleport.html[官网]
teleport 是vue3 内置组件,接受2个函数(to:指定将在其中移动
内容的目标元素 如:body,.home ,#home;disabled :禁止使用该功能)
请注意,这将移动实际的 DOM 节点,而不是被销毁和重新创建,并且它还将保持任何组件实例的活动状态。所有有状态的 HTML 元素 (即播放的视频) 都将保持其状态。
核心就是to的操作
## 注意点
### 值得注意的新特性
Vue 3 中需要关注的一些新功能包括:
组合式 API
Teleport
片段
触发组件选项
来自 @vue/runtime-core 的 createRenderer API 创建自定义渲染器
单文件组件组合式 API 语法糖 (