Vue表单与v-model

274 阅读4分钟

表单输入绑定

基础用法

你可以用 v-model 指令在表单 <input><textarea><select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。

提示

v-model 会忽略所有表单元素的 value、checked、selected attribute 的初始值而总是将当前活动实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

text 和 textarea 元素使用 value propertyinput 事件; checkbox 和 radio 使用 checked propertychange 事件; select 字段将 value 作为 prop 并将 change 作为事件。

提示

对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现 v-model 不会在输入法组织文字过程中得到更新。如果你也想响应这些更新,请使用 input 事件监听器和 value 绑定,而不是使用 v-model。

文本 (Text)

<template>
  <div id="app">
    <input v-model="message" placeholder="edit me" />
    <p>Message is: {{ message }}</p>
    <button @click="message = 'jingxi'">set message to jingxi</button>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";

export default {
  name: "App",
  data() {
    return {
      message: "su",
    };
  },
  components: {},
};
</script>

image.png

多行文本 (Textarea)

<template>
  <div id="app">
    <textarea v-model="message" placeholder="edit me" />
    <p>Message is: {{ message }}</p>
    <button @click="message = 'jingxi'">set message to jingxi</button>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";

export default {
  name: "App",
  data() {
    return {
      message: "su",
    };
  },
  components: {},
};
</script>

image.png

在文本区域插值不起作用,应该使用 v-model 来代替。

<!-- bad -->
<textarea>{{ text }}</textarea>

<!-- good -->
<textarea v-model="text"></textarea>

复选框 (Checkbox)

单个复选框,绑定到布尔值:

<template>
  <div id="app">
    <label>
      <input type="checkbox" v-model="x" />
      <span>抽烟:{{x}}</span>
    </label>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";
12;
export default {
  name: "App",
  data() {
    return {
      x: true,
    };
  },
  components: {},
};
</script>

多个复选框,绑定到同一个数组:

<template>
  <div id="app">
    爱好:{{x}}
    <label>
      <input type="checkbox" v-model="x" value="抽烟" />
      <span>抽烟</span>
    </label>
    <label>
      <input type="checkbox" v-model="x" :value="2"/>
      <span>喝酒</span>
    </label>
    <label>
      <input type="checkbox" v-model="x" value="3"/>
      <span>烫头</span>
    </label>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";
12;
export default {
  name: "App",
  data() {
    return {
      x: [],
    };
  },
  components: {},
};
</script>

image.png

单选框 (Radio)

<template>
  <div id="app">
    爱好:{{x}}
    <label>
      <input name="want(可以不加name)" type="radio" v-model="x" value="抽烟" />
      <span>抽烟</span>
    </label>
    <label>
      <input name="want(可以不加name)" type="radio" v-model="x" value="喝酒"/>
      <span>喝酒</span>
    </label>
    <label>
      <input name="want(可以不加name)" type="radio" v-model="x" value="烫头"/>
      <span>烫头</span>
    </label>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";
12;
export default {
  name: "App",
  data() {
    return {
      x: '',
    };
  },
  components: {},
};
</script>

image.png

选择框 (Select)

单选时

<template>
  <div id="app">
    你想要:{{ x }}
    <select v-model="x">
      <option value="">Please select one</option>
      <option v-for="item in array" :value="item.value" :key="item.value">
        {{ item.text }}
      </option>
    </select>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      array: [
        { text: "抽烟", value: 1 },
        { text: "喝酒", value: 2 },
        { text: "烫头", value: 3 },
      ],
      x: "",
    };
  },
  components: {},
};
</script>

注意

如果 v-model 表达式的初始值未能匹配任何选项,<select> 元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,更推荐像<option disabled value="">Please select one</option>这样提供一个值为空的禁用选项。

多选时 (绑定到一个数组,用的少):

<select v-model="selected" multiple>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>
<br />
<span>Selected: {{ selected }}</span>

form(表单)

<template>
  <div id="app">
    登录
    <form @submit.prevent="onSubmit">
      <label>
        <span>用户名</span>
        <input type="text" v-model="user.username" />
      </label>
      <label>
        <span>密码</span>
        <input type="password" v-model="user.password" />
      </label>
      <button type="submit">登录</button>
    </form>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      user: {
        username: "",
        password: "",
      },
      x: "",
    };
  },
  methods: {
    onSubmit() {
      console.log(this.user);
    },
  },
  components: {},
};
</script>

修饰符

.lazy

在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组织文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件_之后_进行同步:

<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg" />
  • input事件,键盘、鼠标、任何输入设备的输入
  • change事件,只在input失去焦点时触发

.number

如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:

<input v-model.number="age" type="number" />

这通常很有用,因为即使在 type="number" 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值。

.trim

如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:

<input v-model.trim="msg" />

v-model

