1. 程式人生 > >vue常用指令v-model和v-for

vue常用指令v-model和v-for

1.v-model

 一般用於表單input的雙向資料繫結

可以用 v-model 指令在表單 <input> 及 <textarea> 元素上建立雙向資料繫結。它會根據控制元件型別自動選取正確的方法來更新元素。儘管有些神奇,但 v-model 本質上不過是語法糖。它負責監聽使用者的輸入事件以更新資料,並對一些極端場景進行一些特殊處理。

v-model 會忽略所有表單元素的 valuecheckedselected 特性的初始值而總是將 Vue 例項的資料作為資料來源。你應該通過 JavaScript 在元件的 data 選項中宣告初始值。

eg

<template>
  <div >
    <!--常用指令-->
    <!--1.v-model 一般用於表單input的雙向資料繫結-->
    <input type="text" v-model="msg"/> {{msg}}
    <br>
    <textarea v-model="msg0" placeholder="add multiple lines"></textarea>
    {{msg0}}
    <br>
    <div id='example-3'>
      <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
      <label for="jack">Jack</label>
      <input type="checkbox" id="john" value="John" v-model="checkedNames">
      <label for="john">John</label>
      <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
      <label for="mike">Mike</label>
      <br>
      <span>Checked names: {{ checkedNames }}</span>
    </div>
    <br>
    <div id="example-4">
      <input type="radio" id="one" value="One" v-model="picked">
      <label for="one">One</label>
      <br>
      <input type="radio" id="two" value="Two" v-model="picked">
      <label for="two">Two</label>
      <br>
      <span>Picked: {{ picked }}</span>
    </div>
    <div id="example-5">
      <select v-model="selected">
        <option disabled value="">請選擇</option>
        <option>A</option>
        <option>B</option>
        <option>C</option>
      </select>
      <span>Selected: {{ selected }}</span>
    </div>
   
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: '常用指令input',
      msg0: '常用指令textarea',
      checkedNames:[],
      selected:'',
      picked: ''
    }
  }
}
</script>

<style>

</style>

效果:

2.v-for

2.1 v-for在數組裡面的用法

v-for 指令根據一組陣列的選項列表進行渲染。v-for 指令需要使用 item in items 形式的特殊語法,items 是源資料陣列並且 item 是陣列元素迭代的別名。
eg:
<template>
  <div class="hello">
  <ul id="example-1">
  <li v-for="item in items">
    {{ item.message }}
  </li>
</ul>
    
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      items: [
      { message: 'Foo' },
      { message: 'Bar' },
      { message: 'Bar' }
    ]
    }
  }
}  
</script>

<style >

</style>
2.1.1 v-for 在數組裡面用的時候支援一個可選引數index索引,與angular不同,它必須要在迴圈的時候給定一個引數index,才可以引用,即必須在(item,index)in items這樣引用後才可以得到index的值
eg:
<template>
  <div class="hello">
  <ul id="example-1">
  <li v-for="(item,index) in items">
    {{ item.message }}------{{index}}
  </li>
</ul>
    
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      items: [
      { message: 'Foo' },
      { message: 'Bar' },
      { message: 'Bar' }
    ]
    }
  }
}  
</script>

<style >

</style>
效果

可以看見index並沒有顯示,

正確的使用方法

eg:

<template>
  <div class="hello">
  <ul id="example-1">
  <li v-for="item in items">
    {{ item.message }}------{{index}}
  </li>
</ul>
    
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      items: [
      { message: 'Foo' },
      { message: 'Bar' },
      { message: 'Bar' }
    ]
    }
  }
}  
</script>
<style >
</style>

效果:


2.2 v-for 在物件裡面的使用

在物件裡面使用如果沒有其他的可選屬性預設迴圈的是物件的值value

eg:

<template>
  <div class="hello">
  <ul id="example-1">
  <li v-for="item in object">
    {{ item }}
  </li>
</ul>
    
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
     object: {
      firstName: 'John',
      lastName: 'Doe',
      age: 30
    }
    }
  }
}  
</script>

<style >

</style>

效果:他顯示的就是物件的值

同樣的在物件裡面使用index也必須使用引數形成傳入才能取值到索引index,他還可以接受第三個引數,key鍵值,也是當做第三個引數傳入即可獲取使用

eg:

<template>
  <div class="hello">
  <ul id="example-1">
  <li v-for="(item,index,key) in object">
    {{ item }}------{{index}}_____{{key}}
  </li>
</ul>
    
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
     object: {
      firstName: 'John',
      lastName: 'Doe',
      age: 30
    }
    }
  }
}  
</script>

<style >

</style>


效果:

需要注意的是接受的引數第一個必須是value,否在預設把第一個值當做value,也就是說如果引數只有index和key,最終會把第一個引數值當做value值,後面兩個引數的位置可以替換

以下摘自vue的api

key

當 Vue.js 用 v-for 正在更新已渲染過的元素列表時,它預設用“就地複用”策略。如果資料項的順序被改變,Vue 將不會移動 DOM 元素來匹配資料項的順序, 而是簡單複用此處每個元素,並且確保它在特定索引下顯示已被渲染過的每個元素。這個類似 Vue 1.x 的 track-by="$index" 。

這個預設的模式是高效的,但是隻適用於不依賴子元件狀態或臨時 DOM 狀態 (例如:表單輸入值) 的列表渲染輸出

為了給 Vue 一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一 key 屬性。理想的 key 值是每項都有的且唯一的 id。這個特殊的屬性相當於 Vue 1.x 的 track-by ,但它的工作方式類似於一個屬性,所以你需要用 v-bind 來繫結動態值 (在這裡使用簡寫):

