關於Vue和React的一些對比及個人思考(中)


關於Vue和React的一些對比及個人思考(中)


vue和React都是目前最流行、生態最好的前端框架之一。框架本身沒有優劣之分,只有適用之別,選擇符合自身業務場景、團隊基礎的技術才是我們最主要的目的。

博主1年前用的是Vue框架,近半年轉技術棧到React框架,對於Vue和React都有一些基本的瞭解。接下來博主將與大家通過上、中、下三部一起走近Vue和React,共同探討它們的差異。(比如你正在用vue,對react感興趣也可以看下,反之亦然)

整體內容概覽:


關於Vue和React的一些對比及個人思考(中)


中部將主要從條件渲染是否顯示列表渲染計算屬性偵聽器ref表單插槽八個方面對比vue和react,歡迎多多交流,共同探討,感謝支持。

上部鏈接:關於Vue和React的一些對比及個人思考(上)

9.條件渲染(v-if vs &&)

條件渲染用於根據條件判斷是否渲染一塊內容。

vue

vue中用v-if指令條件性地渲染一塊內容。只有當表達式返回真值時才被渲染,v-if還可以和v-else-if、v-else配合使用,用於不同條件下的渲染,類似js裡的if else語法。

(1)基本用法

<code> 
This is content.

複製代碼/<code>

data

<code>  data() {
return {
showContent: false
}
}
複製代碼/<code>

當showContent為false時,不會渲染DOM節點,會留下一個註釋標誌。


關於Vue和React的一些對比及個人思考(中)


showContent為true時,才會渲染DOM節點。


關於Vue和React的一些對比及個人思考(中)


(2)v-else 二重判斷

v-if和v-else配合使用時,v-else必須要和v-if相鄰,否則會報錯。

<code>  

This is content.

Hide content.


複製代碼/<code>

(3)v-else-if 多重判斷

當有多重判斷條件時,可以使用v-else-if,類似v-if的else-if塊,v-else 元素必須緊跟在帶v-if或者v-else-if的元素的後面,否則它將不會被識別。

<code>

A


B


C


Not A/B/C

複製代碼/<code>

(4)template 使用 v-if

另外,當想切換多個元素時,在<template>上使用v-if可以針對元素進行分組。/<template>

<code><template>

Title


Paragraph 1


Paragraph 2


/<template>
複製代碼/<code>

react

react使用與運算符&&、三目運算符(?:)、if else來實現條件渲染的效果。

(1)與運算符

與運算符&&,實現效果類似v-if,左邊變量為真值時,渲染右邊的元素。

<code> return (

{showItem &&
This is content.
}

);
複製代碼/<code>

(2)三目運算符(?:)

使用三目運算符(?:),實現類似v-if v-else效果,showItem變量為true時顯示第一個元素,變量為false時顯示第二個元素。

<code> return (

{
showItem ?
(
This is true content.
) : (
This is false content.
)
}

);
複製代碼/<code>

(3)多重判斷

當處理多重判斷時,可以使用函數加if else多重判斷或者switch case的形式來實現,實現類似v-if v-else-if v-else的效果。

Ⅰ.if-else多重判斷

<code>render() {
const { type } = this.state;
const toggeleShow = (type) => {
if (type === 'A') {
return
A
;
} else if (type === 'B') {
return
B
;
} else if (type === 'C') {
return
C
;
} else {
return null;
}
};

return (

{toggeleShow(type)}

);
}
複製代碼/<code>

Ⅱ.switch case多重判斷

<code>render () {
const { type } = this.state;
const toggeleShow = (type) => {
switch (type) {
case 'A':
return
A
;
case 'B':
return
B
;
case 'C':
return
C
;
default:
return null;
}
};

return (

{toggeleShow(type)}

);
}
複製代碼/<code>

10.是否顯示(v-show vs style+class)

另一個用於展示條件的元素的選項是v-show,react中可以通過style或者切換class的形式實現是否顯示。

vue

v-show渲染的元素會被渲染並保留在DOM中。v-show只是簡單地切換元素的css屬性display。

<code> 
This is content.

複製代碼/<code>

showContent為false時,style的display屬性值為none。


關於Vue和React的一些對比及個人思考(中)


showContent為true時,style的display屬性值為block(元素默認display屬性值)。


