多年前在网上看到一场开发者的讨论,
# 代码约架?Vue.js和Binding.scala两大框架作者的PK
尽管没有用过scala, 但总是对这一对比念念不忘. 如果确实有优秀的工具能够简化代码量, 那自然是好事, 今天就借助AI的力量, 对前端常用的vue和react代码进行一个简单的比较.
以下代码都用 秘塔AI搜索 生成, 简单进行了清理.
提示词:
react 调用github的公开API, 获取头像数据
js
import { useState, useEffect } from "react";
function App() {
const [input, setInput] = useState("octocat");
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const fetchUser = (username) => {
setLoading(true);
fetch(`https://api.github.com/users/${username}`)
.then((res) => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.then(setUser)
.catch((e) => setError(e.message))
.finally(() => setLoading(false));
};
useEffect(() => {
fetchUser(input);
}, [input]);
return (
<div>
<input
value={input}
onChange={(e) => setInput(e.target.value.trim())}
placeholder="输入 GitHub 用户名"
/>
{loading && <p>加载中...</p>}
{error && <p>错误:{error}</p>}
{user && (
<div style={{ marginTop: "1rem", textAlign: "center" }}>
<img
src={user.avatar_url}
alt={user.login}
/>
<h3>{user.name || user.login}</h3>
</div>
)}
</div>
);
}
看一下vue
js
<template>
<div class="github-avatar">
<input v-model="username" placeholder="GitHub 用户名" @keyup.enter="fetchUser" />
<button @click="fetchUser">获取头像</button>
<!-- 当 data.avatar_url 有值时显示头像 -->
<div v-if="user">
<h3>{{ user.name || user.login }}</h3>
<img :src="user.avatar_url" alt="GitHub Avatar" class="avatar" />
<p>简介:{{ user.bio }}</p>
</div>
<!-- 错误提示 -->
<p v-if="error" class="error">{{ error }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import axios from 'axios'
const username = ref('') // 输入框绑定的用户名
const user = ref(null) // 保存返回的用户对象
const error = ref('') // 错误信息
// 调用 GitHub 公共 API
async function fetchUser() {
if (!username.value) {
error.value = '请先输入用户名'
return
}
error.value = ''
try {
const resp = await axios.get(`https://api.github.com/users/${username.value}`)
// resp.data 中包含 avatar_url 等字段[[1]]
user.value = resp.data
} catch (e) {
if (e.response && e.response.status === 404) {
error.value = '用户不存在'
} else {
error.value = '请求出错,请稍后再试'
}
user.value = null
}
}
</script>
可以看到对于简单的需求, 二者的代码量和行数基本一样. 比较大的区别在于vue的写法更接近传统的html结构, 思路上也是首先有静态模板, 之后是动态逻辑, 中间是数据绑定关系. 而react的模板写在最后, 和js逻辑混在一起, 好处是减少了编译负担, 代价是思路和习惯要转个弯才能适应. 当然vue这种写法也未必就是最好的, 只是对于前端来说, vue提供了一种更平缓的转换曲线, 因此也吸引了众多开发者.
为便于对比把binding.scala的代码也放一下, 由于比较小众, 没有用AI生成的, 而是直接复制了框架作者的代码.
ini
@dom def render = {
val githubUserName = Var("")
def inputHandler = { event: Event => githubUserName := event.currentTarget.asInstanceOf[Input].value }
<div>
<input type="text" oninput={ inputHandler }/>
<hr/>
{
val name = githubUserName.bind
if (name == "") {
<div>Please input your Github user name</div>
} else {
val githubResult = FutureBinding(Ajax.get(s"https://api.github.com/users/${name}"))
githubResult.bind match {
case None =>
<div>Loading the avatar for { name }</div>
case Some(Success(response)) =>
val json = JSON.parse(response.responseText)
<img src={ json.avatar_url.toString }/>
case Some(Failure(exception)) =>
<div>{ exception.toString }</div>
}
}
}
</div>
}
这只是核心代码, 前后还有一些导入和声明. 可以看到该技术借助宏和元编程能力, 把界面和逻辑代码尽可能紧密的结合在一起, 虽然确实减少一些代码行数, 但是否足够清晰易懂, 恐怕还是要划个问号.
今天, 前端, 或者更广泛些, 客户端的代码究竟如何书写, 还没有标准答案. 这个问题的本质是想要兼顾静态展示和动态交互, 但可能并没有一种通用的万能方法, 只能由开发者根据二者的比例作出取舍.