LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

Vue有20樣寫法,你知道么?

admin
2024年10月18日 20:47 本文熱度 1036

引入

打開 Vue3 的官方文檔,它首先會(huì)告訴你,Vue 的組件可以按兩種不同的風(fēng)格書寫:選項(xiàng)式 API 和組合式 API。文檔為我們提供一系列兩種風(fēng)格的代碼參考,供我們按照偏好進(jìn)行選擇。

實(shí)際上,Vue3 組件可不止兩種寫法,而是多達(dá)十幾種!然而,不管是什么寫法,它們都是基于同一個(gè)底層系統(tǒng)實(shí)現(xiàn)的,概念之間也是彼此相通的,只是使用的接口不同。在實(shí)際開發(fā)中,我們也不會(huì)同時(shí)使用到那么多種寫法,但是這并不意味著我們不需要去了解這些寫法!

如果你仔細(xì)閱讀 Vue3 的文檔,會(huì)發(fā)現(xiàn)一些示例或者 api 看起來模棱兩可,不知道這些 api 到底有什么用,或者閱讀 Vue 的源碼時(shí),總是能發(fā)現(xiàn)一些對(duì)于我們來說意圖不明的邏輯,那么,你可能先要了解一些 Vue 的寫法。先了解一個(gè)東西怎么用,再去分析它是怎么實(shí)現(xiàn)的。

看完本文章,你會(huì)收獲到:

  1. vue 的渲染原理。
  2. 什么是 defineComponent、h、creatVnode。
  3. 渲染函數(shù)和 jsx 的區(qū)別。
  4. 馬上能夠上手 jsx。
  5. 輕松閱讀 vue 文檔的所有示例和 api。
  6. 輕松看懂不同的 vue 組件寫法。
  7. 不管新手老手,都會(huì)對(duì) Vue 有所新的認(rèn)識(shí)。
  8. 等等...

本文章遵從循序漸進(jìn)的寫作順序,從易到難,輕松上手!

setup 語法糖

setup 語法糖應(yīng)該是最常用的寫法了。在 Vue3 中,我們想封裝一個(gè)組件,最習(xí)慣的做法還是新建一個(gè) Vue 文件,并將組件代碼寫在文件中。具體是:頁面結(jié)構(gòu)寫在 template 中,頁面邏輯寫在 script 中,頁面樣式寫在 style 中。

總之,我們將與該組件相關(guān)的代碼都寫在一起、放在一個(gè)文件中單獨(dú)維護(hù),在需要該組件的地方引入使用。

這里我們使用了 setup 語法糖,直接在 script 中書寫我們的 setup 內(nèi)部的邏輯。

<template>
  <div>{{ name }}</div>
</template>

<script setup lang="ts">
import { ref } from "vue";
const name = ref("天氣好");
</script>

<style scoped></style>

在 App. vue 中引入并使用:

// App.vue
<template>
  <User />
</template>

<script setup lang="ts">
import User from "./User.vue";
</script>

<style scoped></style>

注:后續(xù)寫法盡管形式不同,但它們最終的目的都是導(dǎo)出一個(gè)組件,所以對(duì)于組件使用方來說(這里是 App. vue),怎么使用這個(gè)組件的代碼都是不變的,所以將不再重復(fù)此代碼。

Vue2 選項(xiàng)式寫法

Vue2 經(jīng)典寫法

這種寫法也是比較經(jīng)典的。和 setup 語法糖寫法類似。我們需要新建一個(gè) vue 文件來存儲(chǔ)我們的組件代碼,然后在需要使用該組件的地方對(duì)其進(jìn)行引入。區(qū)別在于,我們需要在 script 中導(dǎo)出一個(gè) Vue 實(shí)例。

這里我們導(dǎo)出的其實(shí)是一個(gè)普通對(duì)象,該對(duì)象包含 data、methods 等屬性。這個(gè)對(duì)象的屬性都是可選的,即 option,翻譯回來即“選項(xiàng)”。

