Vue: التوجيه الديناميكي للنموذج الخامس

تم إنشاؤها على ١٦ يوليو ٢٠١٥  ·  42تعليقات  ·  مصدر: vuejs/vue

في الوقت الحالي ، لا يدعم توجيه v-model ارتباطات من نوع الشارب لتعبيرات الربط ، ولكن هذه الميزة ستكون مفيدة للغاية لإنشاء عمليات تنفيذ تشبه منشئ النماذج.

التعليق الأكثر فائدة

يمكنك فعل ذلك باستخدام v-model="form[field.name]" .

ال 42 كومينتر

هل يمكنك إعطاء مثال لما قد يكون مفيدًا؟

لنفترض ، على سبيل المثال ، أننا نبني نسخة من phpmyadmin ، والتي تتلقى البيانات من عبارة DESCRIBE TABLE وتقوم بإنشاء نموذج محرر صف من تلك البيانات. ستكون التعبيرات الملزمة ديناميكية بطبيعتها في هذه الحالة ، حيث سنعرف فقط أسماء الحقول بعد تشغيل SQL DESCRIBE TABLE.

+1 ، أنا أبحث عن هذا أيضًا

+1 ، أتمنى أن أرى هذا

ما زلت لا أفهم تمامًا ما الذي يتيحه هذا والذي لا تستطيع البنية الحالية تحقيقه. ربما بعض عينات التعليمات البرمجية؟

بعض الأكواد الزائفة المتعلقة باستنساخ phpmyadmin الموصوفة أعلاه:

    <script>
    modue.exports = {
        data: function(){
            //returns table structure pulled from the backend somehow
            return {fields: [
                {name: "id", type: "integer"},
                {name: "name", type: "varchar"},
                {name: "gender", type: "varchar"}
            ], 
            // this was initialised based on the structure above, does not matter how.
            form: {id: null, name: null, gender: null}); 
        },
       methods: {
          getBindingExpr: function(field){ /* blah-blah */ }
       }

    }
    </script>
    <template>
       <div v-repeat="field: fields">
          <!-- Here we need to display an editor bound to the field -->
           <input type="text" v-model="form.{{field.name}}">
        <!-- Or, we can call a function that calculates the binding expression --
          <input type="text" v-model="{{getBindingExpr(field)}}">
      </div>
    </template>

يمكنك فعل ذلك باستخدام v-model="form[field.name]" .

نستطيع ؟ رائع !

إيفان ، هل يمكنك وضع كمان js يظهر مثالًا على todo-ish

@ yyx990803 ، هذا رائع ، لكنه كان مجرد مثال يظهر مثالًا واحدًا فقط على الاستخدام الديناميكي. قد يكون المنطق أكثر تعقيدًا في نوع من تطبيقات الأعمال.

فقط لأكون واضحًا ، أنا ضد فكرة السماح بالاستيفاء داخل التعبيرات التوجيهية. تعني الشوارب الآن أنه من المتوقع أن تكون النتيجة التي تم تقييمها عبارة عن سلسلة ويتم استخدامها كسلسلة (يتم إدراجها في DOM ، أو إجراء بحث عن المعرف). إن تقييم الشوارب إلى تعبيرات يمكن تقييمها بعد ذلك يجعلها طبقتين من التجريد ويمكن أن ينتهي الأمر بجعل القوالب الخاصة بك مربكة للغاية.

أعتقد أنه سيكون من المفيد جدًا إضافة القدرة على إقحام الجملة قبل تقييم التعبير

تعمل الطريقة data[pathString] بشكل جيد مع الكائنات ذات المستوى المتداخل 1 ولكن بالنسبة إلى 2 أو أكثر لم أجد طريقة للربط ديناميكيًا.

ربما تضيف معدلاً للربط بحيث يكون أوضح من الشوارب

مثال

let myData = {}
let varPath = 'myData.path.to["my"].obj'
let modelPath = 'myData.path.to["my"].model'
<component-name :myparam.interpolate='varPath'></component-name>
<input v-model.interpolate='modelPath'>

أو ربما وظيفة getter / setter يمكن تمريرها.

إخلاء المسؤولية: لم أقرأ المواصفات 2.0 ، لذا ربما تكون قد تناولت هذا الأمر هناك.

@ bhoriuchi لماذا لا توجد خاصية محسوبة؟

computed: {
  varPath: function() {
    return this.myData.path.to['my'].obj;
  },
},
<component-name :myparam="varPath"></component-name>

وبالنسبة إلى v-model يمكنك استخدام الخاصية المحسوبة مع setter.

