
vue3.x文档https://www.vue3js.cn/docs/zh/api/application-config.html#errorhandler
vite是一个Web开发构建工具,由于其本机ES模块导入方法,因此可以闪电般快速地提供代码。通过在终端中运行以下命令,可以使用Vite快速设置Vue项目。1.npm init vite-app
2.npm install
vue create 项目名
注意点 (vue3)
- setup中的this指向是undefind
- beforeCreated中的this指向是proxy ,vue2中的this是vue实例
setup坑
使用provide与inject时,provide如果需要响应子组件,需要将rective/ref整体数据传,不能是对象里面的数据单独传(不响应),见例子
parent.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25<div class="hello">
<h2><button @click="changeMsg">修改</button>{{msg}}</h2>
<headerbar></headerbar>
<contentbar></contentbar>
<footerbar></footerbar>
</div>
setup(){
const data = reactive({
msg:'这是我要传递的信息'
});
const methods = {
changeMsg:function(){
data.msg = '我被 修改了'+Math.random()
}
}
provide('data',data); //子组件会实时更新,响应
provide('msg',data.msg); //子组件只会收到1次,更新 时不将响应
provide('changeMsgFn',methods.changeMsg);
return {
...toRefs(data),
...methods
}
},son.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14setup(props) {
const parentData = inject("data");
const changeMsgFn = inject("changeMsgFn");
/* const data = reactive({
parentData:inject('data'),
msg:inject("msg"),
changeMsg:inject("changeMsgFn")
});
console.log(data); */
return {
parentData,
changeMsgFn
};
},为了增加 provide 值和 inject 值之间的响应性,我们可以在 provide 值时使用 ref 或 reactive。
原文参考:https://v3.cn.vuejs.org/guide/composition-api-provide-inject.html#%E4%BD%BF%E7%94%A8-inject
setup**用法1,使用ref代替vue2中的data+methods**
1 | <ol> |
1 | setup(){ |
1 | setup(){ |
reactive用法,使用reactive代替ref
1 | <ol> |
上面代码遍历时每次都需要写liData?使用toRefs
官方说法:由于props
是反应性的,您不能使用ES6解构,因为它会删除道具的反应性。
1 | const liData = reactive({ |
ref与reactive的区别
ref用于创建简单的响应式数据,reactive用于创建复杂的响应式数据
setup语法糖的使用
使用setup组件自动注册,无需手动在components中注册组件,只需要引入
1 | <template> |
使用setup后新增API
defineProps 用来接收父组件传来的 props
1 | <template> |
defineEmits 子组件向父组件事件传递
1 | <template> |
defineExpose
组件暴露出自己的属性,在父组件中可以拿到。请注意,非setup语法糖,父组件可以直接使用ref拿到子组件的属性和方法。而setup语法糖默认不会拿到任何定义属性和方法,如需要拿到使用defineExpose暴露出去
1 | <template> |
vue2与vue3的生命周期
1 | 选件API 钩在里面 setup |
computed
1 | const num1 = ref(0); |
1 | const num1 = ref(0); |
watch
1 | // watching a getter |
1 | const firstName = ref(''); |
假定结构如下
1 | const state = reactive({ count:1,info:{name:'xxx'} }); |
watch(state,(newVal,oldVal)=>{})
正常情况 异常行为监听一个object对象时newVal === oldVal
watch(()=>state.count,(newVal,oldVal)=>{ })
单独监听某个值的情况
watch([()=>state.count,()=>state.info.name],(newVal,oldVal)=>{ });
此时newVal= [item1(state.count的值),item2(state.info.name)的值]
watch(()=>state.info,(newVal,oldVal)=>{ },{deep:true})
监听state中的某个对象时,需要手动开启deep:true深度监听,否则无法监听到state.info.name的变化时的回调
const state = ref({ count:1,info:{name:'xxx'} });
watchEffetc添加了第三个配置项immediate:true,deep:true1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**`假定有如上的特殊情况`** 监听方法为 `watch(()=>state.value.count)` 需要使用.value
//注意使用reactive时,需要在监听的对象上构造一次,如使用ref创建 的数据,可直接监听
相关链接: https://v3.vuejs.org/guide/reactivity-computed-watchers.html#watch
### watchEffect
```javascript
const state = reactive({
num1:0,
num2:0,
sum:''
});
watchEffect(()=>{
state.sum = Number(state.num1) +Number(state.num2);
});
watchEffect比watch更加智能,类似于computed的方式,watchEffect根据里面的依赖值变化而触发回调
1 | const info = reactive({ |
toRef
toRef可以将reactive某个字段单独提出来与原数据建立共同的映射,即month = person.info.money类似,通过修改toRef的值,可以直接修改reactive
1 | const person = reactive({ |
toRefs
toRefs可以将reactive定义的数据解析出来,去掉第一级
1
2
3
4
5
6
7
8
9
10
11
12
13
14const person = reactive({
name:'xiaoMi',
info:{
money:1
}
});
return {
...toRefs(person)
}
/**
<template>中可以省略person的重复写
<template>{{name}}</template>
/**toRefs将一个Reactive中的某个Object对象单独提出,与原有的数据关联 即user = person
1
2
3
4
5
6
7
8
9
10const person = reactive({
name:'xiaoMi',
info:{
money:1
}
})
const user = toRefs(person);
const editName = ()=>{
user.name.value +='!'
}
readonly
接受一个对象 (响应式或纯对象) 或 ref 并返回原始对象的只读代理。只读代理是深层的:任何被访问的嵌套 property 也是只读的。
shallowReactive
创建一个响应式代理,它跟踪其自身 property 的响应性,但不执行嵌套对象的深层响应式转换 (暴露原始值)
markRaw
1 | const person = reactive({ |
使用markRaw标记的数据将不会成为响应式,主要了为优化,对不需要响应式的数据减少proxy的递归成响应式
标记一个对象,使其永远不会转换为 proxy。返回对象本身。
vue3.x自定义Hooks
1 | //useGetMousePosition.js |
1 | //Test.vue |
vue3中的两种子传父
1 | //方法1 |
自定义hooks
当有公共的逻辑时,将状态data与方法提出封闭在一个js文件中的函数里,导出data数据
1 | import { onBeforeUnmount, onMounted, onUnmounted, reactive } from 'vue'; |
需要使用的地方 如test.vue
1 | import usePoint from '../hooks/index.js'; |
其它变更
不再支持.native
不再支持keycode的事件修饰符 如@click.13=’事件名’
全局注册组件放到了createApp中完成,详见: https://v3.cn.vuejs.org/guide/component-registration.html#%E5%85%A8%E5%B1%80%E6%B3%A8%E5%86%8C
不再支持过滤器 vue.$filter语法
新增
<teleport>
将组件挂载到某个dom1
2
3
4
5
6
7
8
9
10
11<teleport to="body">
<div v-if="modalOpen" class="modal">
<div>
I'm a teleported modal!
(My parent is "body")
<button @click="modalOpen = false">
Close
</button>
</div>
</div>
</teleport>404 Not found 路由由
path:*
更改 详见:https://router.vuejs.org/zh/guide/essentials/dynamic-matching.html#%E5%93%8D%E5%BA%94%E8%B7%AF%E7%94%B1%E5%8F%82%E6%95%B0%E7%9A%84%E5%8F%98%E5%8C%961
2
3
4
5
6const routes = [
// 将匹配所有内容并将其放在 `$route.params.pathMatch` 下
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
// 将匹配以 `/user-` 开头的所有内容,并将其放在 `$route.params.afterUser` 下
{ path: '/user-:afterUser(.*)', component: UserGeneric },
]app.config.globalProperties.foo = ‘bar 定义的数据/方法可以在Vue.2x(mounted/created)中找到全局定义的方法
vue3获取全局数据/方法:
重点:官网好像不推荐使用getCurrentInstance
getCurrentInstance
只暴露给高阶使用场景,典型的比如在库中。强烈反对在应用的代码中使用getCurrentInstance
。请不要把它当作在组合式 API 中获取this
的替代方案来使用。详见: https://v3.cn.vuejs.org/api/composition-api.html#getcurrentinstance
1
2
3
4
5
6
7//main.js
app.config.globalProperties.$vueName = 'Vue3全局挂载名称'
//xxx.vue
import {getCurrentInstance } from "vue";
let {proxy} = getCurrentInstance()
console.log(proxy.$vueName);Vue2.x中的beforeCreate的
this
指向的vue实例,到了Vue3中,setup/onMounted…生命周期的this指向的**undefined
**vue2.x中的生命周期包含beforeCreate可以获取vue3.x中的setup实例方法、数据,使用this.xxx
1
2
3
4
5
6
7
8
9setup() {
const count = ref(0);
return {
count
}
}
created(){
console.log(this.count);//获取为0
}vue3.x不再支持**.sync和emit(‘update:属性’,值)的语法**
vue2与 vue3版本的双向数据绑定原理
vue2
1 | Object.defineProperty(obj,KEY,{ |
vue2使用的object.defineProperty存在的问题
新增、删除一个属性时,视图不会更新
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32<template>
<section>
<h1>list.vue</h1>
<h3 v-show="personInfo.name">用户名:{{ personInfo.name }}</h3>
<h3 v-show="personInfo.age">年龄:{{ personInfo.age }}</h3>
<h3 v-show="personInfo.school">学校:{{ personInfo.school }}</h3>
<button @click="addSchool">添加一个学校</button>
</section>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
setup() {
},
data(){
return {
personInfo:{
name:'shao.yuhong',
age:22
}
}
},
methods:{
addSchool(){
this.personInfo.addSchool = '重庆师范大学';
console.log(this.personInfo);
}
}
})
</script>解决方案
vue2.x提供了两种方法
this.$set(this.personInfo,’school’,值)
Vue.set(this.personInfo,’school’,值)
this.$delete(this.personInfo,’school’,值)
Vue.delete(this.personInfo,’school’,值)
vue3
vue3使用proxy代理,弥补了vue2上述问题,但是出现了使用watch监听一个Array/object时,newVal与oldVal相同的问题
proxy中get
set
deleteProerty
使用es6中的Reflect读取,设置、删除某个值,使用Reflect而不是直接返回是因为
好处是,通过Reflect返回值就会知道成功还是失败。
对于vue3而言,底层使用reflect会比较健壮,不容易出现有个错误就导致程序阻塞。如果使用object:
虽然可以通过try catch,但是底层源码如果各种try catch就会显得不优雅。
如果使用reflect,当出现错误的时候,进行逻辑判断从而代码继续往下走
vue.use()与Install
vue.use时,会找到对应的node_modules下的模块,这个模块存在一个文件名为index.js,并调用index.js中的install函数,在install函数中整合了所有组件,并导出
vue2 v-model自定义组件
平时我们使用 v-model 一般用在 input 标签上
1 | 1 <input v-model= 'content' ></input> |
等价于
1
用在组件上类似于
1 | 1 Vue.component( 'base-input' , { |
一个组件上的 v-model
默认会利用名为 value
的 prop 和名为 input
的事件
所以当我们把 v-model 用在自定义组件上时
1 | 1 父组件: |
父组件使用 v-model 绑定在data中定义的属性 flag 传递给子组件(Child),子组件通过 props 接收,名为 value ,通过按钮触发对父组件中 flag 进行修改 ( $emit( ‘input’,!value ) )
通过在model属性中自定义事件:
如果遇到单选框、复选框等类型的输入控件可能会将 value
attribute 用于不同的目的,model
选项可以用来避免这样的冲突:
1 | 1 父组件: |
通过使用 model 里的 event 方法自定义属性名,prop代表和props里的变量相对应
1 | <Child v-model="inputValue"></Child> |
- 本文标题:vue3.x学习笔记
- 本文作者:邵预鸿
- 创建时间:2021-02-21 11:45:25
- 本文链接:/images/logo.jpg2021/02/21/vue3-x学习笔记/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!