vue 3

脚手架搭建:
1.vue-cli
vue create [name]
2.vite
npm init vite-app [name]

vue2、vue3区别

  • vue2
    const app = new Vue(options)
    app.$mount(’#app’)

    vue3区别
    不存在构造函数Vue
    新增具名函数createApp

  • vue2
    访问属性->[组件实例]->返回属性值

    vue3
    访问属性->[组件代理对象(proxy)]->访问属性->[组件实例]->返回属性值->[组件代理对象(proxy)]->返回属性值

  • option api
    任务分散到各个option里面,代码维护不方便
    适用于功能不多,简单功能模块

    composition api
    高内聚,把功能的模块聚集到一起
    // reactivity api 响应式api
    import {ref, watchEffect, computed} from ‘vue’;
    export default {
    setup() { // composition api
    console.log(“所有生命周期钩子函数之前调用”);
    console.log(“this -> undefined”, this); // this -> undefined
    let count = ref(0);
    const increase = () => {
    count.value ++;
    };
    // 里面用个数据,只要发生变化就会重新执行这里面的函数
    watchEffect(() => {

          })
          // 返回的对象会附着到组件实例里面去
          return {
            increase,
            count,
          };
        }
      }
    

vue3 生命周期

import {ref, onMounted, onUnMounted, computed, watchEffect} from 'vue';
// 里面用个数据,只要发生变化就会重新执行这里面的函数
watchEffect(() => {
                
})

// 里面用个数据,只要发生变化就会重新执行这里面的函数,并返回赋值,类似watchEffect
const fiflteredValue = computed({
    get() {
    }
    set() {
    }
})

Vite

webpack  先打包后启动服务
    module 1~n -> webpack -> bound -> webserver


vite(启动的是Koa服务,并没有打包) rollup
    页面 -> devserver
    vite -> devserver -> module

客户端渲染效率比Vue2提升了1.3-2倍
SSR渲染效率比Vue2提升了2-3倍

面试题:Vue3效率提升主要表现在哪学方面?
#静态提升
下面的静态节点会被提升
- 元素节点
- 没有绑定动态内容

    // vue2 的静态节点
    render() {
        createVNode("h1", null, "Hello world");
    }
        
    // vue3 的静态节点
    const hoisted = createVNode("h1", null, "Hello world");
    render() {
            // 使用hoisted
    }                    

静态属性会被提升

    <div class="user">
        {{ user.name }}
    </div>               
    const hoisted = { class: "user" }
    function render() {
        createVNode("div", hoisted, user.name);       
    }

预字符串化

当编译器遇到大量(大概20个)连续的静态内容时,会直接将其编译为一个普通字符串

缓存事件处理函数

<button @click="count ++">plus</button>    
// vue2
function render() {
    return createVNode("button",{
        onclick: function($event) {
          ctx.count ++;
        }
    })
}

// vue3
function render(ctx, _cache) {
    return createVNode("button", {
        onclick: _cache[0] || (_cache[0] = ($event) => (ctx.count ++))
    })        
}

Block Tree

vue2在对比新旧树的时候,并不知道哪些节点是静态的,哪些是动态的,因此只能一层一层比较,这就比较浪费大部分时间在对比静态节点上
vue2(广度优先对比)

vue3在根节点记录哪些是静、动态;
block里面记录所有动态节点数组

树不稳定的会自己生成一个block

PatchFlag

vue2在对比每一个节点,并不知道这个节点哪些相关信息会发生变化,因此只能将所有信息一次比对
她会给

面试题1:为什么vue3中去掉了vue的构造函数?

在过去,如果遇到一个页面有多个vue应用时,往往会遇到一些问题
遇上插件【use,mixin】就全局vue应用都有了
vue3中,去掉vue构造函数函数,转而使用createApp创建vue应用,
把影响广的API提到实例里面去了

vue2的全局构造函数带来了诸多问题:
1.调用构造函数的静态方法会对所有vue应用生效,不利于隔离不同应用
2.vue2的构造函数集成了太多功能,不利于tree shaking,vue3把这些功能使用普通函数导出,能够充分利用tree shaking优化打包体积
3.vue2没有把组件实例和vue应用两个概念区分开,在vue2中,通过new vue创建的对象,既是一个vue应用,同时又是一个特殊的Vue组件组件,
在vue3中,把两个概念区别开来,通过createApp创建的对象,hi是一个vue应用,它内部提供的方法是针对整个应用的,而不再是一个特殊的组件。

面试题2:谈谈你对vue3数据响应式的理解

vue3不再使用Object.defineProperty的方式定义完成数据响应式,而是使用Proxy。
除了Proxy本身效率比Object.defineProperty更高之外,由于不必要递归遍历所有属性属性,而是直接得到一个Proxy,
所以在vue3,对数据的访问是动态的,当访问某个属性的时候,再动态获取和设置,这就极大的提升了在组件初始化阶段的效率。
同时,由于Proxy可以监控到成员新增和删除,因此,在vue3中新增成员,删除成员、索引访问等均可以触发重新渲染,而这些vue2中是难以做到的。

获取响应式数据

reactive plain-object 对象代理 深度代理对象中的所有成员
readonly plain-object or proxy 对象代理 只能读取对象中的成员,不可修改
ref any {value: …} 对value的访问是响应式的,如果给value的值是一个对象,则会通过reactive函数进行代理,如果已经是代理,则直接使用代理
computed function {value: …} 当读取的value值时,会根据情况决定是否运行函数

应用

  • 如果想要让一个对象变成响应式数据,可以使用reactive或ref
  • 如果想要让一个对象的所有属性只读,使用readonly
  • 如果想要让一个非对象数据变为响应式数据,使用ref数据
  • 如果想要根据已知的响应式数据得到一个新的响应式数据,使用computed

监听数据变化

watchEffect

const stop = watchEffect(() => {
        // 该函数会立即执行,然后追中函数中用到的响应式数据,响应式数据变化后会被再次执行
})

// 通过调用stop函数,会停止监听
stop(); // 停止监听

watch

// 等于vue2的$watch
// 监听单个数据的变化
const state = reactive({count: 0})
watch(() => state.count, (newValue, oldValue) => {
   // ...    
}, options)

const countRef = ref(0);
watch(countRef, (newValue, oldValue) => {
   // ...    
}, options)

// 监听多个数据的变化
watch([() => state.count, countRef], ([new1, new2], [old1, old2]) => {
   // ...
});

注意: 无论是watchEffect还是watch,当依赖项发生变化时,会调函数的运行都是异步的(微队列)
应用:除非遇到下面场景,否则均建议选择watchEffect
- 不希望会调函数一开始就执行
- 数据改变时,需要参考旧值
- 需要监控一些回调函数中不会用到的数据

判断

API含义
isProxy判断某个数据是否是由reactive或者readonly
isReactive判断某个数据是否是通过reactive创建的
isReadonly判断某个数据是否是通过readonly创建的
isRef判断某个数据是否是一个ref对象

转换

unref
等同于:isRef(val) ? val.value : val
应用:

function useNewTodo(todos) {
   todos = unref(todos);
   // ...        
}

toRef
得到一个响应式对象某个属性的ref格式

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

const fooRef = toRef(state, 'foo')
fooRef.value ++
console.log(state.foo)  // 2

state.foo ++
console.log(fooRef.value) // 3

toRefs
把一个响应式对象的所有属性转换为ref格式,然后包装到一个plain-object中返回

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

const stateAsRefs = toRefs(state)
/*
stateAsRefs: not a proxy
{
   foo: {value: ...},
   bar: {value: ...}        
}
*/

应用:

    setup() {
    const state1 = reactive({a: 1,b: 2});
    const state2 = reactive({c: 3,d: 4});
    return {
       ...state1, // lost reactivity
       ...state2, // lost reactivity
    }    
}

    setup() {
    const state1 = reactive({a: 1,b: 2});
    const state2 = reactive({c: 3,d: 4});
    return {
       ...toRefs(state1), //  reactivity
       ...toRefs(state2), //  reactivity
    }            
}

function usePos() {
    const pos = reactive({x: 0, y: 0});
    return pos;    
}

setup() {
    const {x, y} = usePos(); // lost reactivity
    const {x, y} = toRefs(usePos()); //  reactivity 
}

降低心智负担

所有的composition function均以ref的结果返回,以保证setup函数的返回结果中不包含reactive或readonly直接产生的数据

#setup

不同于reactivity api,composition api提供的函数很多是与组件深度绑定的,不能脱离组件而存在。

export default() {
    setup(props, context) {
        // 该函数在组件属性被赋值后立即执行,早于所有生命周期钩子函数
        // props 是一个对象,包含了所有的组件属性值
        // context 是一个对象,提供了组件所需要的上下文信息            
    }
}

context对象的成员

成员类型说明
attrs对象同vue2的this.$attrs
slots对象同vue2的this.$slots
emit方法同vue2的this.$emit

生命周期函数

vue2 option apivue3 option apivue3 composition api
beforeCreatebeforeCreate不再需要,代码可直接置于setup中
createdcreated不再需要,代码可直接置于setup中
beforeMountbeforeMountonBeforeMount
mountedmountedonMounted
beforeUpdatebeforeUpdateonBeforeUpdate
updatedupdatedonUpdated
beforeDestroy改beforeUnmountonBeforeUnmount
destroyed改unmountedonUnmounted
errorCapturederrorCapturedonErrorCaptured
-新renderTrackedonRenderTracked
-新renderTriggeredonRenderTriggered

新增钩子函数

钩子函数参数执行时机
renderTrackedDebuggerEvent渲染vdom收集到的每一次依赖时
renderTriggeredDebuggerEvent某个依赖变化导致组件重新渲染时

面试题参考答案

面试题:composition api相比于option api有哪些优势?

从两个方面回答:
1.为了更好的逻辑复用和代码组织
2.更好的类型指导

有了composition api,配合reactivity api,可以在组件内部进行更加细粒度的控制,使得组件中不同的功能高度
聚合,提升了代码的可维护性。对于不同的组织的相同功能,也能够更好的复用。
相比于option api,composition api中没有了指向奇怪的this,所有的api变得更加函数式,这有利于和类型推断
系统比如TS深度配合

gsap 数据逐渐变化库

vuex方案

安装vuex@4.x
两个重要变动

  • 去掉了构造函数vuex,而是用createStore创建仓库
  • 为了配合composition api,新增useStore函数获得仓库对象

#global state
由于vue3的响应式系统本身可以脱离组件而存在,因此可以充分利用这一点,轻松制造多个全局响应式数据

// store/useLoginUser 提供当前登陆用户的共享数据
import { reactive, readonly} from 'vue';
import * as userServ from './api/user'; // 导入api模块

// 创建默认的全局单例响应式数据,仅供该模块内部使用
const state = reactive({user: null, loading: false});

// 对外暴露的数据是只读的,不能直接修改
// 也可以进一步使用toRefs进行封装,从而避免解构或展开后响应式丢失
export const loadingUserStore = readonly(state);

// 登陆
export async function login(loginId, loginRwd) {
    state.loading = true;
    const user = await userServ.login(loginId, loginRwd);
    state.loginUser = user;
    state.loading = false;
}

缺点: 多个vue应用,如果引用的话,会共享

provide&Inject

在vue2中,提供了provide和Inject配置,可以让开发者在高层组件中注入数据,然后在后代组件中使用
除了vue2的配置式注入,vue3在composition api中添加了provide方法,用于提供整个应用的共享数据

对比

支持vuexglobal stateProvide&Inject
组件数据共享☑️☑️☑️
可否脱离组件☑️☑️✖️
调试工具☑️✖️️☑️
状态树☑️️自行决定自行决定
量级重️
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值