2024-01-05
【React-Vue】Vue components

原文發表於 Medium。
如同React,Vue.js也可製作重複使用的網頁元件component,在Vue初始專案中的components資料夾就是提供給我們放至網頁子元件的空間。(當然若您很反骨也可以放置在自己喜歡的資料夾內。)
一個Vue檔案的架構基本上是由 script、template、style這三個部分組成,其中的template是最重要的部分,其他兩個部分甚至可以不要,例如Vue團隊就把 Logo的SVG tag直接做成一個component:
//src/components/icons/IconCommunity.vue
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
/>
</svg>
</template>
template之中的資料呈現我們希望的html結構,這邊的使用方式跟React Functional Component就很像了,下面是程式碼寫法的對比:
//App.vue
<script setup>
import HelloWorld from './components/HelloWorld.vue'
import TheWelcome from './components/TheWelcome.vue'
</script>
<template>
<header>
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
<div class="wrapper">
<HelloWorld msg="You did it!" />
</div>
</header>
<main>
<TheWelcome />
</main>
</template>
//App.jsx (相匹配的寫法)
import HelloWorld from './components/HelloWorld.vue'
import TheWelcome from './components/TheWelcome.vue'
export default function App(){
return(
<header>
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
<div class="wrapper">
<HelloWorld msg="You did it!" />
</div>
</header>
<main>
<TheWelcome />
</main>
)
}
所以若要React開發者改寫Vue.js的話,在許多方面可以說是相當輕鬆。
子元件與props
廢話說完,我們來看一下Vue的component元件寫法,首先依照上方程式碼,我們可以找到HelloWorld跟TheWelcome兩個元件。他們的嵌入方式跟React類似,Import之後就可以直接掛在template中。在此處我們看一下HelloWorld的內部長相。
<script setup> defineProps({ msg: { type: String, required: true } }) </script><template>
<div class="greetings">
<h1 class="green">{{ msg }}</h1>
<h3>
You’ve successfully created a project with
<a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>.
</h3>
</div>
</template>
<style scoped>
h1 {
font-weight: 500;
font-size: 2.6rem;
position: relative;
top: -10px;
}
h3 {
font-size: 1.2rem;
}
.greetings h1,
.greetings h3 {
text-align: center;
}
@media (min-width: 1024px) {
.greetings h1,
.greetings h3 {
text-align: left;
}
}
</style>
同樣是一個非常標準的Vue檔,script、template、style三者皆備。但這個元件有個特別之處,就是有資料從上層的父元素傳來:
//父元素的嵌入狀態
<HelloWorld msg="You did it!" />
//利用msg這個attr,把"You did it!"這個值傳入到HelloWorld子元件
傳遞資料的方式跟React差不多,但子元素接收資料的方式則差異較大。在HelloWorld中接收資料的方式是在script區塊使用defineProps方法來取得:
//HelloWorld.js
<script setup>
//defineProps方法不需要import,但須注意script必須有setup這個attr.
defineProps({
msg: {
type: String, //型別
required: true //是否為必須值
}
})
</script>
//HelloWorld.tsx 參考寫法(由於有指定型別,這在普通的React做不到,必須使用TypeScript)
type props = {
msg : string
}
export default function HelloWorld({msg}: props){
//其餘程式碼
}
這個defineProps中需要一個object入參,object中的key值就會是在父元素上的attribute名稱,而每個key的value又是另外一個object(宣告type、是否為必須值)。
子元素透過props接收到的資料透過下面的程式碼呈現在template中:
<template> <div class="greetings"> <h1 class="green">{{ msg }}</h1> //... </div> </template>使用{{ }}雙層的花括號(double curly braces)來表示資料綁定,意思是說雙層花括號中會指向一個值,它可以是變數,也可以是一個運算式(例如 3–1)。這種方式跟React感覺上不太一樣,但其實很像:
//HelloWorld.tsx 參考寫法(由於有指定型別,這在普通的React做不到,必須使用TypeScript)
type props = {
msg : string
}
export default function HelloWorld({msg}: props){
return(
<div class="greetings">
<h1 class="green">{ msg }</h1>
//...
</div>
)
}
當然這個資料綁定的內容不是僅限於props,只要是在同檔案中的script區塊定義的資料都能綁定:
<script setup> const props = defineProps({ msg: { type: String, required: true }, test:{ type: Number } }) const insideTestValue = "inside" </script><template>
<div class="greetings">
<h1 class="green">{{ msg+test }}</h1>
<p>{{test}}</p> //另一個props資料
<p>{{ insideTestValue }}</p> //內部資料"inside"字串
</div>
</template>
因此React開發者在資料綁定上,必須要記住需使用 {{雙層的花括號}} 來實作。相信改個方式之後,仍然是勝任愉快的。
到此為止,都還是在React的舒適圈內,但接下來的幾篇我將會開始介紹Vue的一些特別的Feature,對於React開發者來說,可能就會有點坐不住了。