關於Vue和React的一些對比及個人思考(中)


注意,v-show 不支持 <template> 元素,也不支持 v-else。/<template>

v-if與v-show對比總結:

  • 1)v-if是“真正”的條件渲染,因為它會確保在切換過程中條件塊內的事件監聽器和子組件適當地被銷燬和重建。
  • 2)v-if也是惰性的:如果在初始渲染時條件為假,則什麼也不做——直到條件第一次變為真時,才會開始渲染條件塊。
  • 3)相比之下,v-show就簡單得多——不管初始條件是什麼,元素總是會被渲染,並且只是簡單地基於 CSS 進行切換。
  • 4)一般來說,v-if有更高的切換開銷,而v-show有更高的初始渲染開銷。因此,如果需要非常頻繁地切換,則使用v-show較好;如果在運行時條件很少改變,則使用v-if較好。

react

react中通過修改style或者class來實現v-show類似效果。

通過修改style屬性的display屬性來實現切換是否顯示。

<code>

This is content.

複製代碼/<code>

通過變量判斷修改class來實現切換效果,本質上也是切換元素的display屬性來實現切換效果。

在react中動態修改元素樣式時(比如切換tab、按鈕選中狀態),適用於使用class來實現。

<code> const itemClass = showItem ? 'show-item-class' : 'hide-item-class';
return (

This is content.

);
複製代碼/<code>

class樣式:

<code>.show-item-class {
display: block;
}
.hide-item-class {
display: none;
}
複製代碼/<code>

11.列表渲染(v-for vs map)

vue中使用v-for來渲染列表,react中使用map來渲染列表。不管是v-for還是map來渲染列表都需要添加key值(key在兄弟節點之間必須唯一),方便快速比較出新舊虛擬DOM樹間的差異。

vue

vue中可以使用v-for來渲染數組、對象、<template>、組件。/<template>

(1)渲染數組

渲染數組時,使用(item, index) in items形式的特殊語法,其中items是源數據數組,item則是被迭代的數組元素的別名,index表示當前元素的索引。

<code>  


{{item.message}}


複製代碼/<code>

data

<code> data() {
return {
items: [
{
message: 'Hello'
},
{
message: 'Welcome'
}
]
}
}
複製代碼/<code>

(2)渲染對象

v-for也可以用來遍歷一個對象的屬性,使用(value, key, index) in obj的形式,其中key表示對象的key值,value表示對象的value值,index表示當前索引。

在遍歷對象時,採用Object.keys()的結果遍歷,但是不能保證它的結果在不同的 JavaScript 引擎下都一致。

<code>

{{index}}.{{key}}: {{value}}

複製代碼/<code>

data

<code>  data() {
return {
obj: {
name: 'xiaoming',
age: 18,
sex: 'male',
height: 175
}

}
}
複製代碼/<code>

(3)渲染多個元素

在<template>上使用v-for來渲染一段包含多個元素的內容。/<template>

在<template>上使用v-for來渲染元素段時,不允許綁定key值。因為template上並不會生成實際Dom節點。可以給底下的子元素綁定key值。/<template>

<code>

<template>
{{ item.message }}


/<template>

複製代碼/<code>

data

<code> data() {
return {
items: [
{
message: 'hello'
},
{
message: 'world'
},
{
message: 'welcome'
}
]
}
},
複製代碼/<code>

生成DOM時,並不會生成實際DOM節點。


關於Vue和React的一些對比及個人思考(中)


(4)渲染自定義組件列表

在自定義組件上,可以使用v-for渲染自定義組件列表,通過props將數據傳遞給組件。

在組件上使用v-for時,key是必須的。

v-for渲染自定義組件列表,將item通過props傳遞給組件。

<code> <my-component>    v-for="(item, index) in items" 
:key="item.message + index"
:item="item">
/<my-component>
複製代碼/<code>

my-component組件使用props接收父組件傳來的數據。

<code><template>
{{item.message}}

/<template>


複製代碼/<code>

react

react中使用map()方法來實現列表渲染。

(1)渲染數組

遍歷數組中的每個元素,得到一組jsx元素列表。數組中的每一個元素需要添加唯一的key值。