simplesmiler لم أجرب الخصائص المحسوبة بطريقة ربط ثنائية الاتجاه ،

تحديث

simplesmiler - لذا فإن المشكلة التي this داخل أداة الجمع أو حتى value في get(value) يشير كلاهما إلى المكون.

بعض المعلومات الأساسية عن حالة الاستخدام الخاصة بي.

أقوم بإنشاء مُنشئ نماذج يستخدم كائن json لبناء النماذج. كائن التكوين هو أكثر أو أقل مصفوفة ثنائية الأبعاد من الكائنات (صفوف / نماذج). يحتوي كل كائن تكوين نموذج على حقل نموذج يحتوي على سلسلة المسار للحقل الذي يجب تعيينه. من أجل استخدام خاصية محسوبة لهذا ، سأحتاج إلى أن أكون قادرًا على التحديد من المكون باستخدام رابط المكون ما هو فهرس الصف / النموذج من أجل البحث عن مسار النموذج من كائن التكوين

لدي حاليًا هذا العمل باستخدام مصفوفة ثنائية الأبعاد مُهيأة مسبقًا تسمى formData والتي أقوم بربط كل نموذج بها بـ v-model="formData[rowIndex][formIndex]" وأراقب هذا الكائن لإجراء التغييرات وتحديث كائن البيانات الأصل ، لكنني لا يعجبني هذا الأسلوب لأنه يتطلب مني التهيئة المسبقة لمصفوفة لإضافة مجال ديناميكي.

أحتاج إلى مستويين من التداخل لأنني أستخدم مكون منشئ النماذج هذا على مكون آخر يحتاج إلى تعيين كائن يشبه شيئًا ما

data: {
  templates: {
    operatingSystems: {
      <someuuid1>: [ <osid1>, <osid2> ],
      <someuuid2>: [ <osid5>, <osid10>, <osid22> ]
   }
  }
}

حيث ستبدو سلسلة المسار الخاصة بي

templates.operatingSystems[<dynamic uuid>]

التحديث 2

لقد تغيرت من استخدام مصفوفة متعددة الأبعاد إلى كائن عادي بأسماء مفاتيح

"<rowIndex>_<formIndex>"

واستخدمت ساعة عميقة للحفاظ على مزامنة البيانات مع الوالدين. ما زلت أعتقد أن الربط المتداخل سيكون مفيدًا.

+1

بالنسبة لي ، v-model="$data[field.name]" هو الحل!

victorwpbastos هذا لا يعمل

على سبيل المثال إذا كان لديك البيانات التالية وسلسلة الحقول

$data = {
  'animal': {
    'dog': {
      'husky': 1
    }
  }
}
field.name = 'animal.dog.husky'

وأنت تستخدم

v-model="$data[field.name]"

وأدخل القيمة 2 في النموذج ، ستبدو البيانات في النهاية على هذا النحو

$data = {
  'animal': {
    'dog': {
      'husky': 1
    }
  },
 'animal.dog.husky': 2
}

السبب في فائدة الربط المحرف هو المكان الذي تقوم فيه ببناء مدخلات متداخلة ديناميكية حيث لا يمكنك "رمز ثابت" للمسار الأصلي (على سبيل المثال ، "animal.dog") في التوجيه

أعدت النظر في هذا ووجدت حلاً أكثر بساطة. يمكنك إنشاء كائن مخصص وإضافة محاضر / محددات إليه عند إنشائه باستخدام سلسلة مسار النموذج. اليك مثال بسيط

قائمة المدخلات

<template lang="jade">
  div
    div(v-for="form in config.forms")
      input(v-model="formData[form.model]")
</template>

<script type="text/babel">
  import Vue from 'vue'
  import _ from 'lodash'

  export default {
    props: ['value', 'config'],
    computed: {},
    methods: {
      vueSet (obj, path, val) {
        let value = obj
        let fields = _.isArray(path) ? path : _.toPath(path)
        for (let f in fields) {
          let idx = Number(f)
          let p = fields[idx]
          if (idx === fields.length - 1) Vue.set(value, p, val)
          else if (!value[p]) Vue.set(value, p, _.isNumber(p) ? [] : {})
          value = value[p]
        }
      }
    },
    data () {
      return {
        formData: {}
      }
    },
    created () {
      _.forEach(this.config.forms, (form) => {
        Object.defineProperty(this.formData, form.model, {
          get: () => _.get(this.value, form.model),
          set: (v) => this.vueSet(this.value, form.model, v)
        })
      })
    }
  }
</script>

