vue3.2、vue3和vue2不同之处

缩写记忆:
tv code2&tf spa
tv code2: defineProps和defineEmits、defineExpose、useSlots和useAttrs)
event 缓存
template,vite,composition ApI,生命周期都加on,diff算法优化(添加标记,增量diff),dom优化、expose
typescript,function编程vue3新增了一个名为setup的入口函数,value, computed, watch, onMounted等方法都需要从外部import。 setup pinia api
在这里插入图片描述
expose: 子组件是

1.data侦听从object.defineproperty=> proxy
缺点增加对象key,不能响应,需要$set(this.obj,‘key’,‘value’)

const person = {
name: '炫H5',
age: 20
};
Object.keys(person).forEach(function(key) {
Object.defineProperty(person, key, {
enumerable: true,
configurable: true,
get: function() {
console.log('get');
},
set: function(newVal) {
// 当属性值发生变化时我们可以进行额外操作
console.log(`欢迎大家来到${newVal}`);
},
});
});
person.name = '炫H5前端博客';
//欢迎大家来到炫H5前端博客
//"炫H5前端博客"

proxy劫持方法更多,有11种,比如apply,has,construct等。

const queuedObservers = new Set();
const observe = fn => queuedObservers.add(fn);
const observable = obj => new Proxy(obj, {set});
function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
queuedObservers.forEach(observer => observer());
return result;
}
const person = observable({
name: '炫H5',
age: 5
});
function print() {
console.log(`${person.name}, ${person.age}年了`)
}
observe(print);
person.name = '炫H5前端博客已经有';

2.setup中生命周期加了on,destroy=> onunmount、create=>setup
setup外可以用vue2的生命周期。
在这里插入图片描述

3.vite代替webpack
自动注册
vue2:require.context()

const requireComponent = require.context(
    // 其组件目录的相对路径
    '@/components',
    // 是否查询其子目录
    true,
    // 匹配基础组件文件名的正则表达式
    /index.vue$/
)

vue3:import.meta.globEager

// 自动导入公共组件
const modulesFiles:any = import.meta.globEager('./components/*/*.vue')
// console.log(modulesFiles,"看看是什么东西")

Vite 用 esbuild 替代 Rollup 进行预打包,速度也非常快,上面的第三点可以看到生产可以用 esbuild 作为压缩器。生产打包还是用的Rollup, esbuild 目前对生产包支持不够健壮,很多配置无法通过 esbuild 实现

4.template只能有一个根节点改为多个

5.diff算法优化
tag:‘div’,
props:{
className:‘container’,
id:‘div1’
},
children:[//没有children就是text
{
tag:‘p’,
children:‘text’
}
]

所以vue3 针对此问题,在此基础上做出了优化:

标记模板中的静态内容,区别了模板中的静态和动态节点
更新时,只diff操作动态的内容
Vue3中会首先区分出以上模板的静态节点和动态节点,当视图更新时,只对动态节点部分进行diff运算,减少了资源的损耗
参考链接

6.dom创建优化,静态提升 hoistStatic
参考:https://juejin.cn/post/6898503749351047175
vue2的基于snabbdom优化,diff
在Vue2中无论元素是否参与更新,每次都会重新创建,然后再渲染。如下图所示,每次都会createVNode。
但是在Vue3中使用了静态提升后,对于不参与更新的元素,只会被创建一次,在渲染时直接复用即可:

7.event事件侦听器缓存 cacheHandlers
1 vue2.x中,绑定事件每次触发都要重新生成全新的function去更新
2 cacheHandlers 是Vue3中提供的事件缓存对象
3 当 cacheHandlers 开启,会自动生成一个内联函数,同时生成一个静态节点。当事件再次触发时,只需从缓存中调用即可,无需再次更新

8.ssr
Vue2 中也是有 SSR 渲染的,但是 Vue3 中的 SSR 渲染相对于 Vue2 来说,性能方面也有对应的提升。

