首頁  >  文章  >  web前端  >  聊聊Vue2開發者如何快速上手Vue3

聊聊Vue2開發者如何快速上手Vue3

青灯夜游
青灯夜游轉載
2022-07-26 19:57:092732瀏覽

如何快速上手Vue3?以下這篇文章給大家比較一下Vue2和Vue3,並介紹一下Vue2開發者如何快速上手Vue3,希望對大家有幫助!

聊聊Vue2開發者如何快速上手Vue3

筆者之前是Vue2 React開發者,因專案需要直接上手Vue3,所以快速學習一下,中間會對比一些和React相關的差異。閱讀前提:已經上手了Vue2的開發,本文主要聊的問題:

  • Vue3的全新特性

  • Vue2和Vue3的一些差異

  • Vue2開發者如何快速上手Vue3

  • Vue3和React的簡單比對

  • 使用Vue3編寫元件庫

(學習影片分享:vue影片教學

Vue2 vs Vue3


1、簡單說

  • Vue2只支援單節點,Vue3 template支援多節點,類似react fragments
  • 變化基本上都在script中(Option api -> Composition api)不會再看滿螢幕的this了! ! !
  • style支援v-bind
  • Proxy取代defineProperty
    • defineProperty無法實作對陣列物件的深層監聽,Proxy是瀏覽器最新api,功能更加強大。
    • 不再支援IE,Vue2想享受Vue3帶來的部分更新,可考慮升級Vue2.7版本
  • TypeScript的支援
    • Vue2採用的是Facebook的Flow,無法完美支援TypeScript(所以專案初期技術選型很重要)
    • Vue3 TypeScript完全重寫,提供和React一樣的TS支援
  • 全新生態
    • 基本上還是vue週邊伴隨Vue3升級那一套,但是狀態管理推薦,由原來的Vuex變為Pina
    • 全新的vite支持,包括vitest等,官方提供週邊工具更多了
  • 其它優化
    • 效能更好,體積更小就不用說了
    • 事件監聽快取 ,類似@click綁定的函數,無需多次創建,放在了cacheHandler緩存中
    • #SSR:Vue 3.0 會將靜態標籤直接轉化為文本,相比React 先將JSX 轉換成虛擬DOM,再將虛擬DOM 轉換為HTML,這一點Vue3的速度要快很多
    • Use Hooks 放棄過去的mixins,使用Hooks解決過去mixins的一些缺點

2、原始碼

#了解的不多,後續再補充

diff演算法的最佳化

  • 不再和vue2一樣,完全比較兩棵虛擬DOM樹,Vue3採用動靜結合的方法,最佳化diff效能
  • 透過編譯階段對靜態模板進行分析,編譯產生Block tree。更新效能由 模版整體大小相關 =》與動態內容的數量相關,這是一個非常大的效能突破。將程式碼提升到渲染函數之外,這可以避免在每次渲染時重新建立這些對象,從而大大提高記憶體使用率並減少垃圾回收的頻率。

原始碼管理

  • vue2 poly-repo
    • vue2.x的原始碼託管在src目錄中,然後依據功能拆分出了complier(模板編譯的相關代碼),core(與平台無關的通用運行時代碼),platforms(平台專有代碼),server(服務端渲染的相關代碼)、sfc (.vue 單一檔案解析相關程式碼)、shared(共用工具程式碼) 等目錄
  • #vue3 mono-repo
    • package可以獨立於vue.js去使用,這樣例如使用者想要使用vue3.0的響應式,可以單獨依賴reactive,而不必依賴整個vue.js,減少引用包的體積,而vue2.x卻做不到這一點。
  • 原始碼結構比較

聊聊Vue2開發者如何快速上手Vue3

#全新的API


#什麼是組合式API? - Vue官方

  • 解決了過去組件過長時,optionsApi帶來的難以維護的問題
  • 邏輯可以整塊復用
  • 所有API都是import引入的,對Tree - shaking很友好,沒用到功能,打包的時候會被清理掉,減少包的大小

#1、setup

  • 新的 setup  選項在元件被建立之前執行,一旦 props 被解析完成,它就會被當作組合式API 的入口。
  • 可以當做Vue2的beforeCreate和create生命週期用
  • 可直接寫await語法
  • #SFC單一檔案元件中直接使用&lt ;script lang="ts" setup>即可,或者也可以結合export default使用
<script>
const result = await Http.get(&#39;/getUserInfo&#39;)
</script>
// or 
export default {
  setup(props, context) {
    // Attribute (非响应式对象,等同于 $attrs)
    console.log(context.attrs)
    // 插槽 (非响应式对象,等同于 $slots)
    console.log(context.slots)
    // 触发事件 (方法,等同于 $emit)
    console.log(context.emit)
    // 暴露公共 property (函数)
    console.log(context.expose)
  }
}

#2、ref

  • #ref 用來建立
  • 基礎型別
  • 的響應式資料template中預設呼叫value顯示數據,script需要使用
  • .value
  • 呼叫跟react ref差不多,react是.current取得值,vue3是.value。
Ref的本質是透過Reactive創建的,Ref(10)=>Reactive({value:10})

有一定的心智負擔,尤大也明確說了不會支援script中直接存取。究其原因,還是基礎型別無法攔截它的變化,當然也有大哥提出用new String('foo')類似的語法來包裝基礎型別。個人感覺直接拿已支援的reactive來搞也不錯
  • 相關api
  • #Ref
  • ts定義 import { type Ref } from 'vue';
  • isRef#  判斷是否為ref物件。一般是ref,toRef,toRefs創建的變數
  • toRefs

reactive物件解構為單一響應式物件

##shallowRef
    建立一個追蹤自身 .value 變化的ref,但不會使其值也變成響應式的,簡單理解為創建一個和ref相同結構的非響應式變數
  • triggerRef
  • 強制更新頁面DOM。即使建立的ref沒有變,想更新dom可以用
  • customRef
  • 提供類似computed的get和set,可自訂ref行為

3、reactive

reactive 用來建立聊聊Vue2開發者如何快速上手Vue3引用型別

的響應式資料#######reactive的本質是將每一層的資料都解析成###proxy物件#########reactive 的響應式預設都是###遞迴的###,改變某一層的值都會遞歸的呼叫一遍,重新渲染dom。 #########直接解構###,響應性會遺失,需要用###toRefs###包。引用類型直接改變引用位址也會導致響應式遺失#############相關api################readonly### 將reactive的值更改為唯讀#########shallowReactive###  只能回應淺層的資料如果是深層的資料只會改變值不會改變檢視######
import { reactive, toRefs } from 'vue'

const book = reactive({
  author: 'Vue Team',
  year: '2020',
  title: 'Vue 3 Guide',
  description: 'You are reading this book right now ;)',
  price: 'free'
})

let { author, title } = toRefs(book)

title.value = 'Vue 3 Detailed Guide' // 我们需要使用 .value 作为标题,现在是 ref
console.log(book.title) // 'Vue 3 Detailed Guide'
####### 4.生命週期#########區別不大,把setup當created用,其它就當改了個名###
<script>
import { onMounted } from &#39;vue&#39;;

const getUserInfo = () => {
  console.log(&#39;获取用户信息&#39;);
};
onMounted(getUserInfo);
</script>
#########

5、watch & watchEffect

watch

  • 功能和vue2一致
  • watch(监听参数,变化回调,配置参数)
  • 注意监听对象的单个属性:watch(() => articleInfo.author, (newVal) => {}),第一个参数为箭头函数返回要监听的目标属性
import { ref, reactive, watch } from 'vue'

const counter1 = ref(0)
const counter2 = ref(0)
// 监听多个
watch([counter1, counter2], (newValue, oldValue) => {
  console.log('The new counter1 value is: ' + counter1.value)
  console.log('The new counter2 value is: ' + counter2.value)
})

const obj = reactive({
  name: 'JJ',
  age: 18
})
// 深度监听对象
watch(obj, (newValue, oldValue) => {
  console.log('The new obj value is: ' + obj.value)
}, {
   deep: true,
   immediate: true
})
// watch监听单个属性
watch(() => obj.name, (newValue, oldValue) => {
  console.log('The new obj value is: ' + obj.value)
}, {
   deep: true,
   immediate: true
})

watchEffect

  • 类似React useEffect,但是不需要写依赖项,只要我们回调中引用了 响应式的属性
  • 和watch的区别:
    • 同一个功能的两种不同形态,底层的实现是一样的
    • watch 可以获取到新值与旧值(更新前的值),而 watchEffect 是拿不到的。
    • watch - 显式指定依赖源,watchEffect - 自动收集依赖源
    • watchEffect 在组件初始化的时候就会执行一次用以收集依赖,watch指定了依赖,所以不需要。
    • 可以理解为watchEffect 就是配置了{ immediate: true } 的watch
  • 使用场景:antfu小哥:推荐在大部分时候用 watch 显式的指定依赖以避免不必要的重复触发,也避免在后续代码修改或重构时不小心引入新的依赖。watchEffect 适用于一些逻辑相对简单,依赖源和逻辑强相关的场景(或者懒惰的场景 )。
const stopWatch = watchEffect(
  (oninvalidate): void => {
    oninvalidate(() => {
      console.log("前置校验函数");
    });
    // 引用了响应式的属性 count
    console.log("watchEffect count变化", count.value);
  },
  {
    // 副作用刷新时机 flush 一般使用post
    // 可选:pre(组件更新前执行)/sync(强制效果始终同步触发)/post(组件更新后执行)
    flush: "post",
    // 开发调试
    onTrigger() {
      console.log("开发调试");
    },
  }
);

6、computed

  • 更加灵活,可以在定义响应式变量时声明
  • 作用和vue2无差异
import { ref, computed } from 'vue'

const counter = ref(0)
const twiceTheCounter = computed(() => counter.value * 2)
// get set写法
const plusOne = computed({
  get: () => counter.value + 1,
  set: (val) => {
    counter.value = val - 1
  },
})

plusOne.value = 1
console.log(counter.value) // 0

counter.value++
console.log(counter.value) // 1
console.log(twiceTheCounter.value) // 2

组件


1、异步组件

  • 通过进行引入defineAsyncComponent
  • 可配合Suspense 进行更多操作,可用于loading和骨架屏相关,和react Suspense基本一致。不过react Suspense基本一致这个属性都不太好用,vue的不清楚实际场景咋样
// template
<suspense>
  <template>
    <asynccomponent></asynccomponent>
  </template>

  <template>
    <div>loading...</div>
  </template>
</suspense>

// script
const AsyncComponent = defineAsyncComponent(() => import('./asyncComponent.vue'))

2、Teleport传送组件

Teleport 是一种能够将我们的模板渲染至指定DOM节点,不受父级style、v-show等属性影响,但data、prop数据依旧能够共用的技术;类似于 React 的 Portal。之前写react是不怎么用这个属性,vue3这个估计也没多大用。

主要解决的问题 因为Teleport节点挂载在其他指定的DOM节点下,完全不受父级style样式影响

to 属性 插入指定元素位置,body,html,自定义className等等

<teleport>
    <loading></loading>
</teleport>

3、keep-alive缓存组件

  • 作用和vue2还是一样的,生命周期名称变了
  • 初次进入时:onMounted> onActivated
  • 退出后触发 deactivated
  • 再次进入:只会触发 onActivated

4、组件通信

defineXxxx

defineXxxx 无需import即可直接使用

  • defineProps 代替过去的props
  • defineEmits 代替过去的$emit
  • defineOptions 自定义一些组件属性,比如组件名称(需要插件支持)
  • defineComponent 用于render函数、TSX、IDE提醒等
  • defineExpose 子组件声明的数据,暴露给父组件直接用

provide/inject

和vue2一致

vuex & pina

两者用法,除了pina没有Mutations,差别不大。但是官方推荐的东西,自然有它的各种优点

  • Vuex: State、Gettes、Mutations(同步)、Actions(异步)
  • Pinia: State、Gettes、Actions(同步异步都支持)
  • Vuex4 用于 Vue3 ,Vuex3 用于 Vue2
  • Pinia2.x 即支持 Vue2 也支持 Vue3

TS支持


  • 可以让写react的兄弟,快速上手写vue3
  • react中 {{}} => {}

  • 兼容的指令:v-model,v-if,v-show
import { ref } from 'vue'
let v = ref<string>('')
const renderDom = () => {
    return (
        
           <input>
           <div>
               {v.value}
           </div>
        >
    )
}
export default renderDom</string>

插件


1、开源插件

unplugin-auto-import/vite

无需导入xxx,import { reactive,ref } from "vue";,只需要用即可

unplugin-vue-define-options

自定义组件名称,需要引入插件unplugin-vue-define-options,并在vite中配置

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import DefineOptions from 'unplugin-vue-define-options/vite';

export default defineConfig({
  plugins: [vue(), DefineOptions()],
});

不使用插件,也可以通过多写一个script标签来单独写options

<script>
    export default {
        name: "TButton",
    };
</script>
<script>
  defineOptions({
    name: &#39;TButton&#39;,
  });
</script>

2、vscode插件

volar vscode

  • vetur只支持vue2,volar只支持vue3,两者冲突。
  • 建议禁用vetur,格式化代码使用prettier,本地使用volar做代码高亮。
  • 或者通过项目配置,指定相关插件配置

聊聊Vue2開發者如何快速上手Vue3

指令


1、v-model

  • 底层语法糖时间改变,之前vue2是update:input,vue3 是update:modelValue
  • 支持多个v-model
  • 支持自定义修饰符
  • 弃用.sync等

2、自定义指令

生命周期(和vue3一致)

  • created 元素初始化的时候
  • beforeMount 指令绑定到元素后调用 只调用一次
  • mounted 元素插入父级dom调用
  • beforeUpdate 元素被更新之前调用
  • update 这个周期方法被移除 改用updated
  • beforeUnmount 在元素被移除前调用
  • unmounted 指令被移除后调用 只调用一次

自定义拖拽指令v-move

  • 比如这个v-move 封装自定义拖拽指令
import { Directive } from "vue";
const vMove: Directive = {
  mounted(el: HTMLElement) {
    let moveEl = el.firstElementChild as HTMLElement;
    const mouseDown = (e: MouseEvent) => {
      //鼠标点击物体那一刻相对于物体左侧边框的距离=点击时的位置相对于浏览器最左边的距离-物体左边框相对于浏览器最左边的距离
      console.log(e.clientX, e.clientY, "-----起始", el.offsetLeft);
      let X = e.clientX - el.offsetLeft;
      let Y = e.clientY - el.offsetTop;
      const move = (e: MouseEvent) => {
        el.style.left = e.clientX - X + "px";
        el.style.top = e.clientY - Y + "px";
        console.log(e.clientX, e.clientY, "---改变");
      };
      document.addEventListener("mousemove", move);
      document.addEventListener("mouseup", () => {
        document.removeEventListener("mousemove", move);
      });
    };
    moveEl.addEventListener("mousedown", mouseDown);
  },
};

Hook


用了react hook的人都知道很香,vue3支持这个相当不错,能解决很多业务场景的封装

1、自定义Hook

可以当做mixins写

// useWindowResize
import { onMounted, onUnmounted, ref } from "vue";

function useWindowResize() {
  const width = ref(0);
  const height = ref(0);
  function onResize() {
    width.value = window.innerWidth;
    height.value = window.innerHeight;
  }
  onMounted(() => {
    window.addEventListener("resize", onResize);
    onResize();
  });
  onUnmounted(() => {
    window.removeEventListener("resize", onResize);
  });
  
  return {
    width,
    height
  };
}

export default useWindowResize;

2、hook库

3、react vs vue3

聊聊Vue2開發者如何快速上手Vue3

结语


  • Vue3 的依赖追踪是全自动的,不需要担心传了错误的依赖数组给 useEffect/useMemo/useCallback 从而导致回调中- 使用了过期的值

  • Vue3 Hook也没React Hook那么多限制,后续用用看怎么样

  • 个人比较喜欢SFC语法,html、js、css分离开

笔者vue3也刚用不久,如有错误,还请兄弟们指出

本文所有demo都在该仓库中JJ-UI 一款Vue3组件库,参考大佬文章刚刚搭建好,后续会基于这个架子开发自己的vue3组件库

聊聊Vue2開發者如何快速上手Vue3

【相关视频教程推荐:vuejs入门教程web前端入门

以上是聊聊Vue2開發者如何快速上手Vue3的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除