<div v-for="item in items" :key="item.id">
  <!-- 內容 -->
</div>

建議儘可能在使用 v-for 時提供 key,除非遍歷輸出的 DOM 內容非常簡單,或者是刻意依賴預設行為以獲取效能上的提升。

因為它是 Vue 識別節點的一個通用機制,key 並不與 v-for 特別關聯,key 還具有其他用途,我們將在後面的指南中看到其他用途。


注意事項

由於 JavaScript 的限制,Vue 不能檢測以下變動的陣列:

  1. 當你利用索引直接設定一個項時,例如:vm.items[indexOfItem] = newValue
  2. 當你修改陣列的長度時,例如:vm.items.length = newLength

為了解決第一類問題,以下兩種方式都可以實現和 vm.items[indexOfItem] = newValue 相同的效果,同時也將觸發狀態更新:

// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice
example1.items.splice(indexOfItem, 1, newValue)

為了解決第二類問題,你可以使用 splice

example1.items.splice(newLength)

還是由於 JavaScript 的限制,Vue 不能檢測物件屬性的新增或刪除

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 現在是響應式的

vm.b = 2
// `vm.b` 不是響應式的

對於已經建立的例項,Vue 不能動態新增根級別的響應式屬性。但是,可以使用 Vue.set(object, key, value) 方法向巢狀物件新增響應式屬性。例如,對於:

var vm = new Vue({
  data: {
    userProfile: {
      name: 'Anika'
    }
  }
})

你可以新增一個新的 age 屬性到巢狀的 userProfile 物件:

Vue.set(vm.userProfile, 'age', 27)

你還可以使用 vm.$set 例項方法,它只是全域性 Vue.set 的別名:

vm.$set(this.userProfile, 'age', 27)

有時你可能需要為已有物件賦予多個新屬性,比如使用 Object.assign() 或 _.extend()。在這種情況下,你應該用兩個物件的屬性建立一個新的物件。所以,如果你想新增新的響應式屬性,不要像這樣:

Object.assign(this.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

你應該這樣做:

this.userProfile = Object.assign({}, this.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

有時,我們想要顯示一個數組的過濾或排序副本,而不實際改變或重置原始資料。在這種情況下,可以建立返回過濾或排序陣列的計算屬性。

例如:

<li v-for="n in evenNumbers">{{ n }}</li>
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
  evenNumbers: function () {
    return this.numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

在計算屬性不適用的情況下 (例如,在巢狀 v-for 迴圈中) 你可以使用一個 method 方法:

<li v-for="n in even(numbers)">{{ n }}</li>
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
  even: function (numbers) {
    return numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

v-for 也可以取整數。在這種情況下,它將重複多次模板。

<div>
  <span v-for="n in 10">{{ n }} </span>
</div>

當它們處於同一節點,v-for 的優先順序比 v-if 更高,這意味著 v-if 將分別重複運行於每個 v-for 迴圈中。當你想為僅有的一些項渲染節點時,這種優先順序的機制會十分有用,如下:

<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo }}
</li>

上面的程式碼只傳遞了未完成的 todos。

而如果你的目的是有條件地跳過迴圈的執行,那麼可以將 v-if 置於外層元素 (或 <template>)上。如:

<ul v-if="todos.length">
  <li v-for="todo in todos">
    {{ todo }}
  </li>
</ul>
<p v-else>No todos left!</p>

瞭解元件相關知識,檢視 元件。完全可以先跳過它,以後再回來檢視。

在自定義元件裡,你可以像任何普通元素一樣用 v-for 。

<my-component v-for="item in items" :key="item.id"></my-component>

2.2.0+ 的版本里,當在元件中使用 v-for 時,key 現在是必須的。

然而,任何資料都不會被自動傳遞到元件裡,因為元件有自己獨立的作用域。為了把迭代資料傳遞到元件裡,我們要用 props :

<my-component
  v-for="(item, index) in items"
  v-bind:item="item"
  v-bind:index="index"
  v-bind:key="item.id"
></my-component>

不自動將 item 注入到元件裡的原因是,這會使得元件與 v-for 的運作緊密耦合。明確元件資料的來源能夠使元件在其他場合重複使用。

下面是一個簡單的 todo list 的完整例子:

<div id="todo-list-example">
  <input
    v-model="newTodoText"
    v-on:keyup.enter="addNewTodo"
    placeholder="Add a todo"
  >
  <ul>
    <li
      is="todo-item"
      v-for="(todo, index) in todos"
      v-bind:key="todo.id"
      v-bind:title="todo.title"
      v-on:remove="todos.splice(index, 1)"
    ></li>
  </ul>
</div>

注意這裡的 is="todo-item" 屬性。這種做法在使用 DOM 模板時是十分必要的,因為在 <ul> 元素內只有 <li> 元素會被看作有效內容。這樣做實現的效果與 <todo-item> 相同,但是可以避開一些潛在的瀏覽器解析錯誤。檢視 DOM 模板解析說明 來了解更多資訊。

Vue.component('todo-item', {
  template: '\
    <li>\
      {{ title }}\
      <button v-on:click="$emit(\'remove\')">X</button>\
    </li>\
  ',
  props: ['title']
})

new Vue({
  el: '#todo-list-example',
  data: {
    newTodoText: '',
    todos: [
      {
        id: 1,
        title: 'Do the dishes',
      },
      {
        id: 2,
        title: 'Take out the trash',
      },
      {
        id: 3,
        title: 'Mow the lawn'
      }
    ],
    nextTodoId: 4
  },
  methods: {
    addNewTodo: function () {
      this.todos.push({
        id: this.nextTodoId++,
        title: this.newTodoText
      })
      this.newTodoText = ''
    }
  }
})