Vue 3.0 于 2020-09-18 发布了,使用了 Typescript 进行了大规模的重构,带来了 Composition API RFC 版本,类似 React Hook 一样的写 Vue,可以自定义自己的 hook ,让使用者更加的灵活。

为什么推出3.0?

  • 对 TypeScript 支持不友好(所有属性都放在了 this 对象上,难以推倒组件的数据类型)
  • 大量的 API 挂载在 Vue 对象的原型上,难以实现 TreeShaking
    • TreeShaking:当我引入一个模块的时候,我不引入这个模块的所有代码,我只引入我需要的代码
  • 架构层面对跨平台 dom 渲染开发支持不友好
  • CompositionAPI。受 ReactHook 启发
  • 更方便的支持了 jsx
  • Vue 3 的 Template 支持多个根标签,Vue 2 不支持
  • 对虚拟 DOM 进行了重写、对模板的编译进行了优化操作

一、setup

为我们使用 vue3 的 Composition API 新特性提供了统一的入口, 有些文章说setup 函数会在 beforeCreate 之后、created 之前执行但实践证明这个说法不正确如下图打印顺序, vue3 也是取消了这两个钩子,统一用 setup 代替, 该函数相当于一个生命周期函数,vue 中过去的 data,methods,watch 等全部都用对应的新增 api 写在 setup()函数中。

1、setup参数

  1. props: 组件传入的属性
  2. context:attrs,emit,slots

props

  setup中接受的props是响应式的, 当传入新的props 时,会及时被更新。由于是响应式的, 所以不可以使用ES6解构,解构会消除它的响应式。需要结构可以用toRefs()

context

  setup中不能访问Vue2中最常用的this对象,所以context中就提供了this中最常用的三个属性:attrsslot 和emit,分别对应Vue2.x中的 $attr属性、slot插槽 和$emit发射事件。

简单用法

2、reactive、ref与toRefs

在vue2.x中, 定义数据都是在data中, 但是Vue3.x 可以使用reactiveref来进行数据定义。

区别

  reactive用于处理对象的双向绑定,ref则处理js基础类型的双向绑定,reactive不能代理基本类型,例如字符串、数字、boolean等。

简单用法

<template>
<div>
<span>{{ year }}</span
><span>{{ user.name }}</span
><span>{{ user.label }}</span>
</div>
</template> <script>
import { reactive, ref } from "vue";
export default {
props: {
data: {
type: Object,
default: {
id: 1,
name: "匹配",
},
},
},
components: {}, setup(props, con) {
const year = ref(10);
const user = reactive({
name: "夏利",
label: "",
});
  //这里ref取值需要加value
if (year.value > 5) {
user.label = "牛逼";
} else {
user.label = "一般";
}
return {
year,
user,
};
},
};
</script>

  不能直接对user进行结构, 这样会消除它的响应式, 这里就和上面我们说props不能使用ES6直接解构就呼应上了。那我们就想使用解构后的数据怎么办,解决办法就是使用toRefs

   return {
year,
// 使用reRefs
...toRefs(user)
}

3、生命周期

  我们可以看到beforeCreatecreatedsetup替换了(但是Vue3中你仍然可以使用, 因为Vue3是向下兼容的, 也就是你实际使用的是vue2的)。其次,钩子命名都增加了on; Vue3.x还新增用于调试的钩子函数onRenderTriggeredonRenderTricked

<script>
import {
defineComponent,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
onErrorCaptured,
onRenderTracked,
onRenderTriggered,
} from "vue"; export default defineComponent({
// beforeCreate和created是vue2的
beforeCreate() {
console.log("------beforeCreate-----");
},
created() {
console.log("------created-----");
},
setup() {
console.log("------setup-----"); // vue3.x生命周期写在setup中
onBeforeMount(() => {
console.log("------onBeforeMount-----");
});
onMounted(() => {
console.log("------onMounted-----");
});
// 调试哪些数据发生了变化
onRenderTriggered((event) => {
console.log("------onRenderTriggered-----", event);
});
},
});
</script>

4、全局定义属性 globalProperties

  在项目中往往会全局定义公共属性或方法,方便我们组件间调用。

import { createApp } from 'vue'
import App from './App.vue'
import utils from './utils' // vue2.0写法
let vue=new Vue()
vue.prototype.utils=utils
// vue3.0写法
const app=createApp(App)
app.config.globalProperties.utils=utils

app.mount('#app')

vue3.0中使用全局定义的属性

<script>

import { getCurrentInstance } from "vue";

export default {
components: {},
setup(props, con) {

const { ctx } = getCurrentInstance();
console.log(ctx.utils);

},
};
</script>

5、use与plugin

定义一个组件

通过use引入

6、readonly 只读属性

在使用readonly后重新进行复制是不允许修改的,这个api不常用

7、computed计算api

这里引入了proxy内的类似写法,有了set与get的内容写法,该函数用来创造计算属性,和过去一样,它返回的值是一个 ref 对象。里面可以传方法,或者一个对象,对象中包含 set()、get()方法。

7.1 创建只读的计算属性

<template>
<div>
<p>refCount: {{refCount}}</p>
<p>计算属性的值computedCount : {{computedCount}}</p>
<button @click="refCount++">refCount + 1</button>
</div>
</template> <script>
import { computed, ref } from '@vue/composition-api'
export default {
setup() {
const refCount = ref(1)
// 只读
let computedCount = computed(() => refCount.value + 1) //2
console.log(computedCount)
return {
refCount,
computedCount
}
}
};
</script>

7.2 通过 set()、get()方法创建一个可读可写的计算属性

<template>
<div>
<p>refCount: {{refCount}}</p>
<p>计算属性的值computedCount : {{computedCount}}</p>
<button @click="refCount++">refCount + 1</button>
</div>
</template> <script>
import { computed, ref } from '@vue/composition-api'
export default {
setup() {
const refCount = ref(1)
// 可读可写
let computedCount = computed({
// 取值函数
get: () => refCount.value + 1,
// 赋值函数
set: val => {
refCount.value = refCount.value -5
}
})
  //触发get函数
console.log(computedCount.value)

// 为计算属性赋值的操作,会触发 set 函数
computedCount.value = 10
console.log(computedCount.value)
// 触发 set 函数后,count 的值会被更新
console.log(refCount.value)

return {
refCount,
computedCount
}
}
};
</script>

8、watch与watchEffect

8.1watch

  watch 函数用来侦听特定的数据源,并在回调函数中执行副作用。默认情况是惰性的,也就是说仅在侦听的源数据变更时才执行回调。

    *   1、需要一个明确的数据资源
         *   2、需要有一个回调函数
         *   3、等到改变才会执行函数
<script>
import { ref, watch } from "vue";
export default {
components: {},
setup(props, con) {
const count = ref(0);
const name = ref("iuuggu");
setTimeout(() => {
(count.value = 1), (name.value = "这一行山");
}, 200);
watch(
() => {
/*
* 1、需要一个明确的数据资源
* 2、需要有一个回调函数
* 3、等到改变才会执行函数
*
*/
return count.value;
},
() => {}
);
// 4、ref简写 ,reactive不可以
watch(count, () => {});
// 5、监听多个
watch(
() => {
return [count, name];
},
([newv, oldv], [newv, oldv]) => {}
);
// 6、onTrack,onTrigger
watch(
() => {
return [count, name];
},
([newv, oldv], [newv, oldv]) => {},
{
onTrack(e) {},
onTrigger(e) {},
}
);
},
};
</script>

8.1.1 监听数据源

reactive

setup(props, context) {
const state = reactive<Person>({ name: 'vue', age: 10 }) watch(
() => state.age,
(age, preAge) => {
console.log(age); // 100
console.log(preAge); // 10
}
)
// 修改age 时会触发watch 的回调, 打印变更前后的值
state.age = 100
return {
...toRefs(state)
}
}

ref

setup(props, context) {
const age = ref<number>(10); watch(age, () => console.log(age.value)); // 100 // 修改age 时会触发watch 的回调, 打印变更后的值
age.value = 100
return {
age
}
}

8.1.2监听多个

setup(props, context) {
const state = reactive<Person>({ name: 'vue', age: 10 }) watch(
[
      () => state.age,
      () => state.name
    ],
([newName, newAge], [oldName, oldAge]) => {
console.log(newName);
console.log(newAge); console.log(oldName);
console.log(oldAge);
}
)
// 修改age 时会触发watch 的回调, 打印变更前后的值, 此时需要注意, 更改其中一个值, 都会执行watch的回调
state.age = 100
state.name = 'vue3'
return {
...toRefs(state)
}
}

8.1.3stop 停止监听

在 setup() 函数内创建的 watch 监视,会在当前组件被销毁的时候自动停止。如果想要明确地停止某个监视,可以调用 watch() 函数的返回值即可,语法如下:

setup(props, context) {
const state = reactive<Person>({ name: 'vue', age: 10 }) const stop = watch(
[() => state.age, () => state.name],
([newName, newAge], [oldName, oldAge]) => {
console.log(newName);
console.log(newAge); console.log(oldName);
console.log(oldAge);
}
)
// 修改age 时会触发watch 的回调, 打印变更前后的值, 此时需要注意, 更改其中一个值, 都会执行watch的回调
state.age = 100
state.name = 'vue3' setTimeout(()=> {
stop()
// 此时修改时, 不会触发watch 回调
state.age = 1000
state.name = 'vue3-'
}, 1000) // 1秒之后讲取消watch的监听 return {
...toRefs(state)
}
}

8.2 watchEffect

 该函数有点像update函数,但他执行在update与beforeuodate之前。

       *    1、首次加载会立即执行
* 2、响应的最终所有依赖监听变化(数据改变)
* 3、在卸载onUnmounte时自动停止
* 4、执行stop就会停止监听,否则一直监听
* 5、异步函数先执行再去监听改变
<script>
import { watchEffect, ref, onMounted } from "vue";
export default {
components: {},
//con==context(attrs,emit,slots)
setup(props, con) {
const count = ref(0);
setTimeout(() => {
count.value = 1;
}, 2000);
const stop = watchEffect(
() => {
/*
* 1、首次加载会立即执行
* 2、响应的最终所有依赖监听变化(数据改变)
* 3、在卸载onUnmounte时自动停止
* 4、执行stop就会停止监听,否则一直监听
* 5、异步函数先执行再去监听改变
*/
},
{
// 6、在update之后执行
flush: "post",
// 同步执行
flush: "async",
}
);
setTimeout(() => {
stop();
}, 4000); // 7、组件挂在ref
const myRef = ref(null);
// 避免监听时先见听到null 在监听到h1
onMounted(() => {
watchEffect(() => {
console.log(myRef.value);
});
});
// 8、debugging 开发模式使用
watchEffect(
() => {
console.log(count.value);
},
{
onTrack(e) {
// 监听到count和改变count
},
onTrigger(e) {
// count改变了会触发
},
}
);
return {
myRef,
count,
};
},
};
</script>

9、ref,torefs,isref,unref

9.1ref

ref() 函数用来根据给定的值创建一个响应式的数据对象,ref() 函数调用的返回值是一个对象,这个对象上只包含一个 .value 属性:

ref数据

<template>
<div class="mine">
{{count}} // 10
</div>
</template> <script >
import {ref } from 'vue';
export default {
setup() {
const count = ref(10)
// 在js 中获取ref 中定义的值, 需要通过value属性
console.log(count.value);
return {
count
}
}
}
</script>

ref 访问dom

在 reactive 对象中访问 ref 创建的响应式数据

当把 ref() 创建出来的响应式数据对象,挂载到 reactive() 上时,会自动把响应式数据对象展开为原始的值,不需通过 .value 就可以直接被访问,例如:

<template>
<div class="mine">
{{count}} -{{t}} // 10 -100
</div>
</template> <script >
import reactive, ref, toRefs } from 'vue';
export default {
setup() {
const count = ref(10)
const obj = reactive({
t: 100,
count
})
// 通过reactive 来获取ref 的值时,不需要使用.value属性
console.log(obj.count);
return {
...toRefs(obj)
}
}
}
</script>

9.2 toRefs() 函数

toRefs() 函数可以将 reactive() 创建出来的响应式对象,转换为普通的对象,只不过,这个对象上的每个属性节点,都是 ref() 类型的响应式数据

<template>
<div>
<p>{{ count }} - {{ name }}</p>
<button @click="count += 1">+1</button>
<button @click="add">+1</button>
</div>
</template> <script>
import { reactive, toRefs } from "@vue/composition-api";
export default {
setup() {
// 响应式数据
const state = reactive({ count: 0, name: "zs" });
// 方法
const add = () => {
state.count += 1;
};
return {
// 非响应式数据
// ...state,
// 响应式数据
...toRefs(state),
add
};
}
};
</script>

9.3 isref

isRef() 用来判断某个值是否为 ref() 创建出来的对象

 setup(props, context) {
const name: string = 'vue'
const age = ref(18)
console.log(isRef(age)); // true
console.log(isRef(name)); // false return {
age,
name
}
}

9.4 unref

unRef() 用来判断某个值是否为 ref() 创建出来的对象有抛出该对象

 setup(props, context) {
const name: string = 'vue'
const age = ref(18)
console.log(unRef(age)); // 18
console.log(unRef(name)); // vue return {
age,
name
}
}

最新文章

  1. 浅析linux内核中的idr机制
  2. 可惜Java中没有yield return
  3. shell程序设计
  4. .net 小技巧
  5. Java 集合深入理解(3):Collection
  6. matlab 相关代码记录
  7. adb device出现error:unknown host service
  8. DedeCMS Error:Tag disabled:&quot;php&quot;的解决办法
  9. 在O(1)时间删除链表结点
  10. java在线截图---通过指定的URL对网站截图
  11. hdu 2546 饭卡(DP)
  12. css伪类选择器详细解析及案例使用-----伪类选择器(2)
  13. VMTools安装
  14. [django]添加自定义template filter标签
  15. ARMV8 datasheet学习笔记4:AArch64系统级体系结构之Self-hosted debug
  16. JavaScript--常用的输出方式
  17. CSS 笔记(一)
  18. Google Android API官网封杀了,没法查android技术资料的3种解决方式
  19. PSR编码规范
  20. 使用 Win2D 绘制带图片纹理的圆(或椭圆)

热门文章

  1. vue实现拖拽排序
  2. 使用 Elastic 技术栈构建 Kubernetes全栈监控
  3. Prometheus 配置文件中 metric_relabel_configs 配置--转载
  4. 专家动态页面的实现——php基于CI框架的学习(二)
  5. 【软件推荐】使用Cmder替换Windows自带的控制台
  6. Dynamic CRM登陆界面的客制化(持续更新)
  7. Java(195-214)【final、权限、内部类】
  8. Jmeter(四十三) - 从入门到精通高级篇 - Jmeter之IP伪装和欺骗(详解教程)
  9. 推荐个开源在线文档,助道友领悟 Django 之“道”
  10. top:0;bottom:0;left:0;right:0;同时使用的效果