Skip to content

v-model

组件

组件 v-model 转换为 Vue 2 data.model

jsx
<ModelInput v-model_trim={this.form.name} />

支持成员表达式。Options API 中使用 this.$set;setup render 中对齐 composition render-instance sugar,按需注入 getCurrentInstance().proxy.$set

原生控件

控件支持内容
text inputcomposing guard、lazy、trim、number
textarealazy、trim、number
checkbox单值、数组、true-value、false-value
radiovalue、number
select单选、多选、number
rangeinput/change 事件策略

完整示例

vue
<script lang="jsx">
import ModelInput from '../shared/ModelInput.vue'

export default {
  name: 'VModelDemo',
  components: { ModelInput },
  data() {
    return {
      form: { name: 'Oxc' },
      text: ' trim me ',
      lazyText: 'textarea',
      checks: ['A'],
      enabled: 'yes',
      choice: 'B',
      selected: 2,
      multiple: ['A']
    }
  },
  render() {
    return (
      <article class="demo-card wide-card">
        <span class="case-label">v-model 全类型</span>
        <h3>组件与原生表单</h3>
        <div class="form-grid">
          <ModelInput label="组件 model + trim + $set" vModel_trim={this.form.name} />
          <label class="field-row"><span>input trim</span><input class="control" vModel_trim={this.text} /></label>
          <label class="field-row"><span>textarea lazy</span><textarea class="control" vModel_lazy={this.lazyText} /></label>
          <label><input type="checkbox" value="A" vModel={this.checks} /> A</label>
          <label><input type="checkbox" value="B" vModel={this.checks} /> B</label>
          <label><input type="checkbox" true-value="yes" false-value="no" vModel={this.enabled} /> enabled</label>
          <label><input type="radio" value="A" vModel={this.choice} /> A</label>
          <label><input type="radio" value="B" vModel={this.choice} /> B</label>
          <select class="control" vModel_number={this.selected}>
            <option value="1">one</option><option value="2">two</option>
          </select>
          <select class="control" multiple vModel={this.multiple}>
            <option value="A">A</option><option value="B">B</option><option value="C">C</option>
          </select>
        </div>
        <pre>{JSON.stringify({ form: this.form, text: this.text, checks: this.checks, enabled: this.enabled, choice: this.choice, selected: this.selected, multiple: this.multiple }, null, 2)}</pre>
      </article>
    )
  }
}
</script>

setup render-instance

当 setup 中的 v-model 绑定到成员表达式时,编译器生成的 $set_n_q_i 会改为通过捕获的 Vue 2 render instance 调用。业务源码本身不能使用 this

vue
<script lang="tsx">
import { defineComponent, reactive } from 'vue'
import ModelInput from '../shared/ModelInput.vue'

export default defineComponent({
  name: 'SetupRenderInstanceSfc',
  setup() {
    const form = reactive({
      name: '',
      amount: 1,
      skills: [] as string[]
    })

    return () => (
      <article class="demo-card">
        <span class="case-label">composition render instance</span>
        <h3>setup() 中的 v-model 运行时辅助</h3>
        <p>
          源码没有使用 this;编译器仅为 v-model 生成的
          $set、_n、_i 辅助调用捕获当前 Vue 实例。
        </p>

        <ModelInput
          label="姓名"
          placeholder="输入姓名"
          vModel={form.name}
        />

        <label class="field-row">
          <span>数量</span>
          <input
            class="control"
            type="number"
            vModel_number={form.amount}
          />
        </label>

        <div class="inline-options">
          {['JSX', 'TSX'].map(skill => (
            <label key={skill}>
              <input
                type="checkbox"
                value={skill}
                vModel={form.skills}
              />
              {skill}
            </label>
          ))}
        </div>

        <p class="result-line">
          name: {form.name || '-'} · amount: {form.amount} · skills:{' '}
          {form.skills.join(', ') || '-'}
        </p>
      </article>
    )
  }
})
</script>

基于 Oxc Parser 的 Vue 2.7 JSX/TSX 转换器