<code>  render() {
const items = [
{
message: 'hello'
},
{
message: 'world'
},
{
message: 'welcome'
}
];
const listItems = items.map((item, index) =>
{item.message}
);
return (

{listItems}

);
}
複製代碼/<code>

(2)渲染對象

對於對象,可以採用方法通過Object.keys()或者Object.entries()來遍歷對象。

<code>  render() {
const obj = {
name: 'xiaoming',
age: 18,
sex: 'male',
height: 175
};
const renderObj = (obj) => {
const keys = Object.keys(obj);
return keys.map((item, index) =>
{obj[item]}
);
};
return (

{renderObj(obj)}

);
}
複製代碼/<code>

(3)渲染自定義組件列表

渲染自定義組件列表與vue中類似,需要給組件添加key值標識。

<code>  render() {
const items = [
{
message: 'hello'
},
{
message: 'world'
},
{
message: 'welcome'
}
];
const listItems = items.map((item, index) =>
<listitem>);
return (

{listItems}

);
}
複製代碼/<code>

12.計算屬性(computed vs useMemo+useCallback)

計算屬性表示根據組件的數據(包含組件自身的數據和接收父組件的props)需要二次計算並“保存”的數據,使用計算屬性的好處是避免每次重複計算的開銷(比如遍歷一個巨大的數組並做大量的計算)。

vue

vue中用computed來表示計算屬性,可以定義多個計算屬性,計算屬性可以互相調用。計算屬性是基於它們的響應式依賴進行緩存的。只在相關響應式依賴發生改變時它們才會重新求值。vue中可以直接使用this.xxx直接獲取到計算屬性。

(1)基本用法

下面聲明計算屬性reversedMessage依賴於message,這就意味著只要 message還沒有發生改變,多次訪問reversedMessage計算屬性會立即返回之前的計算結果。

<code>

message:
{{reversedMessage}}


複製代碼/<code>

script

<code>  data() {
return {
message:''
}
},
computed: {
reversedMessage() {
return this.message.split('').reverse().join('')
}
}
複製代碼/<code>

(2)計算屬性的setter

技術屬性默認只有getter,也可以使用setter,當修改計算屬性的時候,會觸發setter回調。

script

<code>data() {
return {
message:'',
info: ''
}
},

computed: {
reversedMessage: {
get() { // get回調
return this.message.split('').reverse().join('')
},
set(newValue) { // set回調
this.info = newValue
}
}
},
methods: {
changeMessage(event) {
// 修改reversedMessage計算屬性
this.reversedMessage = event.target.value;
}
}
複製代碼/<code>

react

react hooks使用useMemo表示memoized的值,使用useCallback表示memoized的回調函數,實現與vue中computed類似的功能。

適用場景:子組件使用了PureComponent或者React.memo,那麼你可以考慮使用useMemo和useCallback封裝提供給他們的props,這樣就能夠充分利用這些組件的淺比較能力。

(1)useMemo

useMemo返回一個memoized的值。useMemo會依賴某些依賴值,只有在某個依賴項改變時才會重新計算memoized值。如果沒有提供依賴項數組,useMemo 在每次渲染時都會計算新的值。useMemo可以作為性能優化的手段。

傳入useMemo的函數會在渲染期間執行。請不要在這個函數內部執行與渲染無關的操作,諸如副作用這類的操作屬於useEffect的適用範疇,而不是useMemo。

<code>function NewComponent(props) {
const { num } = props;
const [size, setSize] = useState(0);
// max是useMemo返回的一個memoized的值
const max = useMemo(() => Math.max(num, size), [num, size]);
return (

type="number"
value={size}
onChange={(e) => setSize(e.target.value)} />
Max {max}

);
}
複製代碼/<code>

(2)useCallback