<template>
  <div>{{ name }}</div>
</template>

<script lang="ts">
export default {
  data() => {
    return {
      name"天氣好",
    };
  },
};
</script>

<style></style>

defineComponent 輔助函數(shù)

盡管我們?cè)?script 語言塊中導(dǎo)出的默認(rèn)對(duì)象會(huì)被 vue 編譯器當(dāng)成 vue 實(shí)例,但不管怎么看,它依舊只是一個(gè) plain object。在定義組件實(shí)例方面,vue 提供了一個(gè)名為 defineComponent 輔助接口。

<template>
  <div>{{ name }}</div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
  data() => {
    return {
      name"天氣好",
    };
  },
});
</script>

<style></style>

盡管這個(gè)接口也不能改變我們導(dǎo)出的是一個(gè)普通對(duì)象的事實(shí),但是它可以為我們的實(shí)例提供強(qiáng)大的類型推導(dǎo)。我們可以把它看成是一個(gè)返回 vue 實(shí)例的工廠函數(shù),讓我們的代碼看起來更加規(guī)范。

Vue3 選項(xiàng)式寫法

在 Vue3 中,官方引入了新的選項(xiàng) setup,這是 Vue3 選項(xiàng)式寫法和 Vue2 寫法的主要區(qū)別。setup 選項(xiàng)的意義在于它允許我們?cè)谶x項(xiàng)式的寫法中引用和使用組合式的 api,比如 onMounted、ref、reactive 等。但對(duì)于我們來說,它對(duì)于我們有益的地方還是基于它封裝起來的 setup 語法糖用起來很方便。

<template>
  <div>{{ name }}</div>
</template>

<script lang="ts">
export default {
  setup() {
    return {
      name"天氣好",
    };
  },
};
</script>

<style></style>

使用 defineComponent 時(shí),它能夠提示我們 setup 將會(huì)接收到什么參數(shù):

<template>
  <div>{{ name }}</div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
  setup(prop,context) {
    return {
      name"天氣好",
    };
  },
});
</script>

<style></style>

以上寫法我們都是在 template 上書寫我們的頁面結(jié)構(gòu),這也是最常見的幾種寫法,下面我們來介紹幾種了解 vue 底層必不可少的寫法,渲染函數(shù)。

手寫渲染函數(shù)

template 模板語法本質(zhì)上也可以算是一種語法糖。在 vue 編譯器上,template 中的內(nèi)容最終會(huì)被翻譯為渲染函數(shù),掛載到 vue 實(shí)例的 render 屬性上。當(dāng)需要渲染組件時(shí),vue 就執(zhí)行一次 render,得到對(duì)應(yīng)的虛擬節(jié)點(diǎn)樹,最后再轉(zhuǎn)變?yōu)檎鎸?shí) dom。

Vue 允許我們脫離 template,直接自己書寫渲染函數(shù)。位置就在導(dǎo)出實(shí)例的 render 選項(xiàng)上:

<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
  data() => ({ name"天氣好" }),
  render() {
    return this.name;
  },
});
</script>

<style></style>

在 template 中,我們使用類似 html 的模板語法來描述我們的視圖,在 render 函數(shù)中又如何描述呢?vue 提供了兩個(gè) api:createVnode 和 h。二者沒有區(qū)別,h 函數(shù)只是 createVnode 的縮寫。有了 render 函數(shù),我們就不需要寫 template 了。

<script lang="ts">
import { defineComponent, h } from "vue";
export default defineComponent({
  data() => ({ name"天氣好" }),
  render() {
    return h("div"this.name);
  },
});
</script>

<style></style>

在上面的示例中,我們使用 h 函數(shù)生成了一個(gè) vNode,并 return 出去,作為本組件最終在被使用時(shí)渲染出來的效果。

在 template 中我們可以使用 v-if、v-for、slot 等模板語法,在 h 函數(shù)中這些概念也是支持的,只是形式不同,這方面官方文檔有具體的示例。總之,template 模板和 render 選項(xiàng)是可以相互替代的。