9.composition &setup
vue2的Options API 和 vue3的Composition API

Options API 约定:

我们需要在 props 里面设置接收参数

我们需要在 data 里面设置变量

我们需要在 computed 里面设置计算属性

我们需要在 watch 里面设置监听属性

我们需要在 methods 里面设置事件方法

你会发现 Options APi 都约定了我们该在哪个位置做什么事,这反倒在一定程度上也强制我们进行了代码分割。

现在用 Composition API,不再这么约定了,于是乎,代码组织非常灵活,我们的控制代码写在 setup 里面即可。
setup函数里面是没有this对象、必须return、在beforeCreate之前执行。
在vue2中,watch、computed、data、method等API都是直接作为对象的属性
vue3中Composition API,用setup包裹,响应式用ref(),reactive()
在此之前,Vue2.x 的 Mixins 以及 react 的高阶组件等模式都可以实现逻辑的组合与复用,但它们都存在数据来源不清晰、命名空间冲突以及性能的问题。写到这里,要向 react 致敬,因为 React Hooks 的出现是革命性的,而 Vue3 的 composition-api 提供的全新的逻辑复用方案也是受到了 React Hooks 的启发。
但是要return方法和data

const data = reactive({
      orderTab:[{
        icon:"send-gift-o",
        text:"待付款"
      },{
        icon:"send-gift-o",
        text:"待发货"
      },{
        icon:"todo-list-o",
        text:"待收货"
      },{
        icon:"point-gift-o",
        text:"待评价"
      }]
    })
    let methodsMap = {
      // 设置
      setting:()=>{
        router.push({path:'setting'})
      }
    }
    return {
      ...methodsMap,
      ...toRefs(data)
    }
  }

但是vue3也支持option API

<template>
  <div>
    <p>{{ text1 }}</p>
    <button @click="myFun1">按钮1</button>
    <p>{{ age }}</p>
    <button @click="myfun2">按钮2</button>
  </div>
</template>
 
<script>
import { ref } from "vue";
 
export default {
  name: "App",
  data() {
    return {
      text1: "option api",
    };
  },
  // setu函数是组合api的入口函数
  setup() {
    let age = ref(20);
    function myfun2() {
      alert("llooppp");
    }
    return { age, myfun2 };
  },
 
  components: {},
 
  methods: {
    myFun1() {
      alert("abcdefg");
    },
  },
};
</script>

9.1暴露给模版的属性来源清晰(从函数返回);
9.2不存在命名空间冲突,返回值可以被任意重命名,并且组件可以用点语法;
9.3受到了 React Hooks 的启发,没有创建额外的组件实例所带来的性能损耗。

可读性强,不用跳跃式查找

importuseAfrom'./a';
importuseBfrom'./b';
importuseCfrom'./c';
exportdefault{
 setup (props) {
 let{ a, methodsA } = useA();
 let{ b, methodsB } = useA();
 let{ c, methodsC } = useC();
 return{
   a,
    methodsA,
    b,
    methodsB,
    c,
    methodsC
  }
 }
}


<template>
    <div ref="div">
     这个是div
    </div>
</template>
<script lang="ts">
import { defineComponent,onMounted,ref } from 'vue'
 
export default defineComponent({
    setup() {
       const div=ref(null) //本质是reactive({value:null})
       // 错误用法
       // this.$refs.div
 
       //正确用法
 
       // 需要再onMountd 生命周期内使用
       onMounted(()=>{ 
           // 界面挂载完后 会执行
           console.log(div.value)
       })
       //接受的是null,原因是setup执行时机比mounted早,dom还没形成 注意vue3的生命周期
        console.log(div.value);// 执行早于 onMounted
        return {
            div
            }
    },
})
</script>
<template>
    <div>
        <button @click="click"></button>
        // 直接引用变量获取值
        <p>{{num}}</p>
    </div>
</template>
<script lang="ts">
import { defineComponent,ref } from 'vue'
 
