1.特性
- 向下兼容:
vue3
支持大多数vue2
特性 - 性能提升:打包大小、初次渲染、更新、内存使用
Composition API
Teleport
(瞬移组件)、Suspense
(解决异步加载组件问题)和全局API的修改和优化- 更好
TypeScript
支持
2.vue-cli搭建Vue3开发环境
Vue-cli
:
Vue.js
开发的标准工具。新版的vue-cli
还提供了图形界面:通过vue ui
命令以图形化界面创建和管理项目- 省去复杂的项目配置过程,快速生成标准化的
Vue
开发环境 - 安装:
npm install -g @vue/cli //推荐
或者
yarn global add @vue/cli
-
创建
vue3
项目:vue create vue3-1
-
package.json
中的vue-cli-service
:能使用vue-cli-service
是因为vue-cli
自动安装了cli-service
这个工具
"serve": "vue-cli-service serve",
"build:prd": "vue-cli-service build",
3.一些文件介绍
- 入口文件
main.ts
import {createApp } from "vue"
import App from "./App.vue"
createApp(App).mount("#app")
App.vue
<template>
<HelloWorld msg="welcome sss" />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import HelloWorld from './components/HelloWorld.vue';
export default defineComponent({
name:'App',
components:{
HelloWorld
}
})
</script>
4. setup()和ref()
(1)
setup
:可以代替vue2
的data
和methods
属性return
出去的数据和方法,在模板中才可以使用,可以精准得控制暴露的变量和方法
setup(props, context) {}
有两个参数,
- 注意
props
对象是响应式的,watchEffect
或watch
会观察和响应props
的更新。不要解构props
对象,那样会使其失去响应性 context
中就提供了this
中最常用的三个属性:attrs
、slot
和emit
,分别对应 Vue2.x 中的$attr
属性、slot
插槽 和$emit
发射事件。并且这几个属性都是自动同步最新的值
(2) ref
:要在template
中使用的变量,必须用ref
包装一下
<script lang="ts">
import {defineComponent,ref} from "vue";
export default defineComponent({
name:"App",
setup(){
const arrs=ref(["1","2","3"])
const selectNum=ref('')
const selectFn=(index:number)=>{
selectNum.value=arrs.value[index];
}
return {
arrs,
selectNum,
selectFn
}
}
})
</script>
- 模板
Refs
:当使用组合式 API 时,reactive refs 和 template refs 的概念已经是统一的。为了获得对模板内元素或组件实例的引用,我们可以像往常一样在 setup() 中声明一个 ref 并返回它
<template>
<div ref="root"></div>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
setup() {
const root = ref(null)
onMounted(() => {
// 在渲染完成后, 这个 div DOM 会被赋值给 root ref 对象
console.log(root.value) // <div/>
})
return {
root,
}
},
}
</script>
5. reactive
它也是一个函数(方法),只不过里边接受的参数是一个Object
(对象),无论是变量还是方法,都可以作为Object
中的一个属性
<script lang="ts">
interface DataProps{
arrs:string[];
selectNum:string;
selectFn: (index:number)=>void;
}
import {ref,reactive} from "vue";
export default {
name:"App",
setup(){
const data:DataProps=reactive({
arrs:["1","2","3"]
selectNum:''
selectFn:(index:number)=>{
data.selectNum=data.arrs[index];
}
})
return { //不用再加value属性,返回的时候不用一个个返回,只需返回data
data
}
}
}
</script>
接收一个普通对象然后返回该普通对象的响应式代理【等同于 2.x 的 Vue.observable()
】
reactive
类的 api
主要提供了将复杂类型的数据处理成响应式数据的能力
因为是组合函数【对象】,所以必须始终保持对这个所返回对象的引用以保持响应性【不能解构该对象或者展开】例如 const { x, y } = useMousePosition()
或者return { ...useMousePosition() }
function useMousePosition() {
const pos = reactive({
x: 0,
y: 0,
})
return pos
}
ref()
和reactive()
都是生成响应式对象,只是编写上有所不同
6.toRefs()
用reactive
输出的变量前面要加一个data.
,如果用...
扩展运算符会解构变成普通变量。不再具有响应式的能力,需要使用toRefs
- 例一:
<script lang="ts">
interface DataProps{
arrs:string[];
selectNum:string;
selectFn: (index:number)=>void;
}
import { reactive,toRefs } from "vue";
export default {
name:"App",
setup(){
const data:DataProps=reactive({
arrs:["1","2","3"]
selectNum:''
selectFn:(index:number)=>{
data.selectNum=data.arrs[index];
}
})
const refData=toRefs(data)
return {
...refData
}
}
}
</script>
- 例二:
function useMousePosition() {
const pos = reactive({
x: 0,
y: 0,
})
return toRefs(pos)
}
// x & y 现在是 ref 形式了!
const { x, y } = useMousePosition()
7.生命周期
setup()
:开始创建组件之前,在beforeCreate
和created
之前执行(可以用来代替这两个钩子函数)。创建的是data
和method
onBeforeMount()
:组件挂载在节点上之前执行的函数onMounted()
:组件挂载完成后执行的函数onBeforeUpdate()
:组件更新之前执行的函数onUpdated()
:组件更新完成之后执行的函数onBeforeUnmount()
:组件卸载之前执行的函数onUnmounted()
:组件卸载完成后执行的函数onActivated()
onDeactivated()
onErrorCaptured()
:当捕获一个来自子孙组件的异常时激活钩子函数
引申:
-
状态跟踪
onRenderTracked
:会跟踪页面上所有响应式变量和方法的状态,也就是所有return
返回的值都会跟踪。只要页面有update
的情况,就会跟踪,然后生成一个event
对象,通过event
来查找程序问题 -
状态触发
onRenderTriggered
:不会跟踪每一个值,而是给出变化值的信息。与
watchEffect
参数选项中的onTrack
和onTrigger
类似
export default {
onRenderTriggered(e) {
debugger
// 检查哪个依赖性导致组件重新渲染
},
}
8.watch
watch(text,(newValue,oldValue)=>{ .... })//watch单个值
watch([() => state.age, year], ([curAge, newVal], [preAge, oldVal]) => { console.log("新值:", curAge, "老值:", preAge); console.log("新值:", newVal, "老值:", oldVal); });
//watch监听的值需要是响应式对象或者有get\set方法
// 侦听复杂的嵌套对象 如果不使用第三个参数deep:true, 是无法监听到数据变化的。 前面我们提到,默认情况下,watch 是惰性的, 那什么情况下不是惰性的, 可以立即执行回调函数呢?其实使用也很简单, 给第三个参数中设置immediate: true即可
const state = reactive({
room: {
id: 100,
attrs: { size: "140平方米", type: "三室两厅"},
},
});
watch( () => state.room, (newType, oldType) => { console.log("新值:", newType, "老值:", oldType); }, { deep: true } );
9.slot 具名插槽语法
在 Vue2.x 中具名插槽和作用域插槽分别使用slot和slot-scope来实现, 在 Vue3.0 中将slot和slot-scope进行了合并同意使用。 Vue3.0 中v-slot:
<!-- 父组件中使用 -->
<template v-slot:content="scoped">
<div v-for="item in scoped.data">{{item}}</div>
</template>
<!-- 也可以简写成: -->
<template #content="{data}">
<div v-for="item in data">{{item}}</div>
</template>
10.在 Vue3.x 中,你可以直接写多个根节点
11.Suspense
组件
Vue3
也新增了类似 React.lazy
功能的 defineAsyncComponent
函数,处理动态引入的组件。defineAsyncComponent
可以接受返回promise
的工厂函数。当您从服务器检索到组件定义时,应该调用Promise
的解析回调
<template>
<Suspense>
<template #default>
<my-component />
</template>
<template #fallback>
Loading ...
</template>
</Suspense>
</template>
<script lang='ts'>
import { defineComponent, defineAsyncComponent } from "vue";
const MyComponent = defineAsyncComponent(() => import('./Component'));
export default defineComponent({
components: {
MyComponent
},
setup() {
return {}
}
})
</script>
12.Teleport
示例:告诉 Vue “Teleport
这个 HTML
到该‘body’
标签”
app.component('modal-button', {
template: `
<button @click="modalOpen = true">
Open full screen modal! (With teleport!)
</button>
<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>
`,
data() {
return {
modalOpen: false
}
}
})
13. vue的全局配置
可以在组件用通过 getCurrentInstance()
来获取全局globalProperties
中配置的信息,getCurrentInstance
方法获取当前组件的实例,然后通过 ctx
属性获得当前上下文,这样我们就能在setup
中使用router
和vuex
, 通过这个属性我们就可以操作变量、全局属性、组件属性等等
setup( ) {
const { ctx } = getCurrentInstance();
ctx.$http
}
14.与 React Hooks
相比
- 与
React Hooks
相同级别的逻辑组合功能,但有一些重要的区别。 与React Hook
不同,setup
函数仅被调用一次,这在性能上比较占优。 - 不存在忘记记录依赖的问题。React Hook
有臭名昭著的闭包陷阱问题,如果用户忘记传递正确的依赖项数组,
useEffect和
useMemo` 可能会捕获过时的变量。 Vue 的自动依赖跟踪可以确保侦听器和计算值总是准确无误 - 不需要顾虑调用顺序,也可以用在条件语句中;
- 不会在每次渲染时重复执行,以降低垃圾回收的压力;
- 不存在内联处理函数导致子组件永远更新的问题,也不需要
useCallback
; React Hook
里的「依赖」是需要去手动声明的,而且官方提供了一个eslint
插件,这个插件虽然大部分时候挺有用的,但是有时候也特别烦人,需要你手动加一行丑陋的注释去关闭它。
15.插件
vue-swr
:
<template>
<div v-if="error">failed to load</div>
<div v-else-if="loading">loading...</div>
<div v-else>hello {{fullName}}!</div>
</template>
<script>
import { createComponent, computed } from 'vue'
import useSWR from 'vue-swr'
export default createComponent({
setup() {
// useSWR帮你管理好了取数、缓存、甚至标签页聚焦重新请求、甚至Suspense...
const { data, loading, error } = useSWR('/api/user', fetcher)
// 轻松的定义计算属性
const fullName = computed(() => data.firstName + data.lastName)
return { data, fullName, loading, error }
}
})
</script>
16.安装升级vue3
npm install -g @vue/cli@next
export PATH="$PATH:/Users/name/.anpm_modules/bin/"
参考文章: