前奏
经验丰富的C(例如)开发人员将看到200行功能。他们将努力将其划分为(例如)每行20行的十个功能。宽松地说,目标是使一个功能永远不会跨一个屏幕。
上下文(更新)
如果以模块化方式编写桌面(例如C)应用程序,则可以很容易地找到错误。查看main
调用的所有函数。找出罪魁祸首;看看里面;递归。相比之下,HTML开发是一场噩梦。当发现缺陷或需要改进时,很难缩小应修改内容的范围。是否有比服务器端模板或客户端库更好的模块化工具? React / Angular / Vue是否适合这项工作?怎么样?
动机
Web开发人员面临同样的问题。理想的是,开口<div>
及其对应的闭合点</div>
之间的线永远不会跨越一个屏幕。如果无法在一个屏幕上同时看到两者,那么保持良好的代码心理形象就困难得多。
一个模板引擎,例如Jinja,可用于拆分HTML文件。
例如,带有文件
<div class="main">
<div class="left">
<!-- many lines -->
</div>
<div class="right">
<!-- many lines -->
</div>
</div>
Jinja的派生可用于将HTML文件拆分为父文件和子文件。
<div class="main">
{% block left %}
{% endblock %}
{% block right %}
{% endblock %}
</div>
{% extends "main.html" %}
{% block left %}
<!-- many lines -->
{% endblock %}
{% block right %}
<!-- many lines -->
{% endblock %}
这在某种程度上让人想起C语言中的拆分功能。在长函数中,丑陋的标志是缩进也变得过多,然后也很难准确地知道循环的开始和结束位置。
同样可以使用D3.js。上面的HTML文件变成了一对HTML和JS文件。
<div class="main">
</div>
let main = d3.select("main")
let left = main.append("div")
.attr("class", "left");
let right = main.append("div")
.attr("class", "right");
问题
这些解决方案都不对。他们觉得自己喜欢使用功能强大的工具来完成一些非常简单的事情,而对代码的新手(或缺席后的自己)看不清,否则这些事情几乎是微不足道的。
如何使用React/Angular/Vue
拆分上方的第一个HTML文件,以确保无论左边有多少代码,<div class="main">
及其结尾的</div>
都仅相隔几行和正确的DIV?
答案 0 :(得分:3)
您有一个非常体贴的问题。我觉得我的回答有点简单,所以也许我误解了您提出问题的目的。
React和Vue利用组件来组织模板并抽象化DOM的复杂性。您可以在这些组件内部封装尽可能多的行为。
从Vue POV(尽管react具有类似的工具可以实现相同的目标)...如果要使用更少的代码行,则可以封装“ left”和“ right”的全部内容(它们的行为,样式和模板)作为组件*。如果两个组件不共享任何状态或数据,这将变得非常简单明了,因为您无需传递任何道具。
代码示例(在Vue中)
这是一个过于简单的示例,通常MyPage.vue
会具有其他行为,例如加载,动画或设置初始应用程序的数据。
// MyPage.vue
<template>
<div>
<v-left/>
<v-right/>
</div>
</template>
<script>
import VRight from '@/components/right.vue';
import VLeft from '@/components/left.vue';
export default {
components: {
VRight,
VLeft
}
}
</script>
最后,这可能在Vue术语中有些覆盖,但是在this document中有一些很好的代码组织插图(适用于任何语言或框架)。
代码复杂度的衡量标准不仅在于给定功能中的代码行,还在于实现某些东西或破坏代码其他区域的风险时需要触摸的位置。
前端代码最脆弱的领域之一就是CSS,这就是为什么将CSS与组件一起打包(使用CSS-in-JS方法或使用Vue的作用域样式)在代码的稳定性和可重用性方面取得了巨大的进步。你写。
我希望这会有所帮助!
*(在很多情况下,这样做并不是最佳选择的原因)
答案 1 :(得分:1)
如果我正确理解了您的问题,我想您也可以使用Svelte来获得所需的知识,tutorial的目标与React / Vue相似,但在某些方面更多的是组件编译器而不是框架。
playground官方的阅读/玩法非常快,并且可以教授几乎所有已知的知识。
根据您的情况,您可以查看以下this article:
App.svelte-主应用程序文件
<script>
import Main from './Main.svelte';
import Left from './Left.svelte';
import Right from './Right.svelte';
</script>
<Main>
<Left />
<Right />
</Main>
Main.svelte-<Main>
组件(<slot>
代表该组件的调用者的内容-在这种情况下,它包含向左和向右的“调用”)
<style>
...
</style>
<div class="main">
<slot></slot>
</div>
Left.svelte-<Left>
组件
<script>
import Box from './Box.svelte';
</script>
<Box title="Left">
<p>
...
</p>
</Box>
Right.svelte本质上等于Left.svelte
Box.svelte-<Box>
和<Left>
共同使用的<Right>
内部组件
<script>
export let title = "box";
</script>
<style>
...
</style>
<div class="box">
<h3>
{title}
</h3>
<slot></slot>
</div>
(此处将左右共同的部分分解为Box组件,但这显然不是必需的)
为了完整起见,请将示例转换为完整的程序:
main.js
import App from './App.svelte';
const app = new App({
target: document.body,
});
export default app;
package.json
{
"name": "svelte-demo",
"version": "1.0.0",
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",
"start": "sirv public"
},
"devDependencies": {
"rollup": "^1.12.0",
"rollup-plugin-commonjs": "^10.0.0",
"rollup-plugin-livereload": "^1.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-svelte": "^5.0.3",
"rollup-plugin-terser": "^5.1.2",
"svelte": "^3.0.0"
},
"dependencies": {
"sirv-cli": "^0.4.4"
}
}
rollup.config.js:
import svelte from 'rollup-plugin-svelte';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js'
},
plugins: [
svelte({
// enable run-time checks when not in production
dev: !production,
// we'll extract any component CSS out into
// a separate file — better for performance
css: css => {
css.write('public/build/bundle.css');
}
}),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration —
// consult the documentation for details:
// https://github.com/rollup/rollup-plugin-commonjs
resolve({
browser: true,
dedupe: importee => importee === 'svelte' || importee.startsWith('svelte/')
}),
commonjs(),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
],
watch: {
clearScreen: false
}
};
function serve() {
let started = false;
return {
writeBundle() {
if (!started) {
started = true;
require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true
});
}
}
};
}
然后:
npm install
npm run dev
(请注意,这实际上是正式的苗条圣殿骑士使用npx degit sveltejs/template my-svelte-project
创建的内容,如登录页面所述)
令人高兴的是Svelte可以编译为标准JavaScript类,因此可以使用常规JavaScript中的组件。从这个角度来看,这是一个无框架的框架。例如参见https://www.shebanglabs.io/rails-antivirus-clamby-clamav/
答案 2 :(得分:0)
我在许多旧的和现代的框架中都发现了相同的问题,它们没有考虑组件和组件的重用。特别是,如果要包含数据元素,并说要left
作为邮件地址,而right
是送货地址,则很难创建像{{1}这样的通用组件}可以同时用于相同的表单,并且可以可靠地处理数据。
您可以按顺序进行操作,例如对于address
的输入,数据将是一个数组,其左侧可能为name="street"
,右侧为[0]
,但是您必须请小心处理空值,如果重新设计了表单,则数据最终可能不会存放在正确的位置进行更新操作。
我知道它很古老,但是我发现ExtJS是一个很好的框架,用于处理组件和处理数据。等价于您的HTML可能是:
[1]
显然,传播{
name: 'main',
xtype: 'left-and-right',
leftItem: {
name: 'mailing'
xtype: 'address'
},
rightItem: {
name: 'shipping',
xtype: 'address'
}
}
需要更多智能,但是所有这些操作都是在后台处理的,因此您可以引用name
或mailing.street
,而不必担心null并重新设计表格。
不幸的是,ExtJS基本上是垂死的,现在归一家因各种错误原因而闻名的公司所有,而所有相关的开发人员都已离开,所以不建议尝试这种方式。
Google Polymer朝着正确的方向发展,并且与框架无关,因此与任何现代框架一起使用可能是一个不错的选择。同样,如果将其用于数据,则可能需要内置智能才能传播shipping.street
。
答案 3 :(得分:0)
“上面的第一个HTML文件如何使用React / Angular / Vue进行拆分,以确保无论左DIV和右DIV中有多少代码,它的关闭位置都仅相隔几行?” < / em>
JSX(XML方言可编译为创建虚拟DOM元素的JS代码)可以很好地完成此任务。它用于React,有时用于Vue。
要在使用许多功能的C示例上构建代码,这正是我们在这里所做的。每个JSX标签都代表一个函数,该函数返回另一个函数或某些UI元素。除了将所有内容都放在<App />
中之外,我们还可以将<App />
分成<Main />
,<Left />
和<Right />
函数:
const App = props => (
<Main>
<Left />
<Right />
</Main>
)
ReactDOM.render('.app', <App />);
要回答主要问题,这是这些框架的存在理由之一吗?恕我直言,这只是表达创建vdom元素的调用的简写,因为在各处编写<App />
比嵌套React.creatElement({...etc})
更容易。由于它只是代表函数,因此它确实符合您在序言中提到的想法。但是我认为它只是为了方便创建vdom元素/ HTML-in-JS,而不是明确地作为模板引擎(其中有很多!)