setup 返回渲染函數(shù)

setup 返回 render 方法

一般來說,在選項(xiàng)式語法中,setup 方法返回一個(gè)對(duì)象,該對(duì)象暴露給 template,供 template 使用,具體參考第三個(gè)例子(vue3 選項(xiàng)式寫法)。如果我們不使用 template,也就沒有返回對(duì)象的必要了。

在 Vue3 中,還有另外一種不使用 template 的寫法,就是在 setup 方法中返回一個(gè) render 方法。

<script lang="ts">
import { defineComponent, h, ref } from "vue";
export default defineComponent({
  setup() {
    const name = ref("天氣好");
    return () => h("div", name.value);
  },
});
</script>

<style></style>

注意:

  1. 在選項(xiàng)式中使用 setup 之后,一般不應(yīng)該再使用 data、生命周期等在選項(xiàng)式寫法中常用的選項(xiàng),而應(yīng)該把主要邏輯都寫在 setup 中,并適當(dāng)引入組合式的 api。比如,使用 ref,而不是 data 選項(xiàng)。
  2. ref 自動(dòng)解包是 template 特有的功能,h 函數(shù)是沒有這個(gè)功能的。在 h 函數(shù)中引入 ref,記得理所當(dāng)然地帶上 .value。

defineComponent 傳入setup

就注意中的第一點(diǎn),我們可以采用下面這種寫法:直接在 defineComponent 中書寫 setup 函數(shù)(如果再省一點(diǎn)就是 setup 語法糖的寫法了)。

<script lang="ts">
import { defineComponent, h, ref } from "vue";
export default defineComponent(() => {
  const name = ref("天氣好");
  return () => h("div", name.value);
});
</script>

<style></style>

以上就是渲染函數(shù)的寫法,是不是有點(diǎn)感覺了呢,一下子就學(xué)會(huì)了兩個(gè) api!后面會(huì)提到的 Jsx 寫法其實(shí)也應(yīng)該歸為渲染函數(shù)寫法的一種(只要不是 template,而是用 JavaScript 表達(dá)頁面結(jié)構(gòu)的,都是渲染函數(shù)),但是相對(duì)于 h 函數(shù),jsx 并不是純粹的 js,所以我將它們分成了兩類。

Vue & Jsx

在render 中使用 jsx

有了前面兩類寫法介紹的鋪墊,接下來引入 jsx 語法就沒有什么難理解的點(diǎn)了。

jsx 在 vue 文件中是這樣寫的。在 render 渲染函數(shù)返回值處書寫 jsx 替代 h 函數(shù)。書寫純 JavaScript 的 h 函數(shù)描述結(jié)構(gòu)還是比較繁冗的,jsx 就是簡化了的h 函數(shù)寫法。

<script lang="tsx">
import { defineComponent } from "vue";
export default defineComponent({
  data() {
    return { name"天氣好" };
  },
  render() {
    return (
      <>
        <div>{this.name}</div>
      </>

    );
  },
});
</script>

<style></style>

在 setup 中使用jsx

jsx 和 setup 配合食用更加。在選項(xiàng)式風(fēng)格中使用 setup,在 setup 中使用組合式 api,并且返回 jsx 書寫的渲染函數(shù)。

<script lang="tsx">
import { defineComponent, ref } from "vue";
export default defineComponent({
  setup() {
    const name = ref("天氣好");
    return () => <>{name.value}</>;
  },
});
</script>

<style></style>

defineComponent 簡寫

這個(gè)其實(shí)就是前面介紹過的 「defineComponent 傳入 setup」 函數(shù)寫法:這里的區(qū)別只是使用 jsx 替代了 h 函數(shù)。

<script lang="tsx">
import { defineComponent, ref } from "vue";
export default defineComponent(() => {
  const name = ref("天氣好");
  return () => (
    <>
      <div>{name.value}</div>
    </>

  );
});
</script>

<style></style>

自行導(dǎo)出 vNode 對(duì)象

我們也可以自己將 render 函數(shù)執(zhí)行一遍,然后將得到的 jsx Element 導(dǎo)出,和上一個(gè)示例「defineComponent 簡寫」是十分相似。但是這段代碼的缺點(diǎn)非常致命,它不支持接收外部傳遞來的屬性參數(shù)。

<script lang="tsx">
import { ref } from "vue";
export default (() => {
  const name = ref("天氣好");
  return () => (
    <>
      <div>{name.value}</div>
    </>

  );
})();
</script>

<style></style>

不要使用這種寫法。這里會(huì)提到這樣寫,只是因?yàn)楹秃竺娴?strong style="-webkit-tap-highlight-color: transparent;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important">「函數(shù)式組件(其二)」 寫法有關(guān)聯(lián)。本寫法與其它寫法都不同,其它寫法導(dǎo)出的都是 JavaScript 對(duì)象或者 jsx 對(duì)象,而這里我們則是自己執(zhí)行了一遍渲染函數(shù)并得到了虛擬節(jié)點(diǎn),直接將虛擬節(jié)點(diǎn)導(dǎo)出去。既然都已經(jīng)把虛擬節(jié)點(diǎn)創(chuàng)建出來了,那自然無法接收 props。

defineComponent 的第二個(gè)參數(shù)

如果 defineComponent 的第一個(gè)參數(shù)是 setup 函數(shù),那么它的第二個(gè)參數(shù)則可以為組件的定義添加需要的選項(xiàng),但一般除了補(bǔ)充 props 選項(xiàng),不會(huì)再需要其它選項(xiàng)了(組合式 api 和 setup 的入?yún)⒖梢酝耆娲渌x項(xiàng))。

<script lang="tsx">
import { defineComponent } from "vue";
export default defineComponent(
  (props) => {
    return () => (
      <>
        <div>{props.userName}</div>
      </>

    );
  },
  {
    props: { userNameString },
  }
);
</script>

<style></style>

直接在 vue 中使用 jsx

這里 jsx 不再只作為返回值,而是直接被某處使用。它可以是被直接導(dǎo)出,或者用在 template 上。

直接導(dǎo)出 jsx 對(duì)象

直接將 jsx 對(duì)象導(dǎo)出使用。比前面的寫法更簡潔,做法就是把 setup 里面的內(nèi)容提到外面。這里需要注意的是我們導(dǎo)出的是一段直接的 jsx 對(duì)象(jsx Element),而不是渲染函數(shù)。

<script lang="tsx">
import { ref } from "vue";
const name = ref("天氣好");
const User = <>{name.value}</>;
export default User;
</script>

<style scoped></style>

直接用在 template 上

這種寫法可以幫助你在自身的組件內(nèi)復(fù)用一些顆粒度更小的組件,它和 setup 語法糖的寫法非常接近,只是 User 變量可以作為標(biāo)簽直接使用。

<template>
  <User />
</template>

<script setup lang="tsx">
import { ref } from "vue";
const name = ref("天氣好");
const User = <>{name.value}</>;
</script>

<style></style>

函數(shù)式組件(其一)

你還可以將 User 寫成函數(shù)式組件,在本頁面內(nèi)使用。但它不會(huì)將連字符屬性轉(zhuǎn)換為小駝峰寫法。這和「直接用在 template 上」的內(nèi)容都是一樣的,它們都是為了方便在組件本身復(fù)用一些常用的組件。

<template>
  <User :user-name="name" />
</template>

<script setup lang="tsx">
import { ref } from "vue";
const name = ref("天氣好");
const User = (props: { "user-name": string }) => {
  return <>{props["user-name"]}</>;
};
</script>

<style></style>

