Vue v-model 指令

实例

使用 v-model 指令在 <input> 元素和数据属性之间创建双向绑定。

  1. <template>
  2. <h1>v-model Example</h1>
  3. <p>Write something, and see the 'inputValue' data property update automatically.</p>
  4. <input type="text" v-model="inputValue">
  5. <p>inputValue property: "{{ inputValue }}"</p>
  6. </template>

定义与用法

v-model 指令用于在表单输入元素之间或 Vue 实例属性和组件之间创建双向绑定。


表单输入元素与 v-model

可以与 v-model 一起使用的表单输入元素有 <input>, <select><textarea>

在表单输入元素上与 v-model 双向绑定 的工作方式如下:
  • 当 Vue 检测到输入值发生变化时,它将相应地更新相应的数据属性。(HTML->JavaScript)
  • 当 Vue 检测到 Vue 实例属性发生更改时,它将相应地更新相应的输入值。(JavaScript->HTML)

  • 组件与 v-model

    当在组件上使用 v-model 时,必须使用 propsemits 正确设置组件接口,以实现双向绑定。

    在组件上使用 v-model 进行 双向绑定 的工作方式如下:
  • 当 Vue 检测到父实例属性发生更改时,新值将作为 prpp 发送到组件。
  • 当 Vue 检测到子组件发生更改时,新值将作为 emit 事件发送给父组件。
  • 在组件上使用 v-model 时,默认 prop 名称为 'modelValue',默认 emit 事件名称为 'update:modelValue'。

    当在组件上使用 v-model 时,我们可以将计算属性与 get()set() 方法一起使用,而不是使用 Vue 实例数据属性。

    可以使用 v-model: 为 prop 和 emit 设置不同于默认 'modelValue' 和 'update:modelValue' 的名称。要使多个值作为双向绑定连接到组件,我们必须用自己的 v-model 定义每个这样的值。


    修饰符

    修饰符详情
    .lazyVue 使用更改事件而不是输入事件来确定何时同步这意味着用户必须首先修改输入,然后在更新实例属性值之前将焦点从输入元素切换开。
    .number将输入类型转换为数字当使用 <input type="number"> 时,这是自动完成的。
    .trim删除输入开始和结束处的空白。
    custom要为 v-model 创建自定义修饰符,我们首先需要定义一个 props 'modelModifiers' 来存储新的修饰符修饰符功能是在一个方法中编写的如果设置了修饰符,则在将值 emits 回父组件之前,将在方法中运行相应的代码。

    更多实例

    实例 1

    使用滑块(<input type="range">)更改 'inputValue' 属性值。<input type="text"> 元素会自动更新,因为它绑定到 v-model 的 'inputValue' 属性。

    1. <template>
    2. <h1>v-model Example</h1>
    3. <p>Drag the slider to change the 'inputValue' data property, and see the input text field update automatically because of the two-way binding from v-model.</p>
    4. <input type="range" min="-50" max="50" v-on:input="sliderChange" value="4">
    5. <p>inputValue property: "{{ inputValue }}"</p>
    6. <input type="text" v-model="inputValue">
    7. </template>
    8. <script>
    9. export default {
    10. data() {
    11. return {
    12. inputValue: null
    13. };
    14. },
    15. methods: {
    16. sliderChange(evt) {
    17. this.inputValue = evt.target.value
    18. }
    19. }
    20. }
    21. </script>
    实例 2

    在具有 propsemits 的组件上使用 v-model,以便 <input> 元素中的更改更新父级的 'text' 属性。

    App.vue:

    1. <template>
    2. <h2>Example v-model Directive</h2>
    3. <p>App.vue 'text' property: "{{ text }}"</p>
    4. <comp-one v-model="text"/>
    5. </template>
    6. <script>
    7. export default {
    8. data() {
    9. return {
    10. text: 'Say Cheese'
    11. }
    12. }
    13. }
    14. </script>

    CompOne.vue:

    1. <template>
    2. <div>
    3. <h3>Component</h3>
    4. <p>Write something in the text input field below to see that changes here are emitted from the component, and the parent 'text' property gets updated by the use of v-model.</p>
    5. <input
    6. :value="modelValue"
    7. @input="$emit('update:modelValue', $event.target.value)"
    8. />
    9. </div>
    10. </template>
    11. <script>
    12. export default {
    13. props: ['modelValue'],
    14. emits: ['update:modelValue']
    15. }
    16. </script>
    17. <style scoped>
    18. div {
    19. border: solid black 1px;
    20. padding: 10px;
    21. margin: 20px 0;
    22. max-width: 500px;
    23. }
    24. </style>
    实例 3

    在组件上使用 v-model 来更清楚地演示双向绑定。该组件可以更新父级 'text' 属性,并且当父级 'text' 属性更改时,该组件会更新。

    App.vue:

    1. <template>
    2. <h2>Example v-model Directive</h2>
    3. <p>App.vue 'text' property: "<pre>{{ text }}</pre>"</p>
    4. <button v-on:click="this.text = 'Hello!'">text='Hello!'</button>
    5. <comp-one v-model="text"/>
    6. </template>
    7. <script>
    8. export default {
    9. data() {
    10. return {
    11. text: 'Say Cheese'
    12. }
    13. }
    14. }
    15. </script>
    16. <style>
    17. pre {
    18. display: inline;
    19. background-color: yellow;
    20. }
    21. </style>

    CompOne.vue:

    1. <template>
    2. <div>
    3. <h3>Component</h3>
    4. <p>Two-way binding on component with v-model:</p>
    5. <ol>
    6. <li>The component can update the 'text' property (using text field).</li>
    7. <li>The component gets updated when the 'text' property is changed (using button).</li>
    8. </ol>
    9. <input
    10. :value="modelValue"
    11. @input="$emit('update:modelValue', $event.target.value)"
    12. />
    13. </div>
    14. </template>
    15. <script>
    16. export default {
    17. props: ['modelValue'],
    18. emits: ['update:modelValue']
    19. }
    20. </script>
    21. <style scoped>
    22. div {
    23. border: solid black 1px;
    24. padding: 10px;
    25. margin: 20px 0;
    26. max-width: 600px;
    27. }
    28. </style>
    实例 4

    在组件内部使用具有计算值的 v-model 以及 get()set() 函数。

    CompOne.vue:

    1. <template>
    2. <div>
    3. <h3>Component</h3>
    4. <p>Two-way binding on component with v-model:</p>
    5. <ol>
    6. <li>The component can update the 'text' property (using text field).</li>
    7. <li>The component gets updated when the 'text' property is changed (using button).</li>
    8. </ol>
    9. <input v-model="inpVal"/>
    10. </div>
    11. </template>
    12. <script>
    13. export default {
    14. props: ['modelValue'],
    15. emits: ['update:modelValue'],
    16. computed: {
    17. inpVal: {
    18. get() {
    19. return this.modelValue;
    20. },
    21. set(inpVal) {
    22. this.$emit('update:modelValue',inpVal)
    23. }
    24. }
    25. }
    26. }
    27. </script>
    28. <style scoped>
    29. div {
    30. border: solid black 1px;
    31. padding: 10px;
    32. margin: 20px 0;
    33. max-width: 600px;
    34. }
    35. </style>
    实例 5

    在组件上使用 v-model:message 将默认 prop 名称 'modelValue' 重命名为 'message' 。

    App.vue:

    1. <template>
    2. <h2>Example v-model Directive</h2>
    3. <p>App.vue 'text' property: "<pre>{{ text }}</pre>"</p>
    4. <button v-on:click="this.text = 'Hello!'">text='Hello!'</button>
    5. <comp-one v-model:message="text"/>
    6. </template>
    7. <script>
    8. export default {
    9. data() {
    10. return {
    11. text: 'Say Cheese'
    12. }
    13. }
    14. }
    15. </script>
    16. <style>
    17. pre {
    18. display: inline;
    19. background-color: yellow;
    20. }
    21. </style>

    CompOne.vue:

    1. <template>
    2. <div>
    3. <h3>Component</h3>
    4. <p>Two-way binding on component with v-model:</p>
    5. <ol>
    6. <li>The component can update the 'text' property (using text field).</li>
    7. <li>The component gets updated when the 'text' property is changed (using button).</li>
    8. </ol>
    9. <input
    10. :value="message"
    11. @input="$emit('update:message', $event.target.value)"
    12. />
    13. </div>
    14. </template>
    15. <script>
    16. export default {
    17. props: ['message'],
    18. emits: ['update:message']
    19. }
    20. </script>
    21. <style scoped>
    22. div {
    23. border: solid black 1px;
    24. padding: 10px;
    25. margin: 20px 0;
    26. max-width: 600px;
    27. }
    28. </style>
    实例 6

    在组件上使用 v-model 两次以创建具有两个值的双向绑定。

    App.vue:

    1. <template>
    2. <h2>Example v-model Directive</h2>
    3. <p>Name: "<pre>{{ name }}</pre>"</p>
    4. <p>Height: <pre>{{ height }}</pre> cm</p>
    5. <comp-one
    6. v-model:name="name"
    7. v-model:height="height"
    8. />
    9. </template>
    10. <script>
    11. export default {
    12. data() {
    13. return {
    14. name: 'Olaf',
    15. height: 120
    16. }
    17. }
    18. }
    19. </script>
    20. <style>
    21. pre {
    22. display: inline;
    23. background-color: yellow;
    24. }
    25. </style>

    CompOne.vue:

    1. <template>
    2. <div>
    3. <h3>Component</h3>
    4. <p>Two inputs are bound to the component with v-model through props and emits.</p>
    5. <p>
    6. <label>
    7. Name:
    8. <input
    9. type="text"
    10. :value="name"
    11. @input="$emit('update:name', $event.target.value)"
    12. />
    13. </label>
    14. </p>
    15. <p>
    16. <label>
    17. Height:
    18. <input
    19. type="range"
    20. :value="height"
    21. @input="$emit('update:height', $event.target.value)"
    22. min="50"
    23. max="200"
    24. />
    25. {{ this.$props.height }} cm
    26. </label>
    27. </p>
    28. </div>
    29. </template>
    30. <script>
    31. export default {
    32. props: ['name','height'],
    33. emits: ['update:name','update:height']
    34. }
    35. </script>
    36. <style scoped>
    37. div {
    38. border: solid black 1px;
    39. padding: 10px;
    40. margin: 20px 0;
    41. max-width: 300px;
    42. }
    43. </style>
    实例 7

    使用 .lazy,以便用户必须首先修改输入元素,然后在使用 v-model 更新属性之前将焦点从输入元素上移开。

    1. <template>
    2. <h1>v-model Example</h1>
    3. <p>Using the '.lazy' modifier, you must first write something, then click somewhere else, or use the tab key to switch focus away from the input element, before the property get updated.</p>
    4. <input type="text" v-model.lazy="inputValue">
    5. <p>inputValue property: "{{ inputValue }}"</p>
    6. </template>
    7. <script>
    8. export default {
    9. data() {
    10. return {
    11. inputValue: null
    12. };
    13. }
    14. }
    15. </script>
    实例 8

    使用 .lazy,以便用户必须首先修改输入元素,然后在使用 v-model 更新属性之前将焦点从输入元素上移开。

    1. <template>
    2. <h1>v-model Example</h1>
    3. <p>Using the '.trim' modifier will remove any white spaces at the start and end of the input.</p>
    4. <p>Add white spaces at the start and end in the input fields below to see the difference with or with out '.trim'.</p>
    5. <p>No '.trim': <input type="text" v-model="inputVal1"> "<pre>{{ inputVal1 }}</pre>"</p>
    6. <p>With '.trim': <input type="text" v-model.trim="inputVal2"> "<pre>{{ inputVal2 }}</pre>"</p>
    7. </template>
    8. <script>
    9. export default {
    10. data() {
    11. return {
    12. inputVal1: 'Hello',
    13. inputVal2: 'Hi'
    14. };
    15. }
    16. }
    17. </script>
    18. <style>
    19. pre {
    20. display: inline;
    21. background-color: lightgreen;
    22. }
    23. </style>
    实例 9

    如果设置了 .allCapital 修饰符,则使用自定义 .allCapital 修饰符将输入中的所有字符转换为大写。

    App.vue:

    1. <template>
    2. <h2>Example v-model Directive</h2>
    3. <p>App.vue 'text' property: "{{ text }}"</p>
    4. <comp-one v-model.allCapital="text"/>
    5. </template>
    6. <script>
    7. export default {
    8. data() {
    9. return {
    10. text: ''
    11. }
    12. }
    13. }
    14. </script>

    CompOne.vue:

    1. <template>
    2. <div>
    3. <h3>Component</h3>
    4. <p>Write something in the text input field below. Click somewhere else or use the tab key to shift focus away from the input element to see the effect of the custom 'allCapital' modifier.</p>
    5. <input
    6. :value="modelValue"
    7. @change="this.emitVal"
    8. />
    9. </div>
    10. </template>
    11. <script>
    12. export default {
    13. props: {
    14. modelValue: String,
    15. modelModifiers: {
    16. // modelModifiers is an empty object initially.
    17. // Modifiers set on the component will be stored here.
    18. default: () => ({})
    19. }
    20. },
    21. emits: ['update:modelValue'],
    22. methods: {
    23. emitVal(e) {
    24. let value = e.target.value
    25. if (this.modelModifiers.allCapital) {
    26. value = value.toUpperCase()
    27. }
    28. this.$emit('update:modelValue', value)
    29. }
    30. }
    31. }
    32. </script>
    33. <style scoped>
    34. div {
    35. border: solid black 1px;
    36. padding: 10px;
    37. margin: 20px 0;
    38. max-width: 500px;
    39. }
    40. </style>

    分类导航