学习Vue3笔记

119 阅读2分钟

为啥要升级到Vue3

  1. Vue2(选项式API/OptionsAPI)逻辑的组织和复用困难;
  2. 相同的数据逻辑散落在不同的选项中,逻辑分散而混乱,本身就难以维护
  3. 而且复用困难(唯一跨组件复用逻辑的方式就是mixin,而mixin的冲突和难追踪问题是很严重)
  4. Vue3的最主要更新就是组合式API(CompositionAPI),将各种选项都定义为可移植和复用的hook;
  5. 最终达到效果:生命周期可以复用,计算属性和监听器可复用,最终通过将自带【响应式数据】+【数据自变化逻辑】的业务模块封装为【自定义hook】,在不同组件间随意复用
  6. 最终散落的逻辑被收拢到一个【自定义hook】中,且【自定义hook】是可以跨组件复用的;
  7. 另外Vue3将底层的响应式数据监听模式由Object.defineProperties修改为了【代理Proxy+反射模式Reflect】,事实上通过浏览器的JS引擎的底层寻址功能轻易监听数据变化,实现了【更小、更快、更轻】;

image.png

组合式API
setup选项
  • 入参props:父组件传入的props
  • 入参context:能够结构得到以下内容:
{ attrs, slots, emit, expose }
生命周期变化

Vue2组件的8大生命周期

beforeCreate() {
        console.log('beforeCreate')
},
created() {
        console.log('created')
},

beforeMount() {
        console.log('beforeMount')
},
mounted() {
        console.log('mounted')
},

beforeUpdate() {
        console.log('beforeUpdate')
},
updated() {
        console.log('updated')
},

// beforeDestroy 改名
beforeUnmount() {
        console.log('beforeUnmount')
},
// destroyed 改名
unmounted() {
        console.log('unmounted')
}

Vue3组件的生命周期

import {
    onBeforeMount,
    onMounted,
    onBeforeUpdate,
    onUpdated,
    onBeforeUnmount,
    onUnmounted,
} from "vue";

export default {
    ...

    // 等于 beforeCreate 和 created
    setup() {
        console.log("setup");

        onBeforeMount(
                () => {
                        console.log("onBeforeMount");
                }
        );
        onMounted(() => {
                console.log("onMounted");
        });

        onBeforeUpdate(() => {
                console.log("onBeforeUpdate");
        });
        onUpdated(() => {
                console.log("onUpdated");
        });

        onBeforeUnmount(() => {
                console.log("onBeforeUnmount");
        });
        onUnmounted(() => {
                console.log("onUnmounted");
        });
    },

}
响应式数据
ref
reactive toRef toRefs
获取DOM元素
<template>
    <p ref="elemRef">我是一行文字</p>
</template>
import { ref, onMounted } from 'vue'
setup() {
    // 创建一个响应式值(存储元素地址)
    const elemRef = ref(null)
    
    // 其它操作...

    /* 向模板返回响应式数据 */
    return {
        elemRef
    }
}

elemRef.value.innerText = "我是修改后的文本"

完整例子

<template>
    <p ref="elemRef">我是一行文字</p>
</template>

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

export default {
    name: 'RefTemplate',
    setup() {
        // 创建一个响应式值(存储元素地址)
        const elemRef = ref(null)

        // 挂载成功后获取DOM元素
        onMounted(() => {
            console.log( elemRef.value)
            elemRef.value.innerText = "我是修改后的文本"
        })

        /* 向模板返回响应式数据 */
        return {
            elemRef
        }
    }
}
</script>

computed
watch与watchEffect
监听单个数据
const numberRef = ref(100);
setTimeout(() => {
        numberRef.value = 200;
}, 2000);
watch(
    numberRef,
    (newNumber, oldNumber) => {
        console.log("ref watch", newNumber, oldNumber);
    },
    {
        immediate: true, // 初始化之前就监听,可选
    }
);

监听多个数据(自动收集依赖)
const numberRef = ref(100);
const state = reactive({
  name: "张全蛋",
  age: 20,
  wife: {
    money: 123,
    friends: ["陈顶天", "陈顶地"],
  },
});

setTimeout(() => {
  state.age = 25;
}, 1500);

setTimeout(() => {
  numberRef.value += 1;
}, 3000);

setInterval(() => (state.wife.money += 1), 1000);

watchEffect(() => {
  console.log(numberRef.value);
  console.log(state.age);
});

watchEffect(() => {
  console.log("watch [state.wife.money]", state.wife.money);
});

深度监听
setTimeout(() => { // state.wife.money += 100 state.wife.friends.push("希哥"); }, 2000);
watch(
    // 第一个参数,确定要监听哪个属性
    () => state.wife,

    // 第二个参数,回调函数
    (newWife, oldWife) => {
        console.log('watch wife deep', newWife, oldWife)
    },

    // 第三个参数,配置项
    {
        immediate: true, // 初始化之前就监听,可选
        deep: true // 深度监听
    }
)

setup简写
自定义hook