useCallback把內聯回調函數及依賴項數組作為參數傳入useCallback,它將返回該回調函數的memoized版本,該回調函數僅在某個依賴項改變時才會更新。當你把回調函數傳遞給經過優化的並使用引用相等性去避免非必要渲染(例如shouldComponentUpdate的子組件時,它將非常有用。

<code>function NewComponent(props) {
const [message, setMessage] = useState('hello world.');
const handleChange = useCallback((value) => {
setMessage(value);
}, []);
return (

type="number"
value={message}
onChange={(e) => handleChange(e.target.value)} />
{message}

);
}

複製代碼/<code>

13.偵聽器(watch vs getDerivedStateFromProps + componentDidUpdate)

偵聽器是指通過監聽props或者組件數據(data或state)的變化來執行一些異步或者數據操作。

vue

vue中主要通過watch監聽props、data、computed(計算屬性)的變化,執行異步或開銷較大的操作。

下面ProjectManage組件通過watch監聽projectId prop的變化獲取對應的項目信息。

<code>export default {
name: "ProjectManage",
props: ["projectId"],
data() {
return {
projectInfo: null
};
},
watch: {
projectId(newVaue, oldValue) {
if (newVaue !== oldValue) {
this.getProject(newValue);
}
}
},
methods: {
getProject(projectId) {
projectApi
.getProject(projectId)
.then(res => {
this.projectInfo = res.data;
})
.catch(err => {
this.$message({
type: "error",
message: err.message
});
});
}

}
};
複製代碼/<code>

react

react中通過static getDerivedStateFromProps()和componentDidUpdate()實現監聽器的功能。

(1)static getDerivedStateFromProps()

getDerivedStateFromProps會在調用render方法之前調用,並且在初始掛載及後續更新時都會被調用。它應返回一個對象來更新state,如果返回null則不更新任何內容。

關於getDerivedStateFromProps有2點說明:

  • 1)不管是props變化、執行setState或者forceUpdate操作都會在每次渲染前觸發此方法。
  • 2)當state的值在任何時候都取決於props的時候適用該方法。
<code>class NewComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
info: ''
}
}
static getDerivedStateFromProps(nextProps, prevState) {
// state中的info根據props中的info保持同步
if (nextProps.info !== prevState.info) {
return {
info: nextProps.info
}
}
return null;
}

render() {
const { info } = this.state;
return
{info}

}
}
複製代碼/<code>

(2)componentDidUpdate()

componentDidUpdate()方法在組件更新後被調用。首次渲染不會執行此方法。當組件更新後,可以在此處操作DOM、執行setState或者執行異步請求操作。

<code>componentDidUpdate(prevProps, prevState, snapshot)
複製代碼/<code>

關於componentDidUpdate有4點說明:

  • 1)componentDidUpdate()的第三個參數snapshot參數來源於getSnapshotBeforeUpdate()生命週期的返回值。若沒有實現getSnapshotBeforeUpdate(),此參數值為undefined。
  • 2)可以在componentDidUpdate()中直接調用setState(),但是它必需被包裹在一個條件語句裡,否則會導致死循環。
  • 3)可以在componentDidUpdate()對更新前後的props進行比較,執行異步操作。
  • 4)如果shouldComponentUpdate()返回值為false,則不會調用componentDidUpdate()。

下面NewComponent組件在componentDidUpdate()裡判斷

<code>class NewComponent extends React.Component {
constructor(props) {

super(props);
this.state = {
projectInfo: null
}
}
getProject = (projectId) => {
projectApi
.getProject(projectId)
.then(res => {
this.projectInfo = res.data;
})
.catch(err => {
message.error(err.message);
});
}
componentDidUpdate(prevProps) {
if (this.props.projectId !== prevProps.projectId) {
this.getProject(this.props.projectId);
}
}
render() {
const { projectInfo } = this.state;
return <react.fragment>
{projectInfo.name}

{projectInfo.detail}

/<react.fragment>
}
}
複製代碼/<code>

14.ref

ref用來給元素或子組件註冊引用信息,允許我們訪問子組件或者子節點。

ref常用於:

  • 管理焦點,文本選擇或媒體播放。
  • 觸發強制動畫。

vue

通過給組件或者子元素設置ref這個attribute為子組件或者子元素賦予一個ID引用。

$refs只會在組件渲染完成之後生效,並且它們不是響應式的。這僅作為一個用於直接操作子組件的“逃生艙”——你應該避免在模板或計算屬性中訪問$refs。

(1)子元素引用ref

子元素上引用ref

<code> 



複製代碼/<code>

加載完畢後使輸入框自動獲取焦點

<code>mounted() {
this.$refs.inputMessage.focus();
}
複製代碼/<code>

(2)子組件引用ref

子組件引用ref常用於父組件使用子組件的方法。

常用表單驗證就是採用這種方式驗證的。

<code><template> 