如果你經(jīng)常使用 tailwind,你可能就會(huì)知道什么情況下會(huì)出現(xiàn)小顆粒度的可復(fù)用標(biāo)簽,比如,一個(gè)加了一大堆類名的 div 標(biāo)簽。

獨(dú)立的 Jsx 文件

以上介紹的所有寫法,都是在 .vue 文件中書寫的,而且也離不開 <script>。接下來的寫法可以讓我們脫離 Vue 的語法塊框架,書寫更像 jsx 的 jsx。

jsx 定義組件

我們需要新建一個(gè) jsx/tsx 文件,然后只要保證導(dǎo)出的仍然是一個(gè)組件就可以了。有了前面的鋪墊,我們不難發(fā)現(xiàn),這不就是去掉 script 標(biāo)簽的選項(xiàng)式寫法嗎?確實(shí)!這是因?yàn)槲夜室庠谇懊姘才帕诉x項(xiàng)式寫法的例子,所以過渡到這里完全沒有壓力!

// User.tsx
import { ref } from 'vue'
export default {
  setup() {
    const name = ref('天氣好')
    return () => <><div>{name.value}</div></>
  }
}

我還是推薦套上 defineComponent:

// User.tsx
import { ref, defineComponent } from 'vue'
export default defineComponent({
  setup() {
    const name = ref('天氣好')
    return () => (<><div>{name.value}</div></>)
  }
});

同樣地,前面對(duì)于 defineComponent 不同方式的使用這里也都可以的。比如導(dǎo)出普通對(duì)象并在 render 或者 setup 中使用 jsx 等等。從 vue 到 jsx,區(qū)別只是省下了 script 語法塊。

vue2 選項(xiàng)式寫法+jsx。

// User.tsx
import { defineComponent } from 'vue'
export default defineComponent({
  data() => ({ name'天氣好' }),
  render() {
    return <><div>{this.name}</div></>
  }
});

導(dǎo)出普通對(duì)象:

// User.tsx
export default {
  data() => ({ name'天氣好' }),
  render() {
    return <><div>{this.name}</div></>
  }
});

函數(shù)式組件(其二)

Vue 中支持的最像函數(shù)式組件的寫法。

// User.tsx
import { ref } from 'vue'

export default function User(props{
  const name = ref('天氣好')
  return <><div>{name.value}</div></>
}

該例和前面的「自行導(dǎo)出 vNode 對(duì)象」非常接近,這也是為什么即使后者存在不能接收參數(shù)的缺陷我也會(huì)提出來,因?yàn)槎叨际鞘褂媒咏瘮?shù)式組件的寫法來描述組件的,但是在 vue 文件中并沒有辦法直接導(dǎo)出這個(gè)函數(shù)組件,而是需要自行執(zhí)行得到vNode。而在 jsx 文件中卻可以將其導(dǎo)出,并且支持接收參數(shù)。

如果你需要為其定義 props,也不需要使用 「defineComponent 的第二個(gè)參數(shù)」為你提供什么 props 選項(xiàng),而是直接在函數(shù)式組件的 props 、emits 屬性上掛載對(duì)應(yīng)的配置。

import { ref } from 'vue'

User.props = {
  userNameString
}

function User(props{
  // const name = ref('天氣好')
  return <><div>{props.userName}</div></>
}

export default User;

相信習(xí)慣了 React 的 fc 的小伙伴,看到這里一定感覺倍感親切。然而 Vue 的 Jsx 終究只是 Vue 的 Jsx,它并沒有像 React 一樣存在那么多強(qiáng)大的 Hooks 和內(nèi)置組件,而是僅僅只是 h 函數(shù)的便捷寫法。在語法上也和 React Jsx 存在諸多區(qū)別。和 React Jsx 相比,Vue Jsx 其實(shí)和自家的 template 更接近。不過 Vue Jsx 寫法的靈活性還是要比 template 模板高,但官方更推薦使用 template。template 更容易上手且提供了更好的性能優(yōu)化,除非你想完完全全掌控組件的每一個(gè)細(xì)節(jié),才需要jsx。

小結(jié)

盡管本文提到了很多種寫法,但大多數(shù)寫法在大多數(shù)時(shí)候都是不會(huì)派上用場的,也應(yīng)該不被派上用場。之所以列舉那么多寫法,主要的目的還是為了循序漸進(jìn)引入 jsx 文件寫法和函數(shù)式組件寫法。

可以看出,Vue 的寫法本質(zhì)上是選項(xiàng)式的。Vue3 在 Vue2 的基礎(chǔ)上引入了 setup 選項(xiàng)和 setup 語法糖,結(jié)合組合式 api 后,開發(fā)者可以將組件的大部分邏輯都維護(hù)在 setup 中,而不是 vue2 中割裂了邏輯的 data+created+methods 選項(xiàng)。

在此基礎(chǔ)上,setup 語法糖支持自動(dòng)導(dǎo)出組件功能,為我們?nèi)粘i_發(fā)帶來了很大的便利。

但是除了使用 template 來表達(dá)我們的結(jié)構(gòu),我們也可以自己使用 render 選項(xiàng)并借助 h 函數(shù)或者 jsx 的力量來手寫渲染函數(shù)。這些都是在 vue 文件中完成的。

既然都不需要 template 了,那么 vue 文件里就只剩下一個(gè) script 了(我們先忽略 style)。在 jsx 文件中,就允許我們直接書寫導(dǎo)出對(duì)象(仍是選項(xiàng)式的寫法),忽略script。

最后是 Vue 的 jsx 文件獨(dú)有的特性。它允許我們導(dǎo)出一個(gè)函數(shù)作為組件,我們稱之為函數(shù)式組件(fc,function component),這是 vue 文件和以前所有寫法所不具備的,外形與 React 相近。

總的來說就一句話,「Vue 本身仍然是選項(xiàng)式的,但是它現(xiàn)在還額外支持了在 jsx 文件中書寫 fc?!?/strong>

個(gè)人看法

使用哪一種寫法,主要看個(gè)人偏好。每種寫法在特定場景下都有它的好處和壞處。選擇哪一種并不重要。但是我還是提幾點(diǎn)個(gè)人建議:

  1. 優(yōu)先選擇 setup 語法糖。
  2. 使用選項(xiàng)式時(shí),推薦套上 defineComponent。
  3. 當(dāng)需要使用 jsx 時(shí),推薦在 vue 文件中使用選項(xiàng)式 setup+返回 jsx 渲染函數(shù)的寫法。

為什么不推薦函數(shù)式組件的寫法,因?yàn)樗枰獙懺?jsx 文件里。如果你只是想通過 jsx 為你的組件增強(qiáng)某些功能,直接改造 vue 文件更加方便,并且不需要修改你引入文件的后綴(.vue -> .jsx/.tsx)。最重要的是,如果真的想寫函數(shù)式組件,為何不試試 React?

當(dāng)然以上只是我個(gè)人的小小看法。如果覺得有用,不妨動(dòng)動(dòng)小手點(diǎn)贊和收藏吧!

看到這里,如果你也想試試在 Vue 中寫 jsx,不妨看看這篇文章,分享了怎么在 Vue 項(xiàng)目中配置 jsx 環(huán)境,充分發(fā)揮 jsx 的優(yōu)勢!

傳送門:【Vue3】對(duì)el-form進(jìn)行二次封裝后,我的開發(fā)效率提升了3倍 - 掘金

參考

渲染函數(shù) & JSX | Vue.js


該文章在 2024/10/19 12:27:24 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲(chǔ)管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

黄频国产免费高清视频,久久不卡精品中文字幕一区,激情五月天AV电影在线观看,欧美国产韩国日本一区二区
日韩成视频在线精品 | 亚洲中文字幕久久久一区 | 在线se国产精品 | 亚洲无中文字幕 | 在线精品视频一区二区三区四区 | 亚洲三级在线观看 |