في الاستخدام

<template lang="jade">
  div
    input-list(v-model="formData", :config='formConfig')
</template>

<script type="text/babel">
  import InputList from './InputList'
  export default {
    components: {
      InputList
    },
    data () {
      return {
        formData: {
          name: 'Jon',
          loc: {
            id: 1
          }
        },
        formConfig: {
          forms: [
            { type: 'input', model: 'loc.id' },
            { type: 'input', model: 'loc["name"]' }
          ]
        }
      }
    }
  }
</script>

في حالة استخدام هذه الطريقة ، بأي طريقة يمكننا ضبط المراقب لكل من البيانات التفاعلية التي تم إنشاؤها ديناميكيًا؟

luqmanrom لست على دراية

لقد كتبت مجموعة أدوات لهذا الغرض. يسمح لك أيضًا بتحوير vuex باستخدام نموذج v

https://github.com/bhoriuchi/vue-deepset

هذا ينبغي أن تفعل خدعة:

التوجيه

Vue.directive('deep-model', {
    bind(el, binding, vnode) {
        el.addEventListener('input', e => {
            new Function('obj', 'v', `obj.${binding.value} = v`)(vnode.context.$data, e.target.value);
        });
    },
    unbind(el) {
        el.removeEventListener('input');
    },
    inserted(el, binding, vnode) {
        el.value = new Function('obj', `return obj.${binding.value}`)(vnode.context.$data);
    },
    update(el, binding, vnode) {
        el.value = new Function('obj', `return obj.${binding.value}`)(vnode.context.$data);
    }
});

الاستخدام (المكون)

const component = Vue.extend({
    template: `<input v-deep-model="'one.two.three'">`,
    data() {
        return {
            one: { two: { three: 'foo' } }
        };
    }
});

هنا مرجع الجيست .

مرحبا اي شخص هنا. أنا أستخدم VUE.js مع Laravel. لدي حقول نموذج مخصص ديناميكي قادمة من قاعدة البيانات. تابعت @ yyx990803 . v-model = "شكل ['اسم']". يعمل المجال. لكن المشكلة هي أنني لا أستطيع الحصول على قيم الحقل في وحدة تحكم Laravel. هل من احد هنا. أنا أستخدم tylerOtwell Form.js Class.
مساعدتكم سيتم تقدير كبير.
شكرا

هذا ليس منتدى مساعدة. لدينا واحد مخصص للإجابة على الأسئلة في https://forum.vuejs.org

لقد جاهدت حقًا أثناء محاولة استدعاء دالة لمعرفة v-model . هنا مثال.

أحاول إنشاء منتقي النطاق الزمني الذي يشبه هذا.
image

هنا ، تأتي الإعدادات المسبقة من مصفوفة تشبه هذا ..