<el-form>
<el-form-item>
<el-input>
/<el-form-item>
<el-form-item>
<el-input>
/<el-form-item>
/<el-form>
<el-button>提交/<el-button>

/<template>


複製代碼/<code>

react

react中不像vue中直接給ref傳字符串類型值,class組件通過React.createRef綁定ref屬性(React v16.0版本之後),函數組件通過useRef綁定ref屬性,還可以使用React.forwardRef用於轉發ref屬性到子組件中。

(1)class組件綁定ref

通過React.createRef在構造函數中生成ref,在綁定到input元素上,加載完成後自動聚焦。

<code>class NewComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
message: 'hello world'
};
this.inputRef = React.createRef();
}
componentDidMount() {
this.inputRef.current.focus();
}
render() {
const { message } = this.state;
return (

type="number"
ref={this.inputRef}
/>
{message}

);
}
}
複製代碼/<code>

(2)函數組件綁定ref

函數組件可以使用useRef綁定ref屬性。useRef返回一個可變的ref對象,其 .current屬性被初始化為傳入的參數(initialValue)。返回的ref 對象在組件的整個生命週期內保持不變。

<code>function NewComponent() {
const [message, setMessage] = useState('hello world.');
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return (


{message}

);
}
複製代碼/<code>

(3)React.forwardRef 轉發 ref 到子組件

React.forwardRef會創建一個React組件,這個組件能夠將其接受的ref屬性轉發到其組件樹下的另一個組件中。

這種技術並不常見,但在以下兩種場景中特別有用:

  • 轉發refs到DOM組件
  • 在高階組件中轉發refs

父組件直接傳遞ref屬性給子組件NewComponent。

<code>function Parent() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return

<newcomponent>

This is refs.

/<newcomponent>
;
}
複製代碼/<code>

子組件使用React.forwardRef 接受渲染函數作為參數,父組件加載完成後聚焦到input輸入框。

<code>const NewComponent = React.forwardRef((props, ref) => (


{props.children}

));
複製代碼/<code>

15.表單(v-model vs value)

對於表單,vue中使用v-model在表單組件上實現雙向數據綁定,react中通過在表單組件上綁定value屬性以受控組件的形式管理表單數據。

vue

v-model指令在表單、<textarea>及<select>元素上創建雙向數據綁定。它會根據控件類型自動選取正確的方法來更新元素。v-model本質上不過是語法糖。/<select>/<textarea>

v-model在內部為不同的輸入元素使用不同的屬性並拋出不同的事件:

  • text和textarea元素使用value屬性和input事件;
  • checkbox和radio使用checked屬性和change事件;
  • select字段將value作為prop並將change作為事件。

(1)基本用法

Ⅰ.文本

input輸入框上綁定v-model屬性綁定msg,當修改input輸入值時,msg會自動同步為用戶輸入值。

<code> 



複製代碼/<code>

v-model寫法等價於:value和@input的結合,:value綁定輸入值,@input表示接收輸入事件修改msg的值為輸入的值,從而實現雙向綁定。

<code> 

(msg = e.target.value)" />

複製代碼/<code>

Ⅱ.複選框

單個複選框綁定到布爾值

<code>


<label>{{ checked }}/<label>

複製代碼/<code>

多個複選框綁定到數組

<code>


<label>apple/<label>
type="checkbox"
id="banana"
value="banana"
v-model="selectedFruits"
/>
<label>banana/<label>

<label>mango/<label>
Selected fruits: {{ selectedFruits }}


複製代碼/<code>

data

<code> data() {
return {
selectedFruits: []
};
}
複製代碼/<code>

Ⅲ.選擇框

1)選擇框單選時,綁定字符串

<code>

<select>
<option> v-for="option in options"
:value="option.value"
:key="option.value"
>
{{ option.text }}
/<option>
/<select>
Selected: {{ selected }}


複製代碼/<code>

data

<code>data() {
return {
selected: "A",
options: [
{ text: "One", value: "A" },
{ text: "Two", value: "B" },
{ text: "Three", value: "C" }
]
};
}
複製代碼/<code>

2)選擇框多選時,綁定的是數組

<code>

<select>
<option> v-for="option in options"
:value="option.value"
:key="option.value"
>
{{ option.text }}
/<option>

/<select>
Selected: {{ selected }}


