本文主要对比总结Rect和Vue一些非常基础的用法,如视图层语法,引用JS变量,类名\内联样式,条件\列表渲染,事件处理的最基础的用法。
本文成文时React最新版本是19.2,Vue最新版本是3.5.22。
组件式开发
原生前端开发中,HTML\CSS\JS通常分为多文件编写,除非非常简单的项目会写在一个文件。
当要修改或复用页面某一部分时,需要去多个文件中查找对应部分的HTML/CSS/JS。
即使将HTML/CSS/JS写在一个文件,也是代码堆叠在一起,难以将某一部分抽取出来复用。
而React和Vue都支持将页面拆分为独立的组件文件,便于复用和修改。
React组件文件通常以.jsx为后缀,Vue则使用.vue单文件组件。
组件结构
React函数组件
React当前主流是函数式组件,即组件就是JS函数.
function MyComponent(){
// ...
}
Vue单文件组件
Vue组件文件以单文件组件(SFC,Single-File Component)为典型形式,文件结构由三个核心标签<template> <script> <style>组成。
<template>编写组件的HTML结构(视图模板)<script>编写组件的JS逻辑(数据、方法等)<style>编写组件的CSS样式
<template>
<!-- 视图模板 -->
</template>
<script>
/* 组件逻辑 */
</script>
<style>
/* 组件样式 */
</style>
视图层语法
React和Vue在视图层的核心差异,体现在React使用JSX(JS XML),而Vue使用Template(模板)。
React和Vue标志性的差别既是JSX和Template的区别。
JSX
JSX是一种将HTML嵌入JS的语法扩展,如果是函数组件则通过JS函数返回HTML来描述视图。
function App(){
return <h1>Hello React!</h1>
}
Template
Template(模板),一种基于HTML的声明式语法,通过在<template>标签内书写HTML来描述视图。
<template>
<h1>Hello Vue!</h1>
</template>
引用JS变量和字面量
JSX中引用JS变量
React的JSX语法无论是元素内容还是元素属性值都通过{}单大括号引用JS变量。
function MyComponent(){
let content = '稀土掘金' // 元素内容
let href = 'https://juejin.cn/' // 元素的href属性值
return (
<a href={href}>{content}</div>
)
}
Template中引用JS变量
Vue的Template中元素内容可以通过{{}}双大括号引用JS变量。
元素属性值需要用""引号包裹引用的JS变量,还需要使用v-bind指令(指令是Template语法的特殊属性,用于在Template中嵌入逻辑)绑定变量,并且JS变量需要在script中声明。
v-bind可以缩写为:
<template>
<!-- 注:要动态绑定href,如果不使用:href而是href="href" -->
<!-- 则会把"href"作为字符串字面量传递给href属性和原生HTML一样 -->
<a :href="href">{{content}}</a>
</template>
<script setup>
let content = '稀土掘金' // 元素内容
let href = 'https://juejin.cn/' // 元素的href属性值
</script>
引用JS字面量
另外React和Vue引用JS字面量和上述引用JS变量的语法是一样的。
类名样式
React className
React通过JSX语法的className属性支持类名样式。
className属性可以使用引号传入字符串,或使用{}大括号传入JS表达式。(注:原生样式类名是class属性,React为了和原生区分采用了className)
className传入字符串
function App(){
return (
<h1 className="title">
<style>{`.title { background-color: #798 }`}</style>
Hello React!
</h1>
)
}
有时候我们需要组件根据某个变量的值(或者说状态)来变换样式,这时可以通过className传入JS表达式来实现,如className根据isActive的值来确定类名是否添加active
function App(){
// 这里isActive声明为变量
// 是因为我们还没学到useState
// 通过手动修改isActive为false测试一下样式根据变量变化
let isActive = true
return (
// className传入三元表达式,根据isActive的值确定是否添加active
<h1 className={isActive ? 'active' : ''}>
<style>{`.active{background-color: #798}`}
Hello React!
</h1>
)
}
Vue绑定class
Vue的Template语法是基于HTML,可以直接使用原生HTML元素class属性。
<template>
<h1 class="title">Hello Vue!</h1>
</template>
<style>
.title {
background-color: #579
}
</style>
但原生class只支持字符串,Vue的Template语法支持class绑定JS对象/数组,需要使用v-bind指令。
v-bind可以缩写为:
- class绑定JS对象
<template>
<!-- 注:这里{}大括号外用""引号包裹,看起来像字符串,但其实传入的是JS对象 -->
<!-- 这是因为Template是扩展HTML,要求属性值用引号包裹 -->
<h1 :class="{active:isActive}">Hello Vue!</h1>
</template>
<script>
// 注:Template使用了变量isActive,需要在这声明
let isActive = true
</script>
<style>
.active {
background-color: #798
}
</style>
- class绑定JS数组
通常元素的class可能不只一个,class绑定JS数组则可以绑定多个类名
<template>
<!-- 注:数组内元素要带''引号,如果不带引号则被认为是变量 -->
<!-- 如下 isActive是变量需要在script中声明 -->
<h1 :class = "['title', isActive ? 'active' : '']"> Hello Vue! </h1>
</template>
<script>
let isActive = true
</script>
<style>
.title {
color: #567
}
.active {
background-color: #798
}
</style>
内联样式
React style
React通过JSX语法的style属性支持内联样式。
style属性必须传入一个JS对象,而且是样式对象。
原生内联样式如下面的代码
<h1 style="background-color:#798">Vanilla</h1>
但在JS中对象键名不能直接使用带有横线的样式名,有两种键名命名方式:
- 驼峰式命名(推荐使用)
- 引号包裹带横线样式名
如 background-color 样式属性就需要使用 backgroundColor 或 'background-color'作为键名。
function App(){
return (
// 注:外侧{}是JSX使用JS变量需要的,内侧{}是JS对象的
<h1 style={{backgroundColor:'#798'}}>
Hello React!
</h1>
<h1 style={{'background-color':'#579'}}>
Hello React!
</h1>
)
}
Vue:style
Vue通过v-bind:style支持内联样式,style可以传入字符串、对象或数组。
- style传入字符串
<template>
<!-- 注:外侧双引号是元素属性值必须使用引号包裹,内侧单引号标识这是一个字符串 -->
<h1 :style="'background-color: #798;color: #567'">Hello Vue!</h1>
</template>
- style传入对象(推荐)
<template>
<!-- 注:带有横线的对象键名要使用引号包裹 -->
<h1 :style="{'background-color':'#798',color:'#567'}">Hello Vue!</h1>
</template>
- style传入数组 当需要传入多个样式对象,可以使用样式数组
<template>
<h1 :style="[baseStyles, dynamicStyles]">Hello Vue!</h1>
</template>
<script setup>
let baseStyles = {
'background-color': '#798'
}
let dynamicStyles = {
color: '#567'
}
</script>
条件渲染
条件渲染是很常见的UI需求,比如登录前显示登录按钮,登录后显示用户名。
React条件渲染
React的JSX语法可以直接是使用原生JS语法的if/else语句支持条件渲染。(注:React的JSX语法是扩展JS所以也可以使用switch/case语句,但通常使用if/else语句即可)
function MyLogin(){
// 手动isLogin改为true测试
let isLogin = false
let username = 'lee'
if(isLogin) {
return (
<span>{username}</span>
)
} else {
return (
<button>login</button>
)
}
}
Vue条件渲染
Vue的template语法支持v-if指令来实现条件渲染。
<template>
<span v-if="isLogin">{{username}}</span>
<button v-else>login</button>
</template>
<script setup>
// 将isLogin改为true测试
let isLogin = false
let username = 'lee'
</script>
列表渲染
列表渲染也是很常见的需求,假设我有一个学生姓名、年龄组成的对象数组。
const students = [
{name: 'lilei', age: 12},
{name: 'hanmeimei', age: 13}
]
将数组按照name:xx | age:xx展示,可以使用列表渲染。
React列表渲染
React的JSX语法可以使用JS中所有能生成迭代结果的语句或方法(比如:for循环、while循环、forEach、for...in、for...of等等),但最推荐的是数组的map方法。
JS中map方法会返回一个新数组,如果把列表UI看成一个由HTML元素组成的数组,那么map用于列表渲染再合适不过。
function StudentList(){
const students = [
{name:'lilei', age: 12},
{name:'hanmeimei', age: 13}
]
return (
<table>
<tr>
<th>name</th>
<th>age</th>
</tr>
{students.map((student) => (
<tr>
<td>{student.name}</td>
<td>{student.age}</td>
</tr>
))}
</table>
)
}
Vue列表渲染
在Vue中通常使用v-for指令支持列表渲染。
<template>
<table>
<tr>
<th>name</th>
<th>age</th>
</tr>
<tr v-for="student in students">
<td>{{student.name}}</td>
<td>{{student.age}}</td>
<tr>
</table>
</template>
<script setup>
const students = [
{name:'lilei', age: 12},
{name:'hanmeimei', age: 13}
]
</script>
事件绑定
React事件绑定直接采用 “小驼峰命名法” 的属性形式,例如将原生 HTML 的 onclick 改为 onClick、onchange 改为 onChange 等,事件处理函数直接通过大括号 {} 传入(本质是传递函数引用)。
Vue通过 v-on 指令(简写为 @)绑定事件,事件名直接使用原生 HTML 的全小写形式(如 click、change),事件处理函数通过引号包裹的形式指定(引用 Vue 实例中的方法)。
对比原生事件绑定
<button onclick="alert('按钮被点击了')">click me!</button>
在Vue中
<button @click="alert('按钮被点击了')">click me!</button>
在React中
function Button(){
return (
<button onClick={()=>alert('按钮被点击了'}>click me!</button>
)
}