Vue和React都是目前最流行、生態最好的前端框架之一。框架自己沒有優劣之分,只有適用之別,選擇符合自身業務場景、團隊基礎的技術纔是咱們最主要的目的。css
博主1年前用的是Vue框架,近半年轉技術棧到React框架,對於Vue和React都有一些基本的瞭解。接下來博主將與你們經過上、中、下三部一塊兒走近Vue和React,共同探討它們的差別。(好比你正在用vue,對react感興趣也能夠看下,反之亦然)html
總體內容概覽:前端
中部將主要從條件渲染、是否顯示、列表渲染、計算屬性、偵聽器、ref
、表單、插槽八個方面對比vue和react,歡迎多多交流,共同探討,感謝支持。vue
上部連接:關於Vue和React的一些對比及我的思考(上)react
條件渲染用於根據條件判斷是否渲染一塊內容。數組
vue中用v-if
指令條件性地渲染一塊內容。只有當表達式返回真值時才被渲染,v-if
還能夠和v-else-if
、v-else
配合使用,用於不一樣條件下的渲染,相似js裏的if else
語法。緩存
<div v-if="showContent">This is content.</div>
複製代碼
data性能優化
data() {
return {
showContent: false
}
}
複製代碼
當showContent
爲false
時,不會渲染DOM
節點,會留下一個註釋標誌。bash
showContent
爲true
時,纔會渲染DOM
節點。前端框架
v-if
和v-else
配合使用時,v-else
必需要和v-if
相鄰,不然會報錯。
<div>
<div v-if="showContent">This is content.</div>
<div v-else>Hide content.</div>
</div>
複製代碼
當有多重判斷條件時,可使用v-else-if
,相似v-if
的else-if塊
,v-else
元素必須緊跟在帶v-if
或者v-else-if
的元素的後面,不然它將不會被識別。
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
複製代碼
另外,當想切換多個元素時,在<template>
上使用v-if
能夠針對元素進行分組。
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
複製代碼
react使用與運算符&&
、三目運算符(?:
)、if else
來實現條件渲染的效果。
與運算符&&
,實現效果相似v-if
,左邊變量爲真值時,渲染右邊的元素。
return (
<div>
{showItem && <div>This is content.</div>}
</div>
);
複製代碼
?:
)使用三目運算符(?:
),實現相似v-if v-else
效果,showItem
變量爲true
時顯示第一個元素,變量爲false
時顯示第二個元素。
return (
<div>
{
showItem ?
(<div>This is true content.</div>) : (<div>This is false content.</div>)
}
</div>
);
複製代碼
當處理多重判斷時,可使用函數加if else
多重判斷或者switch case
的形式來實現,實現相似v-if v-else-if v-else
的效果。
Ⅰ.if-else
多重判斷
render() {
const { type } = this.state;
const toggeleShow = (type) => {
if (type === 'A') {
return <div>A</div>;
} else if (type === 'B') {
return <div>B</div>;
} else if (type === 'C') {
return <div>C</div>;
} else {
return null;
}
};
return (
<div>
{toggeleShow(type)}
</div>
);
}
複製代碼
Ⅱ.switch case
多重判斷
render () {
const { type } = this.state;
const toggeleShow = (type) => {
switch (type) {
case 'A':
return <div>A</div>;
case 'B':
return <div>B</div>;
case 'C':
return <div>C</div>;
default:
return null;
}
};
return (
<div>
{toggeleShow(type)}
</div>
);
}
複製代碼
另外一個用於展現條件的元素的選項是v-show
,react中能夠經過style
或者切換class
的形式實現是否顯示。
v-show
渲染的元素會被渲染並保留在DOM中。v-show
只是簡單地切換元素的css
屬性display
。
<div v-show="showContent">This is content.</div>
複製代碼
showContent
爲false
時,style
的display
屬性值爲none
。
showContent
爲true
時,style
的display
屬性值爲block
(元素默認display
屬性值)。
注意,v-show 不支持
<template>
元素,也不支持 v-else。
v-if
與v-show
對比總結:
v-if
是「真正」的條件渲染,由於它會確保在切換過程當中條件塊內的事件監聽器和子組件適當地被銷燬和重建。v-if
也是惰性的:若是在初始渲染時條件爲假,則什麼也不作——直到條件第一次變爲真時,纔會開始渲染條件塊。v-show
就簡單得多——無論初始條件是什麼,元素老是會被渲染,而且只是簡單地基於 CSS 進行切換。v-if
有更高的切換開銷,而v-show
有更高的初始渲染開銷。所以,若是須要很是頻繁地切換,則使用v-show
較好;若是在運行時條件不多改變,則使用v-if
較好。react中經過修改style
或者class
來實現v-show
相似效果。
經過修改style
屬性的display
屬性來實現切換是否顯示。
<div style={{ display: showItem ? 'block' : 'none' }}>
This is content.
</div>
複製代碼
經過變量判斷修改class
來實現切換效果,本質上也是切換元素的display
屬性來實現切換效果。
在react中動態修改元素樣式時(好比切換
tab
、按鈕選中狀態),適用於使用class
來實現。
const itemClass = showItem ? 'show-item-class' : 'hide-item-class';
return (
<div className={itemClass}>
This is content.
</div >
);
複製代碼
class
樣式:
.show-item-class {
display: block;
}
.hide-item-class {
display: none;
}
複製代碼
vue中使用v-for
來渲染列表,react中使用map
來渲染列表。不論是v-for
仍是map
來渲染列表都須要添加key
值(key
在兄弟節點之間必須惟一),方便快速比較出新舊虛擬DOM
樹間的差別。
vue中可使用v-for
來渲染數組、對象、<template>
、組件。
渲染數組時,使用(item, index) in items
形式的特殊語法,其中items
是源數據數組,item
則是被迭代的數組元素的別名,index
表示當前元素的索引。
<div>
<div v-for="(item, index) in items" :key="item.message + index">
{{item.message}}
</div>
</div>
複製代碼
data
data() {
return {
items: [
{
message: 'Hello'
},
{
message: 'Welcome'
}
]
}
}
複製代碼
v-for
也能夠用來遍歷一個對象的屬性,使用(value, key, index) in obj
的形式,其中key
表示對象的key
值,value
表示對象的value
值,index
表示當前索引。
在遍歷對象時,採用
Object.keys()
的結果遍歷,可是不能保證它的結果在不一樣的 JavaScript 引擎下都一致。
<div v-for="(value, key, index) in obj" :key="key + index">
{{index}}.{{key}}: {{value}}
</div>
複製代碼
data
data() {
return {
obj: {
name: 'xiaoming',
age: 18,
sex: 'male',
height: 175
}
}
}
複製代碼
在<template>
上使用v-for
來渲染一段包含多個元素的內容。
在
<template>
上使用v-for
來渲染元素段時,不容許綁定key值。由於template
上並不會生成實際Dom
節點。能夠給底下的子元素綁定key
值。
<div>
<template v-for="(item, index) in items">
<div :key="item.message">{{ item.message }}</div>
<div :key="item.message + index" class="divider"></div>
</template>
</div>
複製代碼
data
data() {
return {
items: [
{
message: 'hello'
},
{
message: 'world'
},
{
message: 'welcome'
}
]
}
},
複製代碼
生成DOM
時,並不會生成實際DOM
節點。
在自定義組件上,可使用v-for
渲染自定義組件列表,經過props
將數據傳遞給組件。
在組件上使用
v-for
時,key
是必須的。
v-for
渲染自定義組件列表,將item
經過props
傳遞給組件。
<my-component
v-for="(item, index) in items"
:key="item.message + index"
:item="item">
</my-component>
複製代碼
my-component
組件使用props
接收父組件傳來的數據。
<template>
<div>{{item.message}}</div>
</template>
<script>
export default {
props: ['item'],
data() {
return { }
}
}
</script>
複製代碼
react中使用map()
方法來實現列表渲染。
遍歷數組中的每一個元素,獲得一組jsx
元素列表。數組中的每個元素須要添加惟一的key
值。
render() {
const items = [
{
message: 'hello'
},
{
message: 'world'
},
{
message: 'welcome'
}
];
const listItems = items.map((item, index) => <div key={item.message + index}>{item.message}</div>);
return (
<div>
{listItems}
</div>
);
}
複製代碼
對於對象,能夠採用方法經過Object.keys()
或者Object.entries()
來遍歷對象。
render() {
const obj = {
name: 'xiaoming',
age: 18,
sex: 'male',
height: 175
};
const renderObj = (obj) => {
const keys = Object.keys(obj);
return keys.map((item, index) => <div key={index}>{obj[item]}</div>);
};
return (
<div>
{renderObj(obj)}
</div>
);
}
複製代碼
渲染自定義組件列表與vue
中相似,須要給組件添加key
值標識。
render() {
const items = [
{
message: 'hello'
},
{
message: 'world'
},
{
message: 'welcome'
}
];
const listItems = items.map((item, index) =>
<ListItem message={item.message} key={item.message + index} />);
return (
<div>
{listItems}
</div>
);
}
複製代碼
計算屬性表示根據組件的數據(包含組件自身的數據和接收父組件的props
)須要二次計算並「保存」的數據,使用計算屬性的好處是避免每次重複計算的開銷(好比遍歷一個巨大的數組並作大量的計算)。
vue中用computed
來表示計算屬性,能夠定義多個計算屬性,計算屬性能夠互相調用。計算屬性是基於它們的響應式依賴進行緩存的。只在相關響應式依賴發生改變時它們纔會從新求值。vue中能夠直接使用this.xxx
直接獲取到計算屬性。
下面聲明計算屬性reversedMessage
依賴於message
,這就意味着只要 message
尚未發生改變,屢次訪問reversedMessage
計算屬性會當即返回以前的計算結果。
<div>
message: <input type="text" v-model="message" />
<div>{{reversedMessage}}</div>
</div>
複製代碼
script
data() {
return {
message:''
}
},
computed: {
reversedMessage() {
return this.message.split('').reverse().join('')
}
}
複製代碼
技術屬性默認只有getter
,也可使用setter
,當修改計算屬性的時候,會觸發setter
回調。
script
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;
}
}
複製代碼
react hooks使用useMemo
表示memoized
的值,使用useCallback
表示memoized
的回調函數,實現與vue中computed
相似的功能。
適用場景:子組件使用了
PureComponent
或者React.memo
,那麼你能夠考慮使用useMemo
和useCallback
封裝提供給他們的props
,這樣就可以充分利用這些組件的淺比較能力。
useMemo
返回一個memoized
的值。useMemo
會依賴某些依賴值,只有在某個依賴項改變時纔會從新計算memoized
值。若是沒有提供依賴項數組,useMemo 在每次渲染時都會計算新的值。useMemo
能夠做爲性能優化的手段。
傳入
useMemo
的函數會在渲染期間執行。請不要在這個函數內部執行與渲染無關的操做,諸如反作用這類的操做屬於useEffect
的適用範疇,而不是useMemo
。
function NewComponent(props) {
const { num } = props;
const [size, setSize] = useState(0);
// max是useMemo返回的一個memoized的值
const max = useMemo(() => Math.max(num, size), [num, size]);
return (<div>
<input
type="number"
value={size}
onChange={(e) => setSize(e.target.value)} />
<div>Max {max}</div>
</div>);
}
複製代碼
useCallback
把內聯回調函數及依賴項數組做爲參數傳入useCallback
,它將返回該回調函數的memoized
版本,該回調函數僅在某個依賴項改變時纔會更新。當你把回調函數傳遞給通過優化的並使用引用相等性去避免非必要渲染(例如shouldComponentUpdate
的子組件時,它將很是有用。
function NewComponent(props) {
const [message, setMessage] = useState('hello world.');
const handleChange = useCallback((value) => {
setMessage(value);
}, []);
return (<div>
<input
type="number"
value={message}
onChange={(e) => handleChange(e.target.value)} />
<div>{message}</div>
</div>);
}
複製代碼
偵聽器是指經過監聽props
或者組件數據(data
或state
)的變化來執行一些異步或者數據操做。
vue中主要經過watch
監聽props
、data
、computed
(計算屬性)的變化,執行異步或開銷較大的操做。
下面ProjectManage
組件經過watch
監聽projectId prop
的變化獲取對應的項目信息。
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
});
});
}
}
};
複製代碼
react中經過static getDerivedStateFromProps()
和componentDidUpdate()
實現監聽器的功能。
static getDerivedStateFromProps()
getDerivedStateFromProps
會在調用render
方法以前調用,而且在初始掛載及後續更新時都會被調用。它應返回一個對象來更新state
,若是返回null
則不更新任何內容。
關於getDerivedStateFromProps
有2點說明:
props
變化、執行setState
或者forceUpdate
操做都會在每次渲染前觸發此方法。state
的值在任什麼時候候都取決於props
的時候適用該方法。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 <div>{info}</div>
}
}
複製代碼
componentDidUpdate()
componentDidUpdate()
方法在組件更新後被調用。首次渲染不會執行此方法。當組件更新後,能夠在此處操做DOM
、執行setState
或者執行異步請求操做。
componentDidUpdate(prevProps, prevState, snapshot)
複製代碼
關於componentDidUpdate
有4點說明:
componentDidUpdate()
的第三個參數snapshot
參數來源於getSnapshotBeforeUpdate()
生命週期的返回值。若沒有實現getSnapshotBeforeUpdate()
,此參數值爲undefined
。componentDidUpdate()
中直接調用setState()
,可是它必需被包裹在一個條件語句裏,不然會致使死循環。componentDidUpdate()
對更新先後的props
進行比較,執行異步操做。shouldComponentUpdate()
返回值爲false
,則不會調用componentDidUpdate()
。下面NewComponent
組件在componentDidUpdate()
裏判斷
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>
<div>{projectInfo.name}</div>
<div>{projectInfo.detail}</div>
</React.Fragment>
}
}
複製代碼
ref
用來給元素或子組件註冊引用信息,容許咱們訪問子組件或者子節點。
ref
經常使用於:
經過給組件或者子元素設置ref
這個attribute
爲子組件或者子元素賦予一個ID引用。
$refs
只會在組件渲染完成以後生效,而且它們不是響應式的。這僅做爲一個用於直接操做子組件的「逃生艙」——你應該避免在模板或計算屬性中訪問$refs
。
子元素上引用ref
<div>
<input type="text" v-model="message" ref="inputMessage" />
</div>
複製代碼
加載完畢後使輸入框自動獲取焦點
mounted() {
this.$refs.inputMessage.focus();
}
複製代碼
子組件引用ref
經常使用於父組件使用子組件的方法。
經常使用表單驗證就是採用這種方式驗證的。
<template>
<div>
<el-form ref="createForm" label-width="80px" :model="form" :rules="rules">
<el-form-item label="名稱" prop="name">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="郵箱" prop="email">
<el-input v-model="form.email"></el-input>
</el-form-item>
</el-form>
<el-button @click="handleSubmit">提交</el-button>
</div>
</template>
<script>
export default {
name: 'CreateForm',
data() {
return {
form: {
name: '',
email: ''
},
rules: {
name: [{required: true, message: '名稱不能爲空', trigger: 'blur'}],
email: [
{ required: true, message: '請輸入郵箱地址', trigger: 'blur' },
{ type: 'email', message: '請輸入正確的郵箱地址', trigger: ['blur', 'change']}
]
}
}
},
methods: {
handleSubmit() {
this.$refs.createForm.validate((valid) => {
console.log(valid);
})
}
}
}
</script>
複製代碼
react中不像vue中直接給ref
傳字符串類型值,class
組件經過React.createRef
綁定ref
屬性(React v16.3版本以後),函數組件經過useRef
綁定ref
屬性,還可使用React.forwardRef
用於轉發ref
屬性到子組件中。
經過React.createRef
在構造函數中生成ref
,在綁定到input
元素上,加載完成後自動聚焦。
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 (<div>
<input
type="number"
ref={this.inputRef}
/>
<div>{message}</div>
</div>);
}
}
複製代碼
函數組件可使用useRef
綁定ref
屬性。useRef
返回一個可變的ref
對象,其 .current
屬性被初始化爲傳入的參數(initialValue
)。返回的ref
對象在組件的整個生命週期內保持不變。
function NewComponent() {
const [message, setMessage] = useState('hello world.');
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return (<div>
<input type="number" ref={inputRef} />
<div>{message}</div>
</div>);
}
複製代碼
React.forwardRef
會建立一個React組件,這個組件可以將其接受的ref
屬性轉發到其組件樹下的另外一個組件中。
這種技術並不常見,但在如下兩種場景中特別有用:
refs
到DOM
組件refs
父組件直接傳遞ref
屬性給子組件NewComponent
。
function Parent() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return <div>
<NewComponent ref={inputRef}><h2>This is refs.</h2></NewComponent>
</div>;
}
複製代碼
子組件使用React.forwardRef
接受渲染函數做爲參數,父組件加載完成後聚焦到input
輸入框。
const NewComponent = React.forwardRef((props, ref) => (<div>
<input type="number" ref={ref} />
<div>{props.children}</div>
</div>));
複製代碼
對於表單,vue中使用v-model
在表單組件上實現雙向數據綁定,react中經過在表單組件上綁定value
屬性以受控組件的形式管理表單數據。
v-model
指令在表單<input>
、<textarea>
及<select>
元素上建立雙向數據綁定。它會根據控件類型自動選取正確的方法來更新元素。v-model
本質上不過是語法糖。
v-model
在內部爲不一樣的輸入元素使用不一樣的屬性並拋出不一樣的事件:
text
和textarea
元素使用value
屬性和input
事件;checkbox
和radio
使用checked
屬性和change
事件;select
字段將value
做爲prop
並將change
做爲事件。input
輸入框上綁定v-model
屬性綁定msg
,當修改input
輸入值時,msg
會自動同步爲用戶輸入值。
<div>
<input v-model="msg" />
</div>
複製代碼
v-model
寫法等價於:value
和@input
的結合,:value
綁定輸入值,@input
表示接收輸入事件修改msg
的值爲輸入的值,從而實現雙向綁定。
<div>
<input :value="msg" @input="e => (msg = e.target.value)" />
</div>
複製代碼
單個複選框綁定到布爾值
<div>
<input type="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
</div>
複製代碼
多個複選框綁定到數組
<div>
<input type="checkbox" id="apple" value="apple" v-model="selectedFruits" />
<label for="jack">apple</label>
<input
type="checkbox"
id="banana"
value="banana"
v-model="selectedFruits"
/>
<label for="john">banana</label>
<input type="checkbox" id="mango" value="mango" v-model="selectedFruits" />
<label for="mango">mango</label>
<div>Selected fruits: {{ selectedFruits }}</div>
</div>
複製代碼
data
data() {
return {
selectedFruits: []
};
}
複製代碼
1)選擇框單選時,綁定字符串
<div>
<select v-model="selected">
<option
v-for="option in options"
:value="option.value"
:key="option.value"
>
{{ option.text }}
</option>
</select>
<div>Selected: {{ selected }}</div>
</div>
複製代碼
data
data() {
return {
selected: "A",
options: [
{ text: "One", value: "A" },
{ text: "Two", value: "B" },
{ text: "Three", value: "C" }
]
};
}
複製代碼
2)選擇框多選時,綁定的是數組
<div>
<select v-model="selected" multiple>
<option
v-for="option in options"
:value="option.value"
:key="option.value"
>
{{ option.text }}
</option>
</select>
<div>Selected: {{ selected }}</div>
</div>
複製代碼
data
data() {
return {
selected: ["A"], //多選時綁定的是數組
options: [
{ text: "One", value: "A" },
{ text: "Two", value: "B" },
{ text: "Three", value: "C" }
]
};
}
複製代碼
####(2)修飾符 vue對於v-model
擴展了.lazy
、.number
、.trim
修飾符加強功能。
在默認狀況下,v-model
在每次input
事件觸發後將輸入框的值與數據進行同步。添加了.lazy
修飾符,轉變爲change
事件進行同步。
<!-- 在「change」時而非「input」時更新 -->
<input v-model.lazy="msg" >
複製代碼
.number
修飾符能夠自動將用戶的輸入轉換爲數值類型,尤爲是處理數字類型表單項時尤爲有用。
<input type="number" v-model.number="num" />
複製代碼
.trim
修飾符能夠自動過濾用戶輸入的首尾空白字符。
<input v-model.trim="msg" />
複製代碼
v-model
一個組件上的v-model
默認會利用名爲value
的prop
和名爲 input
的事件。
InputMessage
綁定v-model
值爲msg
<InputMessage v-model="msg" />
複製代碼
InputMessage
組件經過value props
接收值,emit input
事件給父組件,修改父組件中msg
的值。
<template>
<input v-model="message" @input="$emit('input', $event.target.value)" />
</template>
<script>
export default {
name: "InputMessage",
props: ["value"],
data() {
return {
message: this.value
};
}
};
複製代碼
對於像<input type="file" />
這種類型的表單組件,不能使用v-model
管理組件數據,能夠經過refs
管理表單組件的數據,這點和react中的非受控組件一致。
<template>
<div>
<input type="file" ref="file" @change="fileChange" />
</div>
</template>
<script>
export default {
name: "InputFile",
data() {
return {};
},
methods: {
fileChange() {
const file = this.$refs.file.files[0];
console.log(file);
}
}
};
</script>
複製代碼
react中,表單元素(<input> <select> <checkbox>
)一般維護本身的state
,將state
賦值給value
屬性,並根據用戶輸入經過setState()
更新state
,以這種方式控制的表單元素稱爲「受控組件」。
受控組件中,state
做爲組件「惟一的數據源」,組件還控制着用戶操做過程當中表單發生的操做。
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 (
<div>
<input value={name} onChange={this.nameChange} />
<div> name: {name} </div>
</div>)
}
}
複製代碼
在react中,對於不能使用state
方式管理的表單組件稱爲非受控組件,非受控組件的值不能經過代碼控制,表單數據交由DOM
節點來處理。對於非受控組件,可使用ref
從DOM
節點中獲取表單數據。
<input type="file" />
始終是一個非受控組件,經過建立ref
的形式獲取文件數據。
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 (
<div>
<input type="file" ref={this.fileRef} onChange={this.fileChange} />
</div>)
}
}
複製代碼
vue和react中都實現了「插槽」(內容分發)功能,vue中主要經過slot
實現插槽功能,react中經過this.props.children
和Render props
實現相似vue中的插槽功能。
vue中經過<slot>
實現插槽功能,包含默認插槽、具名插槽、做用域插槽。
默認插槽使用<slot></slot>
在組件內預留分發內容的「佔位」,在組件起始標籤和結束標籤能夠包含任何代碼,例如html或者其餘組件。
關於默認插槽,有2點說明:
(1)若是不使用插槽,插入到組件中的內容不會渲染。
(2)插槽能夠設置後備內容,在不插入任何內容時顯示。
使用默認插槽的組件:
<template>
<div>
<h2>Slot:</h2>
<slot>Default content.</slot> // 使用slot預留插槽佔位,slot中的內容做爲後備內容
</div>
</template>
<script>
export default {
name: "SlotComponent",
data() {
return {};
}
};
</script>
複製代碼
父組件使用該組件,在組件起始標籤和結束標籤添加插槽內容。
<slot-component>
<h2>This is slot component.</h2>
</slot-component>
複製代碼
最終插槽內容會被插入到組件<slot></slot>
佔位的位置。
<div>
<h2>Slot:</h2>
<h2>This is slot component.</h2>
</div>
複製代碼
當<slot-component>
沒有添加插槽內容時,會渲染默認插槽內容。
<div>
<h2>Slot:</h2>
Default content.
</div>
複製代碼
默認插槽只能插入一個插槽,當插入多個插槽時須要使用具名插槽。slot
元素有一個默認的attribute name
,用來定義具名插槽。
默認插槽的
name
是default
。
在向具名插槽提供內容的時候,咱們能夠在一個 <template>
元素上使用v-slot
指令,並以v-slot
的參數的形式提供其名稱,將內容插入到對應的插槽下。
v-slot:
也能夠簡寫爲#
,例如v-slot:footer
能夠被重寫爲#footer
。
插槽組件slot-component
有header footer
兩個具名插槽和一個默認插槽。
<template>
<div>
<header>
<slot name="header">
Header content.
</slot>
</header>
<main>
<slot>
Main content.
</slot>
</main>
<footer>
<slot name="footer">
Footer content.
</slot>
</footer>
</div>
</template>
複製代碼
向插槽中分別插入內容:
<slot-component>
<template v-slot:header>
<div>This is header content.</div>
</template>
<template>
<div>This is main content.</div>
</template>
<template #footer>
<div>This is footer content.</div>
</template>
</slot-component>
複製代碼
最終html會被渲染爲:
<div>
<header>
<div>This is header content.</div>
</header>
<main>
<div>This is main content.</div>
</main>
<footer>
<div>This is footer content.</div>
</footer>
</div>
複製代碼
有時候咱們須要在父組件中顯示插槽組件的數據內容,這時候做用域插槽就派上用場了。
做用域插槽須要在<slot>
元素上綁定attribute
,這被稱爲插槽prop
。在父級做用域中,可使用帶值的v-slot
來定義咱們提供的插槽prop
的名字。
插槽組件
<template>
<div>
<header>
<slot name="header">
Header content.
</slot>
</header>
<main>
<slot :person="person">
{{ person.name }}
</slot>
</main>
</div>
</template>
<script>
export default {
name: "SlotComponent",
data() {
return {
person: {
name: "xiaoming",
age: 14
}
};
},
methods: {}
};
</script>
複製代碼
父組件做用域將包含全部插槽prop
的對象命名爲slotProps
,也可使用任意你喜歡的名字。
<slot-component>
<template slot="header">
<div>This is header content.</div>
</template>
// 使用帶值的`v-slot`來定義插槽`prop`的名字
<template v-slot:default="slotProps">
<div>{{ slotProps.person.name }}</div>
<div>{{ slotProps.person.age }}</div>
</template>
</slot-component>
複製代碼
最終html將被渲染爲:
<div>
<header>
<div>This is header content.</div>
</header>
<main>
<div>xiaoming</div>
<div>14</div>
</main>
</div>
複製代碼
react中經過this.props.children
和Render props
實現相似vue中的插槽功能。
每一個組件均可以經過this.props.children
獲取包含組件開始標籤和結束標籤之間的內容,這個與vue中的默認插槽相似。
在
class
組件中使用this.props.children
,在function
組件中使用props.children
。class
組件使用this.props.children
獲取子元素內容。
class NewComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return <div>{this.props.children}</div>
}
}
複製代碼
function
組件使用props.children
獲取子元素內容。
function NewComponent(props) {
return <div>>{props.children}</div>
}
複製代碼
父組件使用NewComponent
組件
<NewComponent>
<h2>This is new component header.</h2>
<div>
This is new component content.
</div>
</NewComponent>
複製代碼
最終html將被渲染爲:
<div>
<h2>This is new component header.</h2>
<div>This is new component content.</div>
</div>
複製代碼
render prop
是指一種在React組件之間使用一個值爲函數的prop
共享代碼的技術。render prop
是一個用於告知組件須要渲染什麼內容的函數prop
。
好比咱們經常使用的react-router-dom
中的Route
的component prop
就採用了典型的render prop
的用法。
<Router history={browserHistory}>
<Route path="/" component={Index}> // component props接收具體的組件
<IndexRoute component={HomePage} />
<Route path="/users" component={Users} />
</Route>
</Router>
複製代碼
經過多個render prop
便可實現相似vue中具名插槽的功能。
NewComponent
定義了header
、main
、footer prop
。
class NewComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
const { header, main, footer, children } = this.props;
return (<div>
<header>
{header || (<div>Header content.</div>)}
</header>
<main>
{main || (<div>Main content.</div>)}
</main>
{children}
<footer>
{footer || (<div>Footer content.</div>)}
</footer>
</div>);
}
}
複製代碼
父組件向子組件傳遞render prop
。
<NewComponent
header={<div>This is header content.</div>}
content={<div>This is main content.</div>}
footer={<div>This is footer content.</div>}>
<div>
This is new component children.
</div>
</NewComponent>
複製代碼
最終html將被渲染爲
<div>
<header>
<div>This is header content.</div>
</header>
<main>
<div>This is main content.</div>
</main>
<div>This is new component children.</div>
<footer>
<div>This is footer content.</div>
</footer>
</div>
複製代碼
以上就是博主關於react和vue的一些對比以及我的思考的中部,以爲有收穫的能夠關注一波,點贊一波,碼字不易,萬分感謝,後續下部會盡快持續更新,感謝關注。