複製代碼/<code>

data

<code> data() {
return {
selected: ["A"], //多選時綁定的是數組
options: [
{ text: "One", value: "A" },
{ text: "Two", value: "B" },
{ text: "Three", value: "C" }
]
};
}
複製代碼/<code>

####(2)修飾符 vue對於v-model擴展了.lazy、.number、.trim修飾符增強功能。

Ⅰ.lazy

在默認情況下,v-model在每次input事件觸發後將輸入框的值與數據進行同步。添加了.lazy修飾符,轉變為change事件進行同步。

<code>

複製代碼/<code>

Ⅱ.number

.number修飾符可以自動將用戶的輸入轉換為數值類型,尤其是處理數字類型表單項時尤其有用。

<code> 
複製代碼/<code>

Ⅲ.trim

.trim修飾符可以自動過濾用戶輸入的首尾空白字符。

<code> 
複製代碼/<code>

(3)自定義組件使用v-model

一個組件上的v-model默認會利用名為value的prop和名為 input的事件。

InputMessage綁定v-model值為msg

<code>  
複製代碼/<code>

InputMessage組件通過value props接收值,emit input事件給父組件,修改父組件中msg的值。

<code><template>

/<template>


複製代碼/<code>

react

react中,表單元素( <select> <checkbox>)通常維護自己的state,將state賦值給value屬性,並根據用戶輸入通過setState()更新state,以這種方式控制的表單元素稱為“受控組件”。/<checkbox>/<select>

(1)受控組件

受控組件中,state作為組件“唯一的數據源”,組件還控制著用戶操作過程中表單發生的操作。

<code>class CreateForm extends React.Component {
constructor(props) {
super(props);
this.state = {
name: ''
}
}

nameChange = (event) => { // 接收事件作為參數
this.setState({
name: event.target.value
});
}

render() {
const { name } = this.state;
return (


name: {name}

)
}
}
複製代碼/<code>

(2)非受控組件

在react中,對於不能使用state方式管理的表單組件稱為非受控組件,非受控組件的值不能通過代碼控制,表單數據交由DOM節點來處理。對於非受控組件,可以使用ref從DOM節點中獲取表單數據。

始終是一個非受控組件,通過創建ref的形式獲取文件數據。

<code>class CreateForm extends React.Component {
constructor(props) {

super(props);
this.fileRef = React.createRef(null);
}

fileChange = (event) => {
event.preventDefault();
const file = this.fileRef.current.files[0];
console.log(file)
}

render() {
return (


)
}
}
複製代碼/<code>

16.插槽(slot vs Render Props+this.props.children)

vue和react中都實現了“插槽”(內容分發)功能,vue中主要通過slot實現插槽功能,react中通過this.props.children和Render props實現類似vue中的插槽功能。

vue

vue中通過<slot>實現插槽功能,包含默認插槽、具名插槽、作用域插槽。/<slot>

(1)默認插槽

默認插槽使用<slot>在組件內預留分發內容的“佔位”,在組件起始標籤和結束標籤可以包含任何代碼,例如html或者其他組件。

關於默認插槽,有2點說明:

(1)如果不使用插槽,插入到組件中的內容不會渲染。 (2)插槽可以設置後備內容,在不插入任何內容時顯示。

使用默認插槽的組件:

<code><template>

Slot:


<slot>Default content./<slot> // 使用slot預留插槽佔位,slot中的內容作為後備內容

/<template>


複製代碼/<code>

父組件使用該組件,在組件起始標籤和結束標籤添加插槽內容。

<code><slot-component>

This is slot component.


/<slot-component>
複製代碼/<code>

最終插槽內容會被插入到組件<slot>佔位的位置。

<code>  

Slot:


This is slot component.



複製代碼/<code>

當<slot-component>沒有添加插槽內容時,會渲染默認插槽內容。/<slot-component>

<code>

Slot:


Default content.

複製代碼/<code>

(2)具名插槽

默認插槽只能插入一個插槽,當插入多個插槽時需要使用具名插槽。slot元素有一個默認的attribute name,用來定義具名插槽。

默認插槽的name是default。

在向具名插槽提供內容的時候,我們可以在一個 <template>元素上使用v-slot指令,並以v-slot的參數的形式提供其名稱,將內容插入到對應的插槽下。/<template>