presets = [
  {
    label: 'Today',
    range: [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')]
  },
]

الآن ، لدي أيضًا تاريخان لحقول الإدخال هذه في data للمكون الخاص بي. startDate & endDate .

ما أريد فعله حقًا هو مقارنة التاريخ الذي حدده المستخدم مع التواريخ التي تم تمريرها في تكوين الإعداد المسبق الخاص بي وتعيين قيمة v-model إما true أو false لكنني غير قادر لأن...

  • v-model لا يقبل الشروط لذلك لا يمكنني فعل preset.range[0] === startDate && preset.range[1] === endDate .
  • v-model لا يسمح بتمرير الاسم المستعار v-for إلى وظيفة. لذلك لا يمكنني فعل شيء مثل
<li v-model="isActive(index)" v-for="(preset, index) in presets">
...
</li>

السماح بالحصول على عبارات شرطية على الأقل يمكن أن يحل هذه المشكلة بسهولة.

أيضًا ، قد أفعل شيئًا خاطئًا بشكل أساسي ، لذا يرجى الإشارة إلى ما إذا كان بإمكاني تحقيق ذلك بأي طريقة مختلفة.

لقد قمت حاليًا بحل المشكلة من خلال استغلال حقيقة أن الخصائص المحسوبة هي استدعاءات وظيفية.

النصي

computed: {
  isActive() {
      return this.presets.map(
        preset =>
          preset.range[0] === this.startDate && preset.range[1] === this.endDate
      );
    }
}

نموذج

<li v-model="isActive[index]" v-for="(preset, index) in presets">
...
</li>

لكن يبدو لي حقًا أنه اختراق. لست متأكدا. الرجاء الاقتراح.

هل يعرف أي شخص ما إذا كان هذا يعمل أيضًا مع Vuex كما هو موضح هنا؟ https://vuex.vuejs.org/guide/forms.html

أريد أن يكون لدي حقل إدخال ديناميكي بعض الشيء.

<input v-model="dataHandler" :scope="foo" type="checkbox" />

كيف يمكنني الوصول إلى "نطاق" لعنصر dom داخل الكود التالي؟

computed: {
  message: {
    get () {
      //
    },
    set (value) {
      //
    }
  }
}

vielhuber حاول استخدام ref ؟

<input ref="myInput" v-model="dataHandler" :scope="foo" type="checkbox" />
this.$refs.myInput.getAttribute('scope') // => 'foo'

مرحبًا ، لدي سؤال Vue متعلق بهذا الموضوع - "التوجيه الديناميكي للنموذج v":

عندما أقوم بتنفيذ مكون Vue ، كيف يمكنني التحكم ديناميكيًا في معدل النموذج الخامس - .lazy ، إلخ ؟؟
على سبيل المثال:

<el-input v-model[field.lazy ? '.lazy' : '']="model[field.key]">

هذا يعمل بالنسبة لي.

<input v-model="$data[field].key" type="text">

fritx لتغيير المعدل "ديناميكيًا" ، استخدمت مدير v-if مثل هذا.

<input v-if="field.lazy" v-model.lazy="model[field.key]">
<input v-else v-model="model[field.key]">

يمكن أن يصبح هذا مرهقًا إذا كنت تريد مجموعة كبيرة ومتنوعة من مجموعات متعددة من المعدلات.

أعتقد أن أحد الخيارات يمكن أن يكون إنشاء مكون قابل لإعادة الاستخدام يحتوي على جميع عبارات if وتمريره مكون الإدخال الذي تريد تقديمه ومجموعة من المُعدِّلات التي تحدد المدخلات التي يتم تقديمها بالمعدِّلات المطلوبة. استخدام عبارة if مثل أعلاه كان جيدًا بما يكفي بالنسبة لي.

لم أتمكن من العثور على طريقة للوصول ديناميكيًا إلى الخاصية المحسوبة في توجيه v-model.
لا توجد طريقة بالنسبة لي للوصول إلى خصائصي المحسوبة حيث يمكنك الوصول إلى خصائص البيانات باستخدام
v-model = "بيانات $ [شيء]"

الكود الخاص بي هو شيء من هذا القبيل:

computed: { get () { // }, set (value) { // } } }

أحتاج إلى طريقة للوصول إلى الخاصية المحسوبة بسلسلة ، والتي لم أتمكن من العثور عليها.
هذا مثال ولكن الحلول المختلفة ستعمل أيضًا.
<input v-model="$computed[someDynamicString]">
أو فقط
<input v-model="[someDynamicString]">

أقرب شيء وجدته هو "_computedWatchers [someDynamicString] .value" لكن هذا لا يعمل مع المحددات والمعرفات ، وربما يعمل إذا كانت مجرد قيمة محسوبة.

v-model="dialogTemp.tmBasFuelEntities[dialogTemp.tmBasFuelEntities.findIndex(t=>t.paramCode==item.paramCode)].paramValue"

هذا هو حواري

dialogTemp: {
  tmBasFuelEntities: [
    {
      paramCode: '',
      paramValue: ''
    },
    {
      paramCode: '',
      paramValue: ''
    },
    {
      paramCode: '',
      paramValue: ''
    },
  ]
}

fritx لتغيير المعدل "ديناميكيًا" ، استخدمت مدير v-if مثل هذا.

<input v-if="field.lazy" v-model.lazy="model[field.key]">
<input v-else v-model="model[field.key]">

يمكن أن يصبح هذا مرهقًا إذا كنت تريد مجموعة كبيرة ومتنوعة من مجموعات متعددة من المعدلات.

أعتقد أن أحد الخيارات يمكن أن يكون إنشاء مكون قابل لإعادة الاستخدام يحتوي على جميع عبارات if وتمريره مكون الإدخال الذي تريد تقديمه ومجموعة من المُعدِّلات التي تحدد المدخلات التي يتم تقديمها بالمعدِّلات المطلوبة. استخدام عبارة if مثل أعلاه كان جيدًا بما يكفي بالنسبة لي.

إنه أمر رائع ولكن كان علي أن أنقل الكثير من الدعائم إلى تلك التي هي مطولة جدًا ، أي فكرة؟ تضمين التغريدة

<template v-else-if="itemCom">
        <component v-if="getFieldType(field) === 'number'"
          :is="itemCom"
          :model="model"
          :field="field"
          :schema="schema"
          v-model.number="model[field.key]"
          v-loading="field.loading"
          v-bind="getFieldAttrs(field)"
          v-on="field.listen"
          @form-emit="handleFormEmit"
        ></component>
        <component v-else
          :is="itemCom"
          :model="model"
          :field="field"
          :schema="schema"
          v-model="model[field.key]"
          v-loading="field.loading"
          v-bind="getFieldAttrs(field)"
          v-on="field.listen"
          @form-emit="handleFormEmit"
        ></component>

fritx يمكنك تغيير v-model إلى :value / @input وتحليلها يدويًا.

</template>
        <component v-if="getFieldType(field) === 'number'"
          :is="itemCom"
          :model="model"
          :field="field"
          :schema="schema"
          :value="parseField(field, model[field.key])"
          @input="model[field.key] = parseField(field, $event.target.value)"
          v-loading="field.loading"
          v-bind="getFieldAttrs(field)"
          v-on="field.listen"
          @form-emit="handleFormEmit"
        ></component>
<template>
<script>

export default {
    ...
    methods: {
        parseField (field, val) {
            if (this.getFieldType(field) === 'number') {
                return Number(val);
            }
            return val;
        }
    }
};
</script>

@ danhanson تبدو رائعة

Danhanson أخشى أن يكون:

:value="getFieldValue(field, model[field.key])"
@input="model[field.key] = getFieldValue(field, $event)"
@change="model[field.key] = getFieldValue(field, $event)"

لست متأكدا ، سأحاول. شكرا!

تضمين التغريدة

لقد وجدت حلاً هنا: https://forum.vuejs.org/t/accessing-computed-properties-from-template-dynamically/4798/9

<input v-model="_self[someDynamicString]">
يعمل لدي

شيء من هذا القبيل

<el-input
  v-if="!nestedField.widget"
  v-model="form[nestedField.id]"
  placeholder=""
  v-bind="nestedField.rest"
>
[
  {
    label: '收房价格',
    id: 'housePrice',
    type: Number,
    widget: 'div',
    fieldSet: [
      {
        label: '',
        id: 'housePrice',
        type: Number,
        defaultValue: 0,
        rest: {
          style: 'width:5em;'
        },
      },
      {
        label: '',
        id: 'priceUnit',
        type: String,
        widget: 'select',
        defaultValue: '元/月',
        options: [
          { label: '元/月', value: '元/月' },
          { label: '元/年', value: '元/年' },
          { label: ' 元/天·m2', value: '元/天·m2' },
        ],
        rest: {
          style: 'width:6em;'
        },
      },
    ],
  },
]

عندما يكون نوع الحقل هو Number ، فأنا أرغب في استخدام v-model.number ، وهو أكثر ملاءمة. تضمين التغريدة

أنا teardown v-model لتناسبه.

<el-input
  v-if="!nestedField.widget"
  :value="form[nestedField.id]"
  @input="v => { form[nestedField.id] = isNumber(nestedField.type) ? Number(v) : v }"
  placeholder=""
  v-bind="nestedField.rest"
>
  <template v-if="nestedField.suffixText" slot="append">{{nestedField.suffixText}}</template>
</el-input>

لدي استنساخ HMTL باستخدام (جزء من إدخال النموذج) الذي أقوم بإدخاله باستخدام jquery. (لا تقل لماذا أستخدم jquery). الآن يتم إدراج عنصري بواسطة jquery. فهل من الممكن ربط نموذج v.

$('.area').append('formPart')
in form i have some inputs like
<div class="form-group">
<input type="text" name="area2" /> 
<input type="text" name="area3" />
</div>

فكيف يمكنني ربط نموذج v في المنطقة 2 و 3.

تضمين التغريدة

لقد وجدت حلاً هنا: https://forum.vuejs.org/t/accessing-computed-properties-from-template-dynamically/4798/9

<input v-model="_self[someDynamicString]">
يعمل لدي

يعمل معي أيضًا ، لكن المتغير "_self" محجوز لخصائص Vue الداخلية (انظر # 2098).

بعبارة أخرى ، يمكن أن يتعطل هذا التنفيذ في المستقبل.

أنا أفضل هذه الطريقة:

<template>
  <input v-model="mySelf[someDynamicString]">
</template>

<script>
export default {
  data() {
    return {
      mySelf: this
    }
  }
}
</script>

لمزيد من التفاصيل ، راجع: https://stackoverflow.com/questions/52104176/use-of-self-attribute-from-vue-vm-is-reliable

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات