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的一些对比以及我的思考的中部,以为有收获的能够关注一波,点赞一波,码字不易,万分感谢,后续下部会尽快持续更新,感谢关注。