如何使用React / Angular / Vue使</div>更接近其<div>?

时间:2019-11-21 13:19:33

标签: html angular reactjs vue.js code-organization

前奏

经验丰富的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?

4 个答案:

答案 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' } } 需要更多智能,但是所有这些操作都是在后台处理的,因此您可以引用namemailing.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,而不是明确地作为模板引擎(其中有很多!)