irpas技术客

vue3初探---vue3新特性学习_guoang_vue3

未知 7363

vue3初探—vue3新特性学习

一、vue3初探—vue3新特性学习

二、vue3初探—在vue3和vuex4.x中使用typescript

三、vue3初探----(vue3项目)vuex4.x中使用typescript最终写法

四、在三中用到的一些TypeScript中的一些高阶类型 Omit Pick ReturnType Parameters

五、vue3初探----项目构建

六、vue3初探----vue3的一些变化

项目构建 vite npm init @vitejs/app demo-vue3-vite 选择vue,选择vue-ts cd demo-vue3-vite npm install npm run dev vue3的新特性

向后兼容:兼容vue2的写法

性能提升

TypeScript的支持

Composition API

当然还有其他改变,可查看官方文档 https://v3.cn.vuejs.org/guide/migration/introduction.html#%E5%80%BC%E5%BE%97%E6%B3%A8%E6%84%8F%E7%9A%84%E6%96%B0%E7%89%B9%E6%80%A7

Composition API setup函数

setup 函数是一个新的组件选项。作为在组件内使用 Composition API 的入口点。

setup会在 beforeCreate前被调用,同时在vue3中setup代替了beforeCreate和created

网上许多文章认为setup执行时间在beforeCreate 和created 之间但试验结果setup是在beforeCreate之前执行

<script> export default { setup() { console.log('setup') }, beforeCreate() { console.log('beforeCreate') }, created() { console.log('created') }, } </script>

vue3中的生命周期函数,可以按需导入到组件中,且只能在 setup() 函数中使用

<script> import { onMounted, onUpdated, onUnmounted } from 'vue'; export default { setup() { onMounted(() => { console.log('mounted!'); }); onUpdated(() => { console.log('updated!'); }); onUnmounted(() => { console.log('unmounted!'); }); return {}; } }; </script>

参数

setup有连个参数 props和context

props 接收当前组件props选项的值,即获取父组件传递过来的参数

context,接收一个上下文对象,该对象中包含了一些在vue 2.x 中需要通过 this 才能访问到属性

<script lang="ts"> import {defineComponent } from 'vue'; export default defineComponent({ props: { name: String }, setup(props, context) { context.attrs; console.log(props.name); context.slots; context.emit; } }); </script>

返回值

函数返回的内容可作为模板渲染

<template> <p>{{name}}</p> </template> <script lang="ts"> import { defineComponent, ref } from 'vue'; export default defineComponent({ setup() { let name = ref('guoang'); return { name }; } }); </script> getCurrentInstance

支持访问内部组件实例

const internalInstance = getCurrentInstance()

getCurrentInstance在await之后调用无法获取到内部组件实例

因为vue在执行时不会等待setup执行完毕,而在setup后面上下文会被设为null所以在await之后获取到是null

export default defineComponent({ async setup() { const result = ref('') result.value = await resultValue() const internalInstance = getCurrentInstance() console.log('await之后getCurrentInstance()获取不到',internalInstance) //internalInstance = null return { result, } }, })

响应式api 响应式api

推荐文章:深入理解 Vue3 Reactivity API

reactive

reactive()函数接收一个普通对象,返回该普通对象的响应式代理对象

reactive()接收一个泛型来定义他的类型

<template> <p>{{user.name}}</p> <p>{{user.age}}</p> </template> <script lang="ts"> interface User { name: string; age: number; } import { reactive, defineComponent } from 'vue'; export default defineComponent({ setup() { let user = reactive<User>({ name: 'guaong', age: 0 }); return { user }; } }); </script>

如果reactive生成的数据如果被展开就失去了响应性

setup() { let state = reactive({ count: 0 }); function add() { state.count += 1; } return { ...state }; } toRefs

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

setup() { let state = reactive({ count: 0 }); function add() { state.count += 1; } return { ...toRefs(state) }; } ref

reactive()负责复杂的数据结构,ref()则可以把基本的数据结构包装成响应式

ref()函数接收一个参数值,返回一个响应式的数据对象。该对象只包含一个指向内部值的 .value 属性

在模板中访问时,无需通过.value属性,它会自动展开

ref()接收一个泛型来定义他的类型

<template> <!-- 无需加value --> <h2>{{num}}</h2> <button @click="add">累加</button> </template> <script lang="ts"> import { ref,defineComponent } from 'vue'; export default defineComponent( { setup() { let num = ref(2); function add() { num.value += 1; //需要加value } return { add, num }; } }); </script> toRef

创建一个ref类型数据, 并和以前的数据关联

备注

1.toRef 创建一个ref类型数据, 并和以前的数据关联 2.toRefs 批量创建ref类型数据, 并和以前数据关联 3.toRef和ref区别 ref-创建出来的数据和以前无关(复制) toRef-创建出来的数据和以前的有关(引用) ref-数据变化会自动更新界面 toRef-数据变化不会自动更新界面 computed

? computed() 函数用来创建计算属性,函数的返回值是一个 ref 的实例

setup() { let num = ref(2); function add() { num.value += 1; } let double = computed(() => num.value * 2); return { add, double, num }; }

或者,接受一个具有 get 和 set 函数的对象,用来创建可写的 ref 对象。

const count= ref(2); const newCount = computed({ get: () => count.value, set: val => { count.value = val } }) watchEffect

立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。

const count = ref(0) watchEffect(() => console.log(count.value))

触发时机

const count = ref(0) watchEffect(() => { const text = count.value ; console.log(text); }, { flush: 'post' // 'pre'组件更新前运行,'post'组件更新后运行,默认为'pre' }) watch

参数watch第一个参数传入的 要监听的对象,第二个参数是回调函数,监听的对象改变就会执行回调函数,第三个参数深度监听或立即执行的配置

返回值 watch返回一个方法调用可停止监听

const unwatch = watch( () => state.count, (newVal, oldVal) => { console.log(oldVal); console.log(newVal); }, { deep: true, imediate: true } ); const stop = () => { unwatch(); };

也可以监听多个对象

watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { /* ... */ }) vue3的响应式系统

vue3将响应式系统完成独立的一个包**@vue/reactivity**,也就是说ref,reactive,effect… 这些方法可以用在任何项目中(浏览器,node),这些方法不再依赖于vue,只需要import { reactive, effect } from “@vue/reactivity”;就可以使用

封装一个操作localStorage的方法

import { reactive, effect } from "@vue/reactivity"; /** * @Author: guoang * @description: 操作localStorage * @param key 需要获取localStorage的key * @param defaultValue 默认值,获取不到localStorage对应key的数据则返回默认值 * @return 一个响应式对象 */ export default function newStorage<T extends {}>(key: string, defaultValue = {}): Partial<T> { let data: Partial<T>= reactive({}); Object.assign(data, window.localStorage.getItem(key) && JSON.parse(<string>(localStorage.getItem(key))) || defaultValue); //在data改变时会触发effect中的方法重新设置localStorage effect(() => { window.localStorage.setItem(key, JSON.stringify(data)) }); return data; }

使用

<template> <label>姓名:</label> <span>{{userInfo.name}}</span> <label>年龄:</label> <span>{{userInfo.age}}</span> <button @click="changeUserInfo">changeUserInfo</button> </template> <script lang="ts"> import { reactive, computed, ref, onMounted } from 'vue'; import newStorage from './newStorage'; interface UserInfo{ name: string age: number|string } export default { setup() { let userInfo = newStorage<UserInfo>('userInfo', { name: '名称', age: 100 }); const changeUserInfo = () => { userInfo.name = 'guoang'; userInfo.age = '120'; }; return { userInfo, changeUserInfo }; } }; </script>

效果

点击changeUserInfo更新视图同时更新localStorage

模板 Refs

在vue2.X中使用vm.$refs

在vue3中

<template> <div ref="divRef"></div> </template> <script lang="ts"> import { defineComponent, onMounted, ref } from 'vue'; export default defineComponent( { setup() { // 创建一个值为null的ref的对象,并返回 const divRef = ref(null); console.log(divRef) return{ divRef } } }); </script> setup语法糖 <template> <Foo /> <div v-click-outside /> </template> <script setup> import { defineProps, defineEmit, useContext } from 'vue'; //导入组件直接使用 import Foo from './Foo.vue'; import vClickOutside from 'v-click-outside'; //导入指令直接使用 *导入指令前面必须加v // 书写组合式 api 就像在正常的 setup 中一般,但是不需要进行手动地进行 return //const count = ref(0) 也可以这样 ref: count = 1; const inc = () => { // 直接操作变量 不用.value count++; }; // 使用 props const props = defineProps({ foo: String }); //使用 emit const emit = defineEmits(['update', 'delete']); // 获取 slots 和 attrs const { slots, attrs } = useContext(); </script> vue新组件Teleport Fragment Suspense Teleport

Teleport 提供了一种简单的方法,使我们可以控制要在DOM中哪个父对象下呈现HTML。

index.html

<body> <div id="app"></div> <div id="web"></div> <script type="module" src="/src/main.ts"></script> </body>

vue中

<template> <div> 我在id=app </div> <!-- to 属性就是目标位置 --> <teleport to="#web"> <div>我在id=web</div> </teleport> </template>

渲染结果

Fragment

在vue2中创建一个Vue组件,那么它只能有一个根节点,多了一层嵌套

<template> <div> <div></div> <div></div> </div> </template>

在vue3中会有一个名为 Fragment 的虚拟元素,他并不会呈现

<template> <div></div> <div></div> </template> Suspense

Suspense异步组件

setup 中返回一个 Promise 对象

defineComponent 包裹要导出的实例对象

<template> <h1>{{ result }}</h1> </template> <script lang="ts"> import { defineComponent, ref } from 'vue'; export default defineComponent({ async setup() { const result = ref(''); result.value = await resultValue(); return { result }; } }); const resultValue = (): Promise<string> => { return new Promise((resolve, reject) => { setTimeout(() => { resolve('HelloWorld'); }, 3000); }); }; </script>

app.vue

使用 <Suspense> 包裹所有异步组件相关代码

<Suspense> 下 <template #default> 插槽包裹异步组件

<Suspense> 下 <template #fallback> 插槽包裹渲染异步组件之前的内容

<template> <Suspense> <template #default> <HelloWorld></HelloWorld> </template> <template #fallback> <h1>Loading...</h1> </template> </Suspense> </template> <script lang="ts" setup> import HelloWorld from './components/HelloWorld.vue'; </script>

三秒后

注意点

解构props属性,如果直接在 setup 中引用,必须要加 toRefs

const { users } = toRefs(props)

setup语法糖中导入指令前面必须加v

import vClickOutside from 'v-click-outside'; //导入指令直接使用 *导入指令前面必须加v(vClickOutside) 注意点

解构props属性,如果直接在 setup 中引用,必须要加 toRefs

const { users } = toRefs(props)

setup语法糖中导入指令前面必须加v

import vClickOutside from 'v-click-outside'; //导入指令直接使用 *导入指令前面必须加v

watchEffect() 与 effect() 的区别

watchEffect() 会维护与组件实例以及组件状态(是否被卸载等)的关系,如果一个组件被卸载,那么 watchEffect() 也将被 stop,但 effect() 则不会,普通开发中不推荐直接用 effect() 啦,使用 watchEffect() 就好了


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #Vue3 #fragment #suspense