v-model本质上是一个语法糖。如下代码<input v-model="test">本质上是<input :value="test" @input="test = $event.target.value">,其中@input是对<input>输入事件的一个监听:value="test"是将监听事件中的数据放入到input。在这边需要强调一点,v-model不仅可以给input赋值还可以获取input中的数据,而且数据的获取是实时的,因为语法糖中是用@input对输入框进行监听的。

本质:

<input type="text" v-model="user.username" />

<input type="text" :value="user.username" @input="user.username=$event.target.value" />

总结

面试问如何实现Vue 的双向绑定,就说v-model的用法。

  • 双向绑定
    • v-model可以实现绑定一个数据,在这个数据变化的时候,UI会变化。
    • 在用户改变UI的时候,数据也会变化。
  • 深入
    • v-modelv-bind:valuev-on:input的语法糖。v-on:input="xxx=$event.target.value"

ant-design-vue

引入 ant-design-vue

  1. 安装脚手架工具
vue-cli

$ npm install -g @vue/cli
# OR
$ yarn global add @vue/cli
  1. 创建一个项目
使用命令行进行初始化。

$ vue create antd-demo

并配置项目。

  1. 使用组件
$ npm i --save ant-design-vue
$ yarn add ant-design-vue

完整引入

import Vue from 'vue';
import Antd from 'ant-design-vue';
import App from './App';
import 'ant-design-vue/dist/antd.css';
Vue.config.productionTip = false;

Vue.use(Antd);

/* eslint-disable no-new */
new Vue({
  el: '#app',
  components: { App },
  template: '<App/>',
});

以上代码便完成了 Antd 的引入。需要注意的是,样式文件需要单独引入。

  1. 进入项目并启动。
$ cd antd-demo
$ npm run serve

此时浏览器会访问 http://localhost:8080/ ,看到 Welcome to Your Vue.js App 的界面就算成功了。

input-输入框

  • 通过鼠标或键盘输入内容,是最基础的表单域的包装。

  • 何时使用

    • 需要用户输入表单域内容时。
    • 提供组合型输入框,带搜索的输入框,还可以进行大小选择。
<template>
  <div id="app">
    <a-input placeholder="Basic usage" />
  </div>
</template>

image.png

Form-表单

具有数据收集、校验和提交功能的表单,包含复选框、单选框、输入框、下拉选择框等元素。

如需要使用 v-model 双向绑定式的校验功能可使用新的表单 a-form-model

  • 何时使用

    • 用于创建一个实体或收集信息。
    • 需要对输入的数据类型进行校验时。
  • 表单 我们为 form 提供了以下三种排列方式:

    • 水平排列:标签和表单控件水平排列;(默认)
    • 垂直排列:标签和表单控件上下垂直排列;
    • 行内排列:表单项水平行内排列。
  • 表单域 表单一定会包含表单域,表单域可以是输入控件,标准表单域,标签,下拉菜单,文本域等。

    这里我们封装了表单域 <Form.Item />

注意:

  1. 如果使用 Form.create 处理表单使其具有自动收集数据并校验的功能,建议使用jsx。
  2. 如果不是使用Vue.use(Form)形式注册的Form组件,你需要自行将$form挂载到Vue原型上。Vue.prototype.$form = Form
//.vue
<template>
  <a-form :form="form" :label-col="{ span: 5 }" :wrapper-col="{ span: 12 }" @submit="handleSubmit">
    <a-form-item label="Note">
      <a-input
        v-decorator="['note', { rules: [{ required: true, message: 'Please input your note!' }] }]"
      />
    </a-form-item>
    <a-form-item label="Gender">
      <a-select
        v-decorator="[
          'gender',
          { rules: [{ required: true, message: 'Please select your gender!' }] },
        ]"
        placeholder="Select a option and change input text above"
        @change="handleSelectChange"
      >
        <a-select-option value="male">
          male
        </a-select-option>
        <a-select-option value="female">
          female
        </a-select-option>
      </a-select>
    </a-form-item>
    <a-form-item :wrapper-col="{ span: 12, offset: 5 }">
      <a-button type="primary" html-type="submit">
        Submit
      </a-button>
    </a-form-item>
  </a-form>
</template>

<script>
export default {
  data() {
    return {
      formLayout: 'horizontal',
      form: this.$form.createForm(this, { name: 'coordinated' }),
    };
  },
  methods: {
    handleSubmit(e) {
      e.preventDefault();
      this.form.validateFields((err, values) => {
        if (!err) {
          console.log('Received values of form: ', values);
        }
      });
    },
    handleSelectChange(value) {
      console.log(value);
      this.form.setFieldsValue({
        note: `Hi, ${value === 'male' ? 'man' : 'lady'}!`,
      });
    },
  },
};
</script>

image.png