v-slot:也可以簡寫為#,例如v-slot:footer可以被重寫為#footer。

插槽組件slot-component有header footer兩個具名插槽和一個默認插槽。

<code><template>

<header>
<slot>
Header content.
/<slot>
/<header>
<main>
<slot>
Main content.
/<slot>

/<main>
<footer>
<slot>
Footer content.
/<slot>
/<footer>

/<template>
複製代碼/<code>

向插槽中分別插入內容:

<code><slot-component>
<template>
This is header content.

/<template>
<template>
This is main content.

/<template>
<template>
This is footer content.

/<template>
/<slot-component>
複製代碼/<code>

最終html會被渲染為:

<code>

<header>
This is header content.

/<header>
<main>
This is main content.

/<main>
<footer>
This is footer content.

/<footer>

複製代碼/<code>

(3)作用域插槽

有時候我們需要在父組件中顯示插槽組件的數據內容,這時候作用域插槽就派上用場了。

作用域插槽需要在<slot>元素上綁定attribute,這被稱為插槽prop。在父級作用域中,可以使用帶值的v-slot來定義我們提供的插槽prop的名字。/<slot>

插槽組件

<code><template>

<header>
<slot>
Header content.
/<slot>
/<header>
<main>
<slot>
{{ person.name }}
/<slot>
/<main>

/<template>


複製代碼/<code>

父組件作用域將包含所有插槽prop的對象命名為slotProps,也可以使用任意你喜歡的名字。

<code> <slot-component>
<template>
This is header content.

/<template>
// 使用帶值的`v-slot`來定義插槽`prop`的名字
<template>
{{ slotProps.person.name }}

{{ slotProps.person.age }}

/<template>
/<slot-component>
複製代碼/<code>

最終html將被渲染為:

<code>

<header>
This is header content.

/<header>
<main>
xiaoming

14

/<main>

複製代碼/<code>

react

react中通過this.props.children和Render props實現類似vue中的插槽功能。

(1)this.props.children

每個組件都可以通過this.props.children獲取包含組件開始標籤和結束標籤之間的內容,這個與vue中的默認插槽類似。

在class組件中使用this.props.children,在function組件中使用props.children。 class組件使用this.props.children獲取子元素內容。

<code>class NewComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return
{this.props.children}

}
}
複製代碼/<code>

function組件使用props.children獲取子元素內容。

<code>function NewComponent(props) {
return
>{props.children}

}
複製代碼/<code>

父組件使用NewComponent組件

<code> <newcomponent>

This is new component header.



This is new component content.

/<newcomponent>
複製代碼/<code>

最終html將被渲染為:

<code>

This is new component header.


This is new component content.


複製代碼/<code>

(2)Render props

render prop是指一種在React組件之間使用一個值為函數的prop共享代碼的技術。render prop是一個用於告知組件需要渲染什麼內容的函數prop。

比如我們常用的react-router-dom中的Route的component prop就採用了典型的render prop的用法。

<code><router>
<route> // component props接收具體的組件
<indexroute>
<route>
/<route>
/<router>
複製代碼/<code>

通過多個render prop即可實現類似vue中具名插槽的功能。

NewComponent定義了header、main、footer prop。

<code>class NewComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
const { header, main, footer, children } = this.props;
return (

<header>
{header || (
Header content.
)}
/<header>
<main>
{main || (
Main content.
)}
/<main>
{children}
<footer>
{footer || (
Footer content.
)}
/<footer>
);
}
}
複製代碼/<code>

父組件向子組件傳遞render prop。

<code> <newcomponent>    header={
This is header content.
}
content={
This is main content.
}
footer={
This is footer content.
}>

This is new component children.

/<newcomponent>
複製代碼/<code>

最終html將被渲染為

<code>

<header>
This is header content.

/<header>
<main>
This is main content.

/<main>
This is new component children.

<footer>
This is footer content.

/<footer>

複製代碼/<code>

結語

以上就是博主關於react和vue的一些對比以及個人思考的中部,覺得有收穫的可以關注一波,點贊一波,碼字不易,萬分感謝,後續下部會盡快持續更新,感謝關注。


原鏈接:https://juejin.im/post/5e292746e51d451c8771d16e


分享到:


相關文章: