助你上手Vue3全家桶之Vue3教程

前言

这些内容是博主在学习过程中记录下来的,有一些不重要的点就跳过了,需要时自行查询文档。其实V2V3的学习成本不高,熟悉V2的话,看完这篇文章就可以上手V3

Vue3官网

在线源码编译地址

1,setup


setup是所有Composition API的容器,值为一个函数。组件中所用到的数据、方法等等,均要配置在setup中,它会在beforeCreate之前执行一次,注意:V3this不再是指向Vue实例,访问this会是undefined

1.1,返回值


  • 若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。
  • 若返回一个渲染函数:则可以自定义渲染内容。

1.2,注意点


尽量不要与V2配置混用

V2配置(datamethoscomputed...)中可以访问到setup中的属性、方法。
但在setup中不能访问到V2配置(datamethodscomputed...)。
如果有重名, setup优先。

setup不能是一个async函数

因为返回值不再return的对象, 而是promise, 模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)

1.3,语法


<script>
import { ref, reactive } from 'vue'

export default {
    name: 'Home',
    setup(props, context) {
        const title = ref('标题')
        const data = reactive({
            value: '哈哈哈'
        })
        return {
          title,
          data
        }
    }
}
</script>

1.4,setup的参数


  • props:值为对象,包含组件外部传递过来,且组件内部声明接收了的属性

  • context:上下文对象

    • attrs: 值为对象,包含组件外部传递过来,但没有在props配置中声明的属性, 相当于this.$attrs
    • slots: 收到的插槽内容, 相当于this.$slots
    • emit: 分发自定义事件的函数, 相当于this.$emit

2,ref 创建响应式数据


使用ref可以创建一个包含响应式数据的引用对象(reference对象,简称ref对象),可以是基本类型、也可以是对象。

语法

// 创建
const xxx = ref(value)

// 使用
xxx.value

// 在模板中
<div>{{xxx}}</div>

3,reactive 创建响应式数据


定义一个对象类型的响应式数据,内部基于ES6Proxy实现,通过代理对象操作源对象内部数据进行操作

语法

// 创建
const xxx = reactive({
    xxx: ''
})

// 使用
xxx.xxx

4,computed 计算属性


V2computed配置功能一致

语法

import { computed } from 'vue'

setup(){
    // 简写语法
    let fullName = computed(() => {
        return person.firstName + '-' + person.lastName
    })
    
    // 完整语法
    let fullName = computed({
        get(){
            return person.firstName + '-' + person.lastName
        },
        set(value){
            const nameArr = value.split('-')
            person.firstName = nameArr[0]
            person.lastName = nameArr[1]
        }
    })
    
    return fullName
}

5,watch 监听


V2watch配置功能一致,语法有点改动

语法

  • 情况一:监视ref定义的响应式数据
watch(sum, (newValue, oldValue) => {
    console.log('sum变化了', newValue, oldValue)
}, {immediate:true})
  • 情况二:监视多个ref定义的响应式数据
watch([sum, msg], (newValue,oldValue) => {
    console.log('sum或msg变化了', newValue,oldValue)
}) 
  • 情况三:监视reactive定义的响应式数据
// 若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue
// 若watch监视的是reactive定义的响应式数据,则强制开启了深度监视
watch(person, (newValue, oldValue) => {
    console.log('person变化了', newValue, oldValue)
}, { immediate:true, deep:false }) // 此处的deep配置不再奏效
  • 情况四:监视reactive定义的响应式数据中的某个属性
watch(() => person.job, (newValue, oldValue) => {
    console.log('person的job变化了', newValue, oldValue)
}, { immediate:true, deep:true }) 
  • 情况五:监视reactive定义的响应式数据中的某些属性
watch([() => person.job, () => person.name], (newValue, oldValue) => {
    console.log('person的job变化了', newValue, oldValue)
}, { immediate:true, deep:true })
  • 特殊情况:此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
watch(() => person.job, (newValue, oldValue) => {
    console.log('person的job变化了', newValue, oldValue)
}, { deep:true })

6,watchEffect 监听回调


watch的区别是,watch既要指明监视的属性,也要指明监视的回调。而watchEffect,不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性,不用写返回值。

语法

// 回调中用到的数据只要发生变化,则直接重新执行回调
watchEffect(() => {
    const x1 = sum.value
    const x2 = person.age
    console.log('watchEffect配置的回调执行了')
})

7,生命周期


生命周期全都写在setup

7.1,改变


  • beforeDestroy 改名为 beforeUnmount
  • destroyed 改名为 unmounted
  • beforeCreate => setup
  • created => setup
  • beforeMount => onBeforeMount
  • mounted => onMounted
  • beforeUpdate => onBeforeUpdate
  • updated => onUpdated
  • beforeUnmount => onBeforeUnmount
  • unmounted => onUnmounted

7.2,语法


setup() {
    onMounted(() => {
      console.log('mounted')
    })
}

8,toRef 创建ref


创建一个ref对象,其value值指向另一个对象中的某个属性

语法

const state = reactive({
  foo: 1,
  bar: 2
})

const fooRef = toRef(state, 'foo')

// 传递props
export default {
  setup(props) {
    useSomeFeature(toRef(props, 'foo'))
  }
}

9,toRefs 响应式转换


将响应式对象转换为普通对象,其中结果对象的每个property都是指向原始对象相应propertyref

语法

const state = reactive({
  foo: 1,
  bar: 2
})

const stateAsRefs = toRefs(state)
// 此时state和stateAsRefs是关联的

10,shallowReactive 响应式外层转换


只处理对象最外层属性的响应式(浅响应式)。适用于:一个对象数据,结构比较深, 但变化时只是外层属性变化

语法

const state = shallowReactive({
  foo: 1,
  nested: {
    bar: 2
  }
})

11,shallowRef 基本数据响应式


只处理基本数据类型的响应式, 不进行对象的响应式处理。适用于:一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换

语法

const shallow = shallowRef({
  greet: 'Hello, world'
})

12,readonly 响应式变只读


让一个响应式数据变为只读的(深只读),应用于不希望数据被修改时

语法

const shallow = shallowRef({
  greet: 'Hello, world', // 只读
  nested: {
    bar: 2 // 只读
  }
})

13,shallowReadonly 响应式变只读


让一个响应式数据变为只读的(浅只读),应用于不希望数据被修改时

语法

const shallow = shallowReadonly({
  foo: 1, // 只读
  nested: {
    bar: 2 // 非只读
  }
})

14,toRaw 响应式变非响应式


将一个由reactive生成的响应式对象转为普通对象,对这个普通对象的所有操作,不会引起页面更新。

语法

const foo = {}
const Foo = reactive(foo)
console.log(toRaw(Foo) === foo) // true

15,markRaw 标记永远不响应式


标记一个对象,使其永远不会再成为响应式对象,有些值不应被设置为响应式的,例如复杂的第三方类库等,当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。

语法

const foo = markRaw({})
console.log(isReactive(reactive(foo))) // false

// 嵌套在其他响应式对象中时也可以使用
const bar = reactive({ foo })
console.log(isReactive(bar.foo)) // false

16,customRef 依赖更新控制


创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收tracktrigger函数作为参数,并且应该返回一个带有getset的对象。

语法

<script>
import { customRef } from 'vue'

export default {
    name: 'Home',
    setup() {
        // 实现防抖函数
        const fn = function(value, delay = 500) {
            let timeout
            return customRef((track, trigger) => {
                return {
                    get() {
                        track()
                        return value
                    },
                    set(newValue) {
                        clearInterval(timeout)
                        timeout = setTimeout(() => {
                            console.log(newValue)
                            value = newValue
                            trigger()
                        }, delay)
                    }
                }
            })
        }
        const keyword = fn('', 500)
        return {
            keyword
        }
    }
}
</script>

17,provide & inject 通信


实现祖与后代组件间通信,父组件有一个provide选项来提供数据,后代组件有一个inject选项来开始使用这些数据

语法

// 祖组件
setup(){
    let car = reactive({ name:'奔驰', price:'40万' })
    provide('car', car)
}

// 后代组件
setup(props, context){
    const car = inject('car')
    return { car }
}

18,响应式数据的判断


18.1,isRef


检查一个值是否为一个ref对象

语法

const val = ref('xxx')
isRef(val) // true

18.2,isReactive


检查一个值是否为一个isReactive对象

语法

const val = isReactive({})
isRef(val) // true

18.3,isReadonly


检查一个对象是否是由readonly创建的只读代理

语法

const state = reactive({
  name: 'John'
})
console.log(isReactive(state)) // true

18.4,isProxy


检查对象是否是由reactivereadonly创建的proxy

语法

const state = reactive({
  name: 'John'
})
console.log(isProxy(state)) // true

19,teleport 移动dom组件


Teleport提供了一种干净的方法,允许我们控制在DOM中哪个父节点下渲染了HTML,而不必求助于全局状态或将其拆分为两个组件。

语法

<teleport to="移动位置">
    <div v-if="isShow" class="mask">
        <div class="dialog">
            <h3>我是一个弹窗</h3>
            <button @click="isShow = false">关闭弹窗</button>
        </div>
    </div>
</teleport>


// to的格式
<teleport to="#some-id" />
<teleport to=".some-class" />
<teleport to="[data-teleport]" />

// disabled的格式
<teleport to="#popup" :disabled="displayVideoInline">
  <video src="./my-movie.mp4">
</teleport>

20,Suspense 异步渲染组件


等待异步组件时先渲染一些额外内容,让应用有更好的用户体验

语法

<template>
    <div class="app">
        <h3>我是App组件</h3>
        <Suspense>
            <template #default>
                <Child/>
            </template>
            <template #fallback>
                <h3>加载中.....</h3>
            </template>
        </Suspense>
    </div>
</template>


import { defineAsyncComponent } from 'vue'
const Child = defineAsyncComponent(() => import('./components/Child.vue'))

components: {
    Child
}

21,全局API调整


将全局的API,即:Vue.xxx调整到应用实例(app)上

V2的api V3的api
Vue.config.xxxx app.config.xxxx
Vue.component app.component
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use
Vue.prototype app.config.globalProperties

22,移除api


名称 现状
Vue.config.productionTip 已移除
config.keyCodes 已移除
$children 已移除
$listeners 已移除
$on 已移除
$off 已移除
$once 已移除
filters 已移除
.native 已移除

23,Ref 获取DOM


由于V3中不在存在this,所以ref的获取调整了

23.1,单个ref


语法

<div ref="Qrcode" class="qr_codeode_url" />

import { ref } from 'vue'

export default {
  setup() {
    const Qrcode = ref(null)
    // 挂载后
    onMounted(() => {
        console.log(Qrcode.value)
    })
    return {
      Qrcode
    }
  }
}

23.2,循环中的ref


V3中在for循环元素上绑定ref将不再自动创建$ref数组。要从单个绑定获取多个ref,请将ref绑定到一个更灵活的函数上

语法

<div v-for="item in list" :ref="setItemRef"></div>

import { onBeforeUpdate, onUpdated } from 'vue'

export default {
  setup() {
    let itemRefs = []
    const setItemRef = el => {
      if (el) {
        itemRefs.push(el)
      }
    }
    onBeforeUpdate(() => {
      itemRefs = []
    })
    onUpdated(() => {
      console.log(itemRefs)
    })
    return {
      setItemRef
    }
  }
}
  • itemRefs不必是数组:它也可以是一个对象,其ref可以通过迭代的key被设置
  • 如有需要,itemRef也可以是响应式的,且可以被侦听

24,emits 自定义事件


定义一个组件可以向其父组件触发的事件

// 在子组件中
<h1 @click="father">{{ msg }}</h1>

export default {
    name: 'HelloWorld',
    props: {
        msg: {
            type: String,
            default: ''
        }
    },
    emits: ['close'],
    setup(props, { emit }) {
        const father = function() {
            emit('close', 'child')
        }
        return {
            father
        }
    }
}

// 在父组件中
<HelloWorld :msg="msg" @click="fn" @close="fn2" />

25,$nextTick 异步更新


使用方式修改

import { nextTick } from 'vue'

nextTick(() => {
  // ...
})

26,hook 生命周期事件


通过事件来监听组件生命周期中的关键阶段

语法

// V2的语法
<template>
  <child-component @hook:updated="onUpdated">
</template>

// V3的语法
<template>
  <child-component @vnode-updated="onUpdated">
</template>

// 驼峰写法
<template>
  <child-component @vnodeUpdated="onUpdated">
</template

如果看了觉得有帮助的,我是@鹏多多11997110103,欢迎 点赞 关注 评论;
END

PS:在本页按F12,在console中输入document.querySelectorAll('._2VdqdF')[0].click(),有惊喜哦

往期文章

个人主页

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容