V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
andyshz
V2EX  ›  Vue.js

VUE 开发求助

  •  
  •   andyshz · 1 天前 · 2392 次点击

    请问 VUE 佬们在开发大表单的时候怎么设计绑定对象的?直接在 data 中声明所有表单项来绑定吗?那岂不是会有很多冗余代码?而且如果多个组件都使用这个对象,对象在传递的时候是不是每个组件中又需要声明一次? 刚从后端学习前端,希望能有大哥指点指点,按照后端的逻辑,这个表单不是应该设计为一个对象,每个组件直接复用对象即可,传递也传递对象,但是现在开发过程中出现不少问题,搜了之后好像说不能绑定 js 的类对象。。。。。。

    18 条回复    2025-08-01 11:40:06 +08:00
    lyonbot
        1
    lyonbot  
       1 天前 via Android
    你需要的是不是 store 或者说是全局状态管理?
    andyshz
        2
    andyshz  
    OP
       1 天前
    并不全是吧,主要我只想要这个对象在一个模块中使用,并且希望做到的就是尽可能地减少冗余代码,我对这一块地设计不是很熟悉
    VUEX 和 PINIA 可以是模块级的吗
    Dlad
        3
    Dlad  
       1 天前
    1 、可以全局声明;
    2 、每个页面都声明一次,代码冗余了,因为做到了按需加载,程序执行效率反而更好。
    3 、我们项目中的实践是:element ui 打底,常用类型不自行开发了;复杂业务逻辑字段,定制成组件(我好兄弟用自己名字命名的组件,开始看着头痛,后来习惯了);整个表单需要复用,全局弹出呼出——表单、逻辑全复用了。
    4 、有些变量,全局各处展示需要实时更新的,放在 pinia store 里面。

    我不是职业搞前端的,对最佳实践了解有限。我们自研的 vue 项目按一般软件工程逻辑优化到这个程度。
    M003
        4
    M003  
       1 天前
    方法 1. 父级声明出大对象,然后 v-model 将整个大对象 绑定到子组件;子组件内可以定义变量,也可以不声明变量,子组件可以监听到父组件传递给子组件的 value, 然后深拷贝覆盖子组件声明的变量(未声明直接赋值,当然必须声明个变量是 undefined ), 修改这个变量,监听变量变化,$emit 传递出去给父组件。

    方法 2. 父组件声明出大对象,对象结构明确。给每个子组件只传递需要的对象中的参数,只修改父组件对象中的某个参数,这样不方便于别的组件读取其他变量。(传递方法和上面一样。)


    就不用 store 了。

    我这是野路子,自己写代码摸索的。
    Elissa
        5
    Elissa  
       1 天前
    data 中一般放一个 form 对象,内部属性对应每个表单内容
    ```js
    data: {
    form: {
    name: undefine,
    age: undefine,
    ......
    }
    }
    ```

    优先用组件库的表单组件,这样直接 v-model 绑定 form.xxx 到组件库的组件上

    如果需要复杂填写,通过传参或将 form.xxx 传入自定义组件,组件内部自行实现 v-model 或通过事件总线修改值
    hafuhafu
        6
    hafuhafu  
       1 天前
    工厂模式。你可以写一个函数用来生成这个对象,而不是直接定义对象。
    SaigyoujiNono
        7
    SaigyoujiNono  
       1 天前 via Android
    我一般 export form
    然后 form: { ...form }
    wangtian2020
        8
    wangtian2020  
       1 天前
    多层数据传递直接扔 pinia store 里,组件要的时候自己去取,想当于一个全局共享的 ref 对象。单层就随便传传了,看你自己怎么方便,不要教条
    我甚至单层传递都不用 props 传,我用 ref 调用组件主动 expose 的方法,用方法传参一次性传递。
    watch props 的操作我觉得很蠢
    layxy
        9
    layxy  
       1 天前
    我也是后端,如果页面复杂,尤其有分步操作,建议上状态管理(vue2 的 vuex 或 vue3 的 pinia),但是使用状态管理也有个操蛋的事情,状态读数据和写数据时分开的,虽然可以在 computed 中 get,set,但是这个机制我没搞明白如果获取的对象是个复杂嵌套对象,我修改深层的属性值,这种用法是否正确
    heybwei
        10
    heybwei  
       1 天前
    其实你的问题描述得不是让人很明白,如果能贴一些大概的结构或伪代码就好了
    chenluo0429
        11
    chenluo0429  
       1 天前 via Android
    如果你有一个大的表单对象,有很多字段,然后需要用不同的表单组件去提供对应字段的编辑,正确的实践是子组件只关注它要显示和修改的字段值,并不需要关心原生的大对象。
    如果每个子组件都要关注原生的对象的话,应当用 provide/inject 实现局部的状态共享。如果状态是全局唯一的话,也可以使用 pinia 这种全局状态管理去做。
    faceRollingKB
        12
    faceRollingKB  
       1 天前
    表单设计不建议使用 vuex 或 pinia ,这两个都是用来管理全局变量的,管理局部模块化数据的话就有点吃力,我是使用 vue 自带的 providers ,再根据自己的想法封装了一套依赖注入来实现的,整体表单通过 FormModel 管理数据和表单项配置,并共享给整个组件树,每个表单项也都有专门的 FormControl 来对接表单的各种操作,但是从 0 到 1 的成本有点高,你要有心理准备
    SchwarzeR
        13
    SchwarzeR  
       1 天前
    vue3 如果需要局部状态管理,业务上存在大量复用有必要封装的话,并且不需要考虑 ssr 的情况下,可以通过声明一个 Composition api 的函数( hook )做一个局部的变量初始化,然后用在需要的地方。这个在 https://cn.vuejs.org/guide/reusability/composables 亦有记载

    但是如果会涉及到 ssr 的话,pinia 也可以做局部的模块化声明,就是麻烦一点
    ```
    // 需要传参根据情况改变内容上的时候就给函数加参数
    function useXXXFormData() {

    const onShow = ref(true)

    const formContextState = reactive({
    xxx:12123,
    xxl:123,
    process:123,
    onSync: false
    })

    // 内部使用 vue 的生命周期 api 比如销毁时清理
    onBeforeUnmount(() => {
    console.log("unmounted!");

    })


    return {
    onShow,
    formContextState
    }
    }
    ```
    直接拿代码给你比方?
    在需要拿来初始化调用的时候直接
    const formstate = useXXXFormData()

    不知道我理解的正确不正确
    faceRollingKB
        14
    faceRollingKB  
       1 天前
    示例:

    <script setup lang="ts">
    const form = Provide(FormModel<TData>);
    form.mode = FormMode.edit;
    form.items = [
    describeControl({
    type: controlWrap('t-input'),
    label: 'xxx:',
    prop: 'yyy',
    value: '',
    validator: [FormValidator.required, FormValidator.max(50)],
    options: {
    placeholder: '请输入 xxx'
    }
    }),
    ];
    form.resetData();
    function onConfirm() {
    form
    .validate()
    .then(() => {
    return service.save(form.data);
    })
    .then(() => {
    MessagePlugin.success('操作成功');
    })
    .catch((err) => {
    MessagePlugin.error(err?.message || err);
    });
    };
    </script>

    <template>
    <div v-if="form.data" v-grid.form="2" class="ph-20 gr-24 gc-12 mb-24">
    <q-form-item prop="aaa"></q-form-item>
    <q-form-item prop="bbb"></q-form-item>
    <q-form-item v-if="form.data.bbb === '???'" prop="ccc"></q-form-item>
    <q-form-item prop="ddd"></q-form-item>
    </div>
    </template>

    <style scoped lang="less"></style>
    chobitssp
        15
    chobitssp  
       1 天前
    class + ref
    xingyuc
        16
    xingyuc  
       1 天前
    不同场景不同用法,写的再优雅也抵不过 AI 的冲击
    jspatrick
        17
    jspatrick  
       1 天前
    页面声明大对象,再 provide/inject ,跨页面考虑 store
    wentx
        18
    wentx  
       1 天前
    vibe 了。。 也不知道 cursor 是咋写的,但是能用
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2683 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 13:38 · PVG 21:38 · LAX 06:38 · JFK 09:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.