export default defineComponent({
    setup() {
        // 声明双向数据ref
        const num=ref()
        // js 通过.value 获取值
        num.value=123;
        const click = ()=>{
            num.value+=1;
        }
        return {
            num,
            click
            }
    },
})
</script>
<template>
  <div>
    <p>{{ user }}</p>
    <button @click="increase">click me! one year later</button>
  </div>
</template>
 
<script>
import { reactive } from "vue";
export default {
  name: "reactive",
  setup() {
    const user = reactive({ name: "Alice", age: 12 });
    function increase() {
      ++user.age
    }
    return { user, increase };
  },
};
</script>

如果觉得return麻烦,可以用script setup,还提供3个方法:
defineProps、defineEmits、useContext
参考连接

vue3函数式编程思路,支持ts更丝滑
使用方法:创建vue-cli4.5以上版本,支持vue3

vue3实例化,函数式编程
createApp(App).use(store).use(router).use(Vant).use(global).mount(‘#app’)

vue2面向对象方式
new Vue({
router,
store,
i18n,
render: h => h(App)
}).$mount(‘#app’)

10.ts类型检查,从flow改为ts
支持tsx对标react jsx
但是不能用v-for、v-if、@click,要用map,三目运算符,onClick
如何使用tsx:

import * as vue from 'vue';
const React = { createElement: vue.h, Fragment: vue.Fragment }

export const Hello = vue.defineComponent({
    props: {
        message: String
    },
    setup(props) {
      return () => <div>{ props.message }</div>
    }
})

11.1fun函数式编程思想,借鉴react
函数作为第一对象
闭包,return对象
没用new 类名。
函数作为参数传递,柯里化
不需要new 对象,直接调用函数。
vue2
new Vue({
router,
store,
render: h => h(App)
}).$mount(‘#app’)
vue3
createApp(App)
app.use(router)
app.use(store,key)
app.mount(‘#app’)

11.1 使用import来按需引入
vue2是将mounted,data,computed,watch之类的方法作为一个对象的属性进行导出。
vue3新增了一个名为setup的入口函数,value, computed, watch, onMounted等方法都需要从外部import。
使用自定义方法(ref、state、reactive、toRef、toRefs等)前需要引入
import { useStore } from “@/store”;
import { useRoute } from “vue-router”;
import { ref, reactive,computed, toRef, toRefs } from “vue”;
优点是:
首先就是我们需要写的代码量少了,
其次就是我们可以封装更多的子函数、引用更多的公共函数去维护我们的代码,
第三就是代码的可读性变高了。(当然,我们的打包体积也会变小)
参考

12.vue2用eventbus,vue3用mitt.js跨组件传值

Vue3 从实例中完全删除了 o n 、 on、 onoff 和 $once 方法
那么官方推荐的做法是使用第三方库:

mitt.js
tiny-emitter
@ai-zen/event-bus -S

npm i @ai-zen/event-bus -S

import { eventBus } from "@ai-zen/event-bus";
  const handler = () => console.log("handle");
    eventBus.on("test on/off", handler);
 eventBus.once("test once", () => console.log("I only be triggered once!"));
eventBus.emit("test on/off");
eventBus.emit("test once");
eventBus.off("test on/off", handler); // 关闭监听

13 element ui =>element plus
组件增加了(缩写seats):
Skeleton-骨架屏
Empty-空状态
Affix -固钉
TimeSelect 时间选择
Space 间距

14.pinia
状态持久化替代vuex(vue2和vue3都适用)
扁平化管理,不用mutation
参考链接

说明vue2vue3.0vue3.2
数据结构data()setup(){}<script setup />
变量使用data(){return{}setup(){return{…data}}不需要return 和export default{}
顶级 await 的支持要写async要写async不需要写async,直接await
ref、parentthis.$parentchild组件return expose、emitsref、 defineExpose、defineEmits
thisthis.$parentgetCurrentInstance 《h2 ref=“root”>姓名</h2》 const {proxy} = getCurrentInstance() console.log(proxy.$refs.root);ref、 defineExpose、defineEmits
父子组件传值props、emitprops、emitdefineProps、defineEmits
插槽slotslot、attrsuseSlots(在jsx/tsx中更实用)和useAttrs()
vuexslotslot、attrsuseSlots和useAttrs()
watch事件watchwatchwatch、watchEffect
v-memo没有没有有。在v-for中使用v-memo时,确保它们被用在了同一个元素上。v-memo在v-for内部是无效的
component需要注册需要注册不需要注册
vscode插件需要注册veturvolar
第三方插件需要注册需要注册一般在 mounted中初始化(注:1)
thisthisgetCurrentInstance()getCurrentInstance()
beforeRouteEnterbeforeRouteEnter放在setup(){}前面。单独建一个script放beforeRouteEnter
emitthis.$emitsetup(props,context){context.emit(‘fun name’, var)}import defineEmits from 'vue';const emit = defineEmits([“changeMsg”]);emit(“changeMsg”, “is son”);
listenerthis.$listener合并到attrs合并到attrs
useRef和useEffect

在这里插入图片描述

15.增加了很多API
在这里插入图片描述

姓名

import { onMounted, ref, getCurrentInstance } from 'vue' const {proxy} = getCurrentInstance() console.log(proxy.$refs.root);

shallowReactive
shallowRef
watch
watchEffect
getCurrentInstance

isRef: 检查一个值是否为一个 ref 对象
isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理

useStore 、 useRouter 和 useRoute 都是只能在 setup中才能使用
const store = useStore()
const route = useRoute() // vue2 this. r o u t e . n a m e r o u t e . n a m e c o n s t r o u t e r = u s e R o u t e r ( ) / / v u e 2 t h i s . route.name route.name const router = useRouter() //vue2 this. route.nameroute.nameconstrouter=useRouter()//vue2this.router.push(‘/’)
router.push(‘/’)

15.1 withDefaults 包裹defineProps泛类型
withDefaults(
defineProps<{
size?: number;
labels?: string[];
}>(),
{
size: 3,
labels: () => [“default label”],
}
);

15.2 withAsyncContext
const post = await withAsyncContext(
fetch(/api/post/1).then(® => r.json())
);

15.3 teleport
让组件脱离固定的组件位置,可以挂载在逻辑上最优的位置, 其它使用都跟组件一样,只有位置改变
比如遮罩图层,to=“body”

15.4 defineComponent
defineAsyncComponent针对ts语法使用,可以有代码提示。

使用方法一:
import { defineAsyncComponent } from “vue”;
const Child = defineAsyncComponent(() => import(‘./child.vue’))

使用方法二:
defineCustomElement

import { defineCustomElement } from ‘vue’
const MyVueElement = defineCustomElement({
props: {},
emits: {},
template: ...,

// defineCustomElement only: CSS to be injected into shadow root
styles: [/* inlined css */]
customElements.define(‘my-vue-element’, MyVueElement)
document.body.appendChild(
new MyVueElement({
// initial props (optional)
})
)

15.5 defineExpose
子暴露给父,父用ref访问。

15.6 v-memo:

在v-for中使用v-memo时,确保它们被用在了同一个元素上。v-memo在v-for内部是无效的

注1:

<script>
import { onMounted, getCurrentInstance } from 'vue'
export default {
  setup () {
    onMounted(() => {
      const self = getCurrentInstance()
      console.log(self.$moment().format('HH:mm'))
    })
  }
}
</script>

15.6减少了api
为了减少副作用 V3 移除了什么 off on

15.7 mixins->composition
1.溯源查找方便
2.命名空间不会冲突,可以用import{ *** as 别名 }

参考链接:
https://www.yisu.com/zixun/721560.html

16.deep样式穿透写法
vue2 /deep/

vue3 必须有一个根节点

<style lang="less" scoped>
  :deep(.title3){
    background-color:antiquewhite;
  }
</style>
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端段

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值