• Vue文档解析


    每一个Vue应用都是通过用Vue函数创建一个新的实例开始
    当一个Vue实例被创建时,它将data对象中的所有property(属性)加入到Vue的响应式系统中,当这些property的值发生改变时,视图将会产生相应,即匹配更新为新的值
    在这里插入图片描述

    当这些数据改变时,视图会进行重渲染,注意:只有当实例被创建时就已经存在于data中的property才是相应式的,即,如果在创建实例后在添加一个新的属性,对于该新属性的改动将不会触发任何视图的更新
    如果知道在晚些时候需要一个property,但是一开始为空或并不存在,只需要设置一些初始值
    例外:使用Object.freeze(需要停止追踪的对象),这会阻止修改现有的property,即相应系统无法再追踪变化
    且该方法需要放在Vue实例前面,对象后面

    除了数据property,Vue实例还暴露了一些有用的实例属性和方法,他们都有前缀$,以便与用户定义的property区分开

    实例生命周期钩子
    每个Vue实例在被创建时都要经过一系列的初始化过程
    例:需要设置数据监听,编译模板,将实例挂载到DOM并在数据变化时更新DOM等
    同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己代码的机会
    比如created钩子可以用在一个实例被创建之后执行代码
    也有一些其他的钩子,在实例生命周期的不同阶段被调用,如mounted,updated,destroyed
    生命周期钩子的this上下文指向调用它的Vue实例

    注意:不要在选项property或回调上使用箭头函数
    如:created:() => console.log(this.a)或app.$watch(‘a’,new Value => this.myMethod())
    因为箭头函数并没有this,this会作为变量一直向上级词法作用域查找,直到找到为止,经常导致
    Uncaught TypeError: Cannot read property of undefined 或
    Uncaught TypeError: this.myMethod is not a function 之类的错误。
    在这里插入图片描述

    模板语法

    Vue.js使用了基于HTML的模板语法,允许开发者声明式地将DOM绑定至底层Vue实例,所有的Vue.js模板都是合法的HTML,所以能被遵循规范的浏览器和HTML解析器解析

    在底层的实现上,Vue将模板编译成虚拟DOM渲染函数,结合响应系统,Vue能够只能地计算出最少需要重新渲染多少组件,并把DOM操作次数减到最少

    如果熟悉虚拟DOM并且喜欢JavaScript原始,可以不用模板,直接写渲染(render)函数,使用可选的JSX语法

    插值

    1.文本

    数据绑定最常见的形式就是使用Mustache语法(双大括号)的文本插值

    <span>Message: {{msg}}</span>
    
    • 1

    Mustache标签将会被替代为对应数据对象上msg property的值。无论何时,绑定的数据对象上msg property发生了改变,插值处的内容都会被更新

    通过使用v-once指令,可以执行一次性的插值,当数据改变时,插值处的内容不会更新,但这会影响到该节点上的其他数据绑定

    <span v-once>这个将不会改变 {{msg}}</span>
    
    • 1
    2.原始HTML

    双大括号会将数据解释为普通文本,而非HTML代码,为了输出正在的HTML,则需要使用v-html指令

    <p>Using mustaches: {{ rawHtml }}</p>
    <p>Using v-html directive: <span v-html="rawHtml"></span></p>
    
    • 1
    • 2

    这个span的内容会被替换成property值rawHtml,直接作为HTML
    会忽略解析property值中的数据绑定
    注意:不能使用v-html来复合局部模板,因为Vue不是基于字符串的模板引擎,组件更合适作为可重用和可组合的基本单位

    动态渲染任意的HTML会非常危险,容易导致XSS攻击,只对可信内容使用HTML插值,不能对用户提供的内容使用插值

    3.Attribute 属性

    Mustache语法不能作用在HTML attribute上,遇到这种情况应该使用v-bind指令

    <div v-bind:id="dynamicId">
    
    • 1

    对于普通的布尔attribute,只要它们存在就意味着值为true,v-bind工作略有不同

    <button v-bind:disabled="isDisabled">Button</button>
    
    • 1

    如果isDisabled的值是null,undefined或false,则disabled属性甚至不会被包含在渲染出来的< button>元素中

    4.使用JavaScript表达式

    对于所有的数据绑定,Vue都提供了完全的JavaScript表达式支持

    {{ number + 1 }}
    {{ ok?'yes':'no' }}
    {{ message.split('').reverse().join('') }}
    <div v-bind:id="'list' + id"></div>
    
    • 1
    • 2
    • 3
    • 4

    这些表达式会在所属Vue实例的数据作用域下作为JavaScript被解析,限制:每个绑定的都只能包含单个表达式
    模板表达式都会被放在沙盒中,只能访问全局变量的一个白名单,如Math和Date,不应该在模板表达式中试图访问用户定义的全局变量

    指令

    指令Directives是带有v-前缀的特殊attribute
    指令attribute的值预期是单个JavaScript表达式(v-for例外)
    指令的职责:当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM

    v-if指令将根据表达式的值的真假来插入/移除元素

    参数

    一些指令能够接收一个参数,在指令名称之后以冒号表示,例如:v-bind指令可以用于响应式地更新HTML attribute

    <a v-bind:href="url">...</a>
    
    • 1

    这里href是参数,告知v-bind指令将该元素的href attribute与表达式url的值绑定

    v-on指令,用于监听DOM事件

    动态参数
    从2.6.0开始,可以用方括号括起来的JavaScript表达式作为一个指令的参数

    <a v-bind:[attributeName]="url">...</a>
    
    • 1

    这里的attributeName会被作为一个JavaScript表达式进行动态求值,求得的值将会作为最终的参数来使用
    例:如果你的Vue实例有一个data property attributeName,其值为href,那么这个绑定将等价于v-bind:href

    同样地,可以使用动态参数为一个动态的事件名绑定处理函数

    <a v-on:[eventName]="doSomething">...</a>
    
    • 1

    当eventName的值为focus时,v-on:[eventName]将等价于v-on:facus

    对动态参数的值的约束
    1.动态参数预期会求出一个字符串,异常情况下值为null,这个特殊的null值可以被显性地用于移除绑定,任何其他非字符串类型的值都将会触发一个警告

    2.动态参数表达式有一些语法约束,因为某些字符,如空格和引号,放在HTML attribute名里是无效的,

    例:<a v-bind:['foo' + bor]="value"> ...</a>
    // 这会触发一个编译警告
    
    • 1
    • 2

    变通的办法是使用没有空格或引号的表达式,或用计算属性代替这种复杂表达式

    3.在DOM中使用模板时(直接在一个HTML文件里撰写模板),还需要避免使用大写字符来命名键名,因为浏览器会把attribute名全部强制转为小写

    // 在DOM中使用模板时,这段代码会被转换为v-bind:[someattr],除非在实例中有一个名为someattr的property,否则代码不会工作
    <a v-bind:[someAttr]="value">...</a>
    
    • 1
    • 2
    修饰符modifier

    修饰符modifier是以半角句号.指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。
    例如:.prevent修饰符告诉v-on指令对于触发的事件调用event.preventDefault()

    <form v-on:submit.prevent="onSubmit">...</form>
    
    • 1
    缩写

    v-前缀作为一种视觉提示,用来识别模板中Vue特定的attribute。当你在使用Vue.js为现有标签添加动态行为(dynamic behavior)时,v-前缀很有帮助,对于一些频繁使用到的指令来说就很繁琐,同时,在构建由Vue管理所有模板的SPA时,v-前缀也变得没那么重要了,因此,Vue为v-bind和v-on这两个最常用的指令,提供了特定简写

    v-bind缩写
    // 完整语法
    <a v-bind:href="url">...</a>
    // 缩写
    <a :href="url">...</a>
    // 动态参数的缩写
    <a :[key]="url">...</a>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    v-on缩写
    //完整语法
    <a v-on:click="doSomething">...</a>
    // 缩写
    <a @click="doSomething">...</a>
    // 动态参数的缩写
    <a @[event]="doSomething">...</a>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    计算属性

    模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的,在模板中放入太多的逻辑会让模板过重且难以维护

    复杂逻辑,应当使用计算属性

    <div id="example">
    	<p>Original message: "{{ message }}"</p>
    	<p>Computed reversed message: "{{ reversedMessage }}"</p>
    </div>
    
    var app = new Vue({
    	el: "#example",
    	data: {
    		message: 'Hello'
    	},
    	computed: {
    		// 计算属性的getter
    		reversedMessage: function(){
    			// this指向app实例
    			return this.message.split('').reverse().join('')
    		}
    	}
    	
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这里我们声明了一个计算属性 reversedMessage
    我们提供的函数将用作property app.reversedMessage的getter函数
    app.reversedMessage的值始终取决于app.message的值

    app.message = 'Goodbye'
    console.log(app.reversedMessage) // => 'eybdooG'
    
    • 1
    • 2

    可以像绑定普通property一样在模板中绑定计算属性,Vue知道app.reversedMessage依赖于app.message,因此当app.message发生变化时,所有依赖app.reversedMessage的绑定也会更新
    以声明的方式创建了这种依赖关系:计算属性的getter函数是没有副作用的,更易于测试和理解

    计算属性缓存vs方法

    通过在表达式中调用方法可以达到和上面一样的效果

    <p>Reversed message: "{{ reversedMessage() }}"</p>
    
    methods: {
    	reversedMessage: function(){
    		return this.message.split('').reverse().join('')
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    我们可以将同一函数定义为一个方法而不是一个计算属性
    二种方式的最终结果确实是完全相同的,但是不同的是:
    计算属性是基于它们的响应式依赖进行缓存的,只在相关响应式依赖发生改变时它们才会重新求值,即:只要message还没有发生改变,多次访问reversedMessage计算属性会立即返回之前的计算结果,而不必再次执行函数

    例如,下面的计算属性将不再更新,因为Date.now()不是死响应式依赖

    computed: {
    	now: function(){
    		return Date.now()
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    相比之下,没当触发重新渲染时,调用方法总会再次执行函数
    为什么需要缓存,假设有一个性能开销比较大的计算属性A,它需要遍历一个巨大的数组并做大量的计算,然后我们可能有其他的计算属性依赖于A,如果没有缓存,我们将不可避免的多次执行A的getter,如果不希望有缓存,请用方法代替

    计算属性vs侦听属性

    Vue提供了一种更通用的方式来观察和响应Vue实例上的数据变动:侦听属性
    当你有一些数据需要随着其他数据变动而变动时,很日你故意滥用watch
    然后,通常更好的做法时使用计算属性而不是命令式的watch回调

    <div id="demo">{{ fullName }}</div>
    
    var app = new Vue({
    	el: "#demo",
    	data: {
    		firstName: 'Foo',
    		lastName: 'Bar',
    		fullName: 'Foo Bar',
    	},
    	watch: {
    		firstName: function(val){
    			this.fullName = val + '' + this.lastName
    		},
    		lastName: function(val) {
    			this.fullName = this.firstName + ' ' + val
    		}
    	}
    })
    
    //上面代码是命令式且重复的,计算属性版本:
    var app = new Vue({
    	el: '#demo',
    	data: {
    		firstName: 'Foo',
    		lastName: 'Bar',
    	},
    	computed: {
    		fullName: function(){
    			return this.firstName + '' + this.lastName
    		}
    	}
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    计算属性的setter
    计算属性默认只有getter,不过在需要时也可以提供一个setter:

    computed: {
    	fullName: {
    		// getter
    		get: function(){
    			return this.firstName + '' + this.lastName
    		}
    		// setter
    		set: function(newValue){
    			var names = newValue.split('')
    			this.firstName = names[0]
    			this.lastName = names[names.length-1]
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    再次运行app.fullName = 'John Doe’时,setter会被调用,app.firstName和app.lastName也会相应地被更新

    侦听器

    虽然计算属性在大多数情况更合适,但有时也需要一个自定义的监听器,这就是为什么Vue通过watch选项提供了一个更通用的方法来响应数据的变化
    当需要在数据变化时执行异步或开销较大的操作时,这个方法时最有用的

    <div id="watch-example">
      <p>
        Ask a yes/no question:
        <input v-model="question">
      </p>
      <p>{{ answer }}</p>
    </div>
    
    <script>
    var watchExampleVM = new Vue({
      el: '#watch-example',
      data: {
        question: '',
        answer: 'I cannot give you an answer until you ask a question!'
      },
      watch: {
        // 如果 `question` 发生改变,这个函数就会运行
        question: function (newQuestion, oldQuestion) {
          this.answer = 'Waiting for you to stop typing...'
          this.debouncedGetAnswer()
        }
      },
      created: function () {
        // `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
        // 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
        // AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
        // `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
        // 请参考:https://lodash.com/docs#debounce
        this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
      },
      methods: {
        getAnswer: function () {
          if (this.question.indexOf('?') === -1) {
            this.answer = 'Questions usually contain a question mark. ;-)'
            return
          }
          this.answer = 'Thinking...'
          var vm = this
          axios.get('https://yesno.wtf/api')
            .then(function (response) {
              vm.answer = _.capitalize(response.data.answer)
            })
            .catch(function (error) {
              vm.answer = 'Error! Could not reach the API. ' + error
            })
        }
      }
    })
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    Class与Style绑定

    操作元素的class列表和内联样式是数据绑定的一个常见需求。因为它们都是attribute,所以我们可以使用v-bind处理它们,只需要通过表达式计算出字符串结果即可,不过,字符串拼接麻烦且易错,因此,在将v-bind用于class和style时,Vue.js做了专门的增强,表达式结果的类型除了字符串外,还可以是对象或数组

    对象语法

    我们可以传给v-bind:class一个对象,以动态的切换class

    <div v-bind:class="{ active: isActive}"></div>
    
    • 1

    上面语法表示active这个class存在与否取决于数据property isActive 的truthiness(真实性)

    可以在对象中传入更过字段来动态切换多个class,此外,v-bind:class指令也可以与普通的class attribute共存

    <div
      class="static"
      v-bind:class="{ active: isActive, 'text-danger': hasError }"
    ></div>
    
    data: {
      isActive: true,
      hasError: false
    }
    
    // 结果渲染为:
    <div class="static active"></div>
    // 当 isActive 或者 hasError 变化时,class 列表将相应地更新。例如,如果 hasError 的值为 true,class 列表将变为
    <div class="static active text-danger"></div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    绑定的数据对象不必内联定义在模板里

    <div v-bind:class="classObject"></div>
    
    data: {
    	classObject: {
    		actice: true,
    		'text-danger': false
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    渲染的结果和上面一样,也可以在这里绑定一个返回对象的计算属性

    <div v-bind:class="classObject"></div>
    data: {
    	isActive: true,
    	error: null
    },
    computed: {
    	classObject: function(){
    		return {
    			active: this.isActive && !this.error
    			'text-danger': this.error && this.error.type === 'fatal'
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    数组语法

    我们可以把一个数组传给v-bind:class,以应用一个class列表

    <div v-bind:class="[activeClass, errorClass]"></div>
    data:{
    	activeClass: 'active',
    	errorClass: 'text-danger'
    }
    渲染为
    <div class="active text-danger"></div>
    如果想根据条件切换列表中的class,可以使用三元表达式:
    <div v-bind:class="[isActive ? activeClass : '',errorClass]"></div>
    这样写将始终添加errorClass,但是只有在isActive是truthy真实时才添加activeClass
    不过,当有多个添加class时,这样写有些繁琐,所以在数组语法中也可以使用对象语法
    <div v-bind:class="[{ active: isActive }, errorClass]"></div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    用在组件上

    当在一个自定义组件上使用class property时,这些class将被添加到该组件的根元素上面,这个元素已经存在的class不会被覆盖

    例如:如果你声明了这个组件
    Vue.component('my-component',{
    	template: '

    Hi

    '
    }) 然后在使用它的时候添加一些class: <my-component class="baz boo"></my-component> HTML将被渲染为 <p class="foor bar baz boo">Hi></p> 同样对带数据绑定class也同样适用 <my-component v-bind:class="{ active: isActive }"></my-component> 当isActive为truthy时,HTML将被渲染成为: <p class="foo bar active">Hi</p>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    绑定内联样式

    对象语法

    v-bind:style 的对象语法十分直观—看着非常像CSS,但其实是一个JavaScript对象.CSS property名可以用驼峰式(camelCase)或短横线分割(kebab-case,记得用引号括起来)来命名:

    <div v-bind:style="{ color:activeColor, fontSize: fontSzie + 'px' }">
    data: {
    	activeColor: 'red',
    	fontSize: 30
    }
    直接绑定到一个样式对象通常会更好,这会让模板更清晰
    <div v-bind:style="styleObject"></div>
    data: {
    	styleObject: {
    		color: 'red',
    		fontSize: '13px'
    	}
    }
    同样地,对象语法常常结合返回对象的计算属性使用
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    数组语法
    v-bind:style 的数组语法可以将多个样式对象应用到同一个元素上:
    <div v-bind:style="[baseStyles, overridingStyles]"></div>
    
    • 1
    • 2
    自动添加前缀

    当v-bind:style使用需要添加浏览器引擎前缀的CSS property时,如transform,Vue.js会自动侦测并添加相应地前缀

    多重值

    从2.3.0起,可以为style绑定中的property提供一个包含多个值的数组,常用于提供多个带前缀的值,例如:

    <div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex']}"></div>
    这样写只会渲染数组中最后一个被浏览器支持的值,在本例中,如果浏览器支持不带浏览器前缀的flexbox,那么就只会渲染display:flex
    
    • 1
    • 2

    条件渲染

    v-if

    v-if指令用于条件性地渲染一块内容,这块内容只会在指令的表达式返回truthy值的时候被渲染

    <h1 v-if="awesome">Vue is awesome!</h1>
    也可以用v-else添加一个else块:
    <h1 v-if="awesome">Vue is avesome!</h1>
    <h1 v-else>Oh on</h1>
    
    • 1
    • 2
    • 3
    • 4

    因为v-if是一个指令,所以必须将它添加到一个元素上,但是如果想切换多个元素,可以把一个元素当做不可见的包裹元素,并在上面使用v-if,最终的渲染结果将不包含元素

    <template v-if="ok">
    	<h1>Title</h1>
    	<p>Paragraph</p>
    </template>
    
    • 1
    • 2
    • 3
    • 4
    v-else

    可以使用v-else指令来表示v-if的else块:

    <div v-if="Math.random() > 0.5">
    	Now you see me
    </div>
    <div v-else>
    	Now you don't
    </div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    v-else元素必须紧跟在v-if或者v-else-if的元素的后面,否则它将不会被识别

    v-else-if

    v-else-if,顾名思义,充当v-if的else-if块,可以连续使用:

    <div v-if="type === 'A'">
    	A
    <div>
    <div v-else-if="type === 'B'">
    	B
    </div>
    <div v-else-if="type === 'C'">
      C
    </div>
    <div v-else>
      Not A/B/C
    </div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    类似于v-else,v-else-if必须紧跟着v-if或者v-else-if元素之后

    用key管理可重复的元素

    Vue会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染,
    除了会使Vue变得非常快之外,还有其他一些好处
    例如,如果你允许用户在不同地登录方式之间切换:

    <template v-if="loginType === 'username'">
      <label>Username</label>
      <input placeholder="Enter your username">
    </template>
    <template v-else>
      <label>Email</label>
      <input placeholder="Enter your email address">
    </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    那么在上面的代码中切换loginType将不会清除用户已经输入的内容,因为两个模板使用了相同的元素,不会替换掉–仅仅是替换了它的placeholder

    这样也不总是符合实际需求,所以Vue提供了一种方式,来表达这两个元素是完全独立的,不要复用它们,只需要添加一个具有唯一值的key attribute即可

    <template v-if="loginType === 'username'">
      <label>Username</label>
      <input placeholder="Enter your username" key="username-input">
    </template>
    <template v-else>
      <label>Email</label>
      <input placeholder="Enter your email address" key="email-input">
    </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    注意:

    v-show

    另一个用于根据条件展示的元素的选项是v-show指令,用法大致一样:

    <h1 v-show="ok">Hello!</h1>
    
    • 1

    不同地是带有v-show的元素始终会被渲染并保留在DOM中,v-show只是简单地切换元素的CSS property display

    注意,v-show不支持元素,也不支持v-else

    v-if vs v-show

    v-if是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建

    v-if也是惰性的:如果在初始渲染时条件为假,则什么也不做,知道条件第一次变为真时,才会开始渲染条件块

    相比之下,v-show就简单的多:不管初始化条件是什么,元素总是会被渲染,并且只是简单地基于CSS进行切换

    一般来说。v-if有更高的切换开销,而v-show有更高的初始渲染开销,因此,如果需要非常频繁地切换,则使用v-show较好,如果在运行时条件很少改变,则使用v-if较好

    v-if 与 v-for一起使用

    不推荐同时使用v-if和v-for
    当v-if与v-for一起使用时,v-for具有比v-if更高的优先级

    列表渲染

    用for把一个数组对应为一组元素

    我们可以用v-for指令基于一个数组来渲染一个列表,v-for指令需要使用item in items形式的特殊语法,其中items是源数据数组,而item则是被迭代的数组元素的别名

    <ul id="example-1">
      <li v-for="item in items" :key="item.message">
        {{ item.message }}
      </li>
    </ul>
    var example1 = new Vue({
      el: '#example-1',
      data: {
        items: [
          { message: 'Foo' },
          { message: 'Bar' }
        ]
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在v-for块中,我们可以访问所有父作用域的property,v-for还支持一个可选的第二个参数,即当前项的索引

    <ul id="example-2">
      <li v-for="(item, index) in items">
        {{ parentMessage }} - {{ index }} - {{ item.message }}
      </li>
    </ul>
    var example2 = new Vue({
      el: '#example-2',
      data: {
        parentMessage: 'Parent',
        items: [
          { message: 'Foo' },
          { message: 'Bar' }
        ]
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    也可以使用of代替in作为分隔符,因为它更接近JavaScript迭代器的语法

    <div v-for="item of items"></div>
    
    • 1
    在v-for里使用对象

    可以使用v-for遍历一个对象的property

    <ul id="v-for-boject" class="demo">
     <li v-for="value in object">
        {{ value }}
      </li>
    </ul>
    new Vue({
      el: '#v-for-object',
      data: {
        object: {
          title: 'How to do lists in Vue',
          author: 'Jane Doe',
          publishedAt: '2016-04-10'
        }
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    也可以提供第二个参数为property名称(也就是键名)

    <div v-for="(value, name) in object">
      {{ name }}: {{ value }}
    </div>
    
    • 1
    • 2
    • 3

    还可以用第三个参数作为索引

    <div v-for="(value, name, index) in object">
      {{ index }}. {{ name }}: {{ value }}
    </div>
    
    • 1
    • 2
    • 3

    在遍历对象时,会按Object.keys()的结果遍历,但是不能保证它的结果在不同地JavaScript引擎下都一直

    维护状态

    当Vue正在更新使用v-for渲染的元素列表时,它默认使用就地更新的策略,如果数据项的顺序被改变,Vue将不会引动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染
    这个默然的模式是高效地,但是只适用于不依赖子组件状态或临时DOM状态(如:表单输入值)的列表渲染输出
    为了给Vue一个提示,以便它能追踪每个节点的身份,从而重用和重新排列现有元素,你需要为每项提供一个唯一的 key attribute

    <div v-for="item in items" v-bind:key="item.id">
    	内容
    </div>
    
    • 1
    • 2
    • 3

    建议尽可能在使用v-for时提供key attribute,除非遍历输出的DOM内容非常简单,或者是刻意依赖默认行为以获取性能上的提升

    因为它是Vue识别节点的一个通用机制,key并不仅与v-for特别关联,还有其他的用途

    注意:不要使用对象或者数组之类的非基本类型值作为v-for的key,请用字符串或数值类型的值

    数组更新检测

    变更方法

    Vue将被侦听的数组的变更方法进行了包裹,所以它们也会触发视图更新,这些被包裹的方法包括
    push()
    pop()
    shift()
    unshift()
    splice()
    sort()
    reverse()

    替换数组

    变更方法,会变更调用了这些方法的原始数组,相比之下,也有非变更方法,例如filter(),concat()和slice(),它们不会变更原始数组,而总是返回一个新数组,当使用非变更方法时,可以用新数组替换旧数组

    example1.items = example1.items.filter({
    	function (item) {
    		return item.message.match(/Foo/)
    	}
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
    注意:由于JavaScript的限制,Vue不能检测数组和对象的变化

    显示过滤/排序后的结果

    有时候,我们想要一个数组经过过滤或排序后的版本,而不实际变更或重置原始数据,在这种情况下,可以创建一个计算属性,来返回过滤或排序后得数组

    <li v-for="n in eventNumbers">{{}}</li>
    data: {
    	numbers: [1,2,3,4,5]
    },
    computed: {
    	eventNumbers: function(){
    		return this.numbers.filter(function(number){
    			return number % 2 === 0
    		})
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在计算属性不适用的情况下(例如,嵌套在v-for循环中),可以使用一个方法

    <ul v-for="set in sets">
    	<li v-for="n in even(set)">{{ n }}</li>
    </ul>
    data: {
    	sets: [[1,2,3,4,5],[6,7,8,9,10]]
    }
    methods: {
    	even: function(numbers){
    		return numbers.filter(function(number){
    			return number % 2 === 0
    		})
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    在v-for里使用值范围

    v-for也可以接受整数,在这种情况下,他会把模板重复对应次数

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

    在这里插入图片描述