Vue从入门到实战:内置指令

来自CloudWiki
跳转至: 导航搜索

v-show

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>v-show指令</title>
	</head>
	<body>
		<div id="app">
			<h1 v-show="yes">Yes!</h1>
			<h1 v-show="no">No!</h1>
			<h1 v-show="age >= 25">Age: {{ age }}</h1>
			<h1 v-show="name.indexOf('Smith') >= 0">Name: {{ name }}</h1>
		</div>
	
		<script src="vue.js"></script>
		<script>
			
			var vm = new Vue({
				el: '#app',
				data: {
					yes: true,
					no: false,
					age: 28,
					name: 'Will Smith'
				}
			})
		</script>
	</body>
</html>

v-show指令是通过CSS样式属性display来控制元素的显示与否。

如果要显示或隐藏多个元素怎么办呢 ? 我们可以使用HTML5 新增的<template>元素来包裹需要切换的显示与隐藏的多个元素,在<template>上使用v-show指令。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>v-show指令</title>
	</head>
	<body>
		<div id="app">
			<template v-show="!isLogin">
				<form>
					<p>username: <input type="text"></p>
					<p>password: <input type="password"></p>
				</form>
			</template>
		</div>
	
		<script src="vue.js"></script>
		<script>
			
			var vm = new Vue({
				el: '#app',
				data: {
					isLogin: false
				}
			})
		</script>
	</body>
</html>

v-if/v-else-if/v-else

v-if指令

v-if指令根据表达式的值的真假来生成或删除一个元素。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>v-if指令</title>
	</head>
	<body>
		<div id="app">
			<h1 v-if="yes">Yes!</h1>
			<h1 v-if="no">No!</h1>
			<h1 v-if="age >= 25">Age: {{ age }}</h1>
			<h1 v-if="name.indexOf('Smith') >= 0">Name: {{ name }}</h1>
		</div>
	
		<script src="vue.js"></script>
		<script>
			var vm = new Vue({
				el: '#app',
				data: {
					yes: true,
					no: false,
					age: 28,
					name: 'Will Smith'
				}
			})
		</script>
	</body>
</html>

v-if指令在HTML元素的显示与否的实现机制上与v-show指令不同,当表达式的值计算为false时,v-if指令不会创建该元素。

v-else-if/v-else

v-else-if 是在vue2.1.0版本中新增,与v-if一起使用,可以使用互斥的条件判断。

 
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<div id="app">
	    <span v-if="score >= 85">优秀</span>
	    <span v-else-if="score >= 75">良好</span>
	    <span v-else-if="score >= 60">及格</span>
	    <span v-else>不及格</div>
		</div>
	
		<script src="vue.js"></script>
		<script>
			var vm = new Vue({
				el: '#app',
			  data: {
			    score: 90
			  }
			})
		</script>
	</body>
</html>

当一个条件满足时,后续的条件都不会再判断。

用key管理可复用的元素

vue会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。例如在下面的代码中,vue为了提高渲染效率,复用了<input>元素。

但是如果我们不希望在E-mail输入框中看到之前输入的用户名,这可以通过为<input>元素添加一个具有唯一值的key属性。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>v-if-key</title>
	</head>
	<body>
		<div id="app">
	    <template v-if="loginType === 'username'">
			  <label>用户名:</label>
			  <input placeholder="请输入你的用户名" key="username-input">
			</template>
			<template v-else>
			  <label>Email:</label>
			  <input placeholder="请输入你的Email" key="email-input">
			</template>
			<p><button v-on:click="changeLoginType">切换登录方式</button></p>
		</div>
	
		<script src="vue.js"></script>
		<script>
			var vm = new Vue({
				el: '#app',
			  data: {
			    loginType: 'username'
			  },
			  methods: {
			  	changeLoginType(){
			  		if(this.loginType === 'username'){
			  			this.loginType = "email";
			  		}
			  		else{
			  			this.loginType = "username";
			  		}
			  	}
			  }
			})
		</script>
	</body>
</html>

v-for指令

v-for指令就是通过循环的方式来渲染一个列表,循环的对象可以是数组,也可以是一个Javascript对象。

v-for遍历数组

vue实例的数据对象定义了一个数组属性books,然后在
  • 元素上使用v-for指令遍历该数组。 这将循环渲染
  • 元素,在v-for块中,可以访问所有父作用域的属性。 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <ul> <li v-for="book in books">{{book.title}}</li> <!-- <li v-for="(book,index) in books">{{index}} - {{book.title}}</li> --> </ul> <div> <span v-for="n in 10">{{ n }} </span> </div> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { books: [ {title: 'Vue无难事'}, {title: 'VC++深入详解'}, {title: 'Servlet/JSP深入详解'} ] } }) </script> </body> </html> v-for指令还支持一个可选的参数作为当前项的索引: <li v-for="(book,index) in books">{{index}} - {{book.title}}</li>

    数组更新检测

    为了检测数组中元素的变化,以便及时将变化反映到视图中,Vue对数组的下列变异方法进行了包裹:

    • push()
    • pop()
    • shift()
    • unshift()
    • splice()
    • sort()
    • reverse()

    如:

    vm.books.push({title:'Java Web开发详解'})
    

    数组中还有一些非变异方法,如filter(),concat(),slice() ,他们不会改变原始数组:

    vm.books =vm.books.concat([{title:'Java Web开发详解'},{title: 'Java无难事'}])
    

    vue在检测到数组变化时,并不是直接重新渲染整个列表,而是最大化地复用DOM元素。替换的数组中,含有相同元素的项不会被重新渲染,因此可以大胆地使用新数组来替换旧数组,不用担心性能问题。

    为了解决部分方法的数组变动 vue检测不到的问题,可采用下列方法:

    //使用Vue的全局set()方法
    Vue.set(vm.books,0,{title: 'Java Web开发详解'})
    //使用数组原型的splice()方法
    vm.books.splice(0,1,{title: 'Java Web开发详解'})
    

    过滤与排序

    有时想显示一个数组经过过滤或排序后的版本,但不实际改变或重置原始数据。

    在这种情况下,可以创建一个计算属性,来返回经过过滤或排序后的数组



    <nowiki>
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<ul>
    					<li v-for="n in evenNumbers">{{ n }}</li> 
    			</ul>
    			
    
    		</div>
    	
    		<script src="vue.js"></script>
    		<script>
    			var vm = new Vue({
    				el: '#app',
    				data: {
    					numbers:[1,2,3,4,5]
    				},
    				computed:{
    					evenNumbers:function(){
    						return this.numbers.filter(function (number){
    							return number %2 ===0
    						})
    					}
    				}
    				
    			})
    		</script>
    	</body>
    </html></nowiki>
    

    v-for遍历整数

    v-for指令也可以接受整数。

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

    v-for遍历对象

    遍历对象的语法形式和遍历数组是一样的,即value in object

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<ul>
    				<li v-for="(value, key, index) in book">{{index}}. {{key}} : {{value}}</li>
    			</ul>
    		</div>
    	
    		<script src="vue.js"></script>
    		<script>
    			var vm = new Vue({
    				el: '#app',
    				data: {
    					book: {
    						title: 'VC++深入详解',
    						author: '孙鑫',
    						isbn: '9787121362217'
    					}
    				}
    			})
    		</script>
    	</body>
    </html>
    

    对象更新检测

    由于Javascripts的限制,Vue不能检测对象属性的添加和删除。要解决这个问题,可以使用Vue全局的set()和delete()方法来添加和删除属性,或是Vue实例的$set()和$delete()方法来添加和删除属性,并触发视图更新。

     
    Vue.set(vm.book,'publishDate','2019-06-01')
    vm.$set(vm.book,'publishDate','2019-06-01')
    			
    Vue.delete(vm.book,'isbn')
    vm.$delete(vm.book,'isbn')
    

    在<template>上使用v-for

    类似v-show和v-if,也可以利用带有v-for指令的<template>来渲染一段包含多个元素的内容。代码如下所示:

    <ul>
      <template v-for="item in items">
        <li>{{ item.msg }}</li>
        <li class="divider" role="presentation"></li>
      </template>
    </ul>
    

    key属性

    为了给Vue一个提示,以便它能够跟踪每个节点的身份,从而重用和重新排序现有元素,需要为列表中每一项提供一个唯一key属性。

    key属性的类型只能是string或者number类型。

    如下文中的v-bind:key="book.id"

     <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<p>
    				ID:<input type="text" v-model="bookId"/>
    				书名:<input type="text" v-model="title"/>
    				<button v-on:click="add()">添加</button>
    			</p>
    			<p v-for="book in books" v-bind:key="book.id">
    				<input type="checkbox">
    				<span>ID:{{book.id}} , 书名:{{book.title}}</span>
    			</p>
    		</div>
    	
    		<script src="vue.js"></script>
    		<script>
    			var vm = new Vue({
    				el: '#app',
    				data: {
    					bookId: '',
    					title: '',
    					books: [
    						{id: 1 ,title: 'Vue无难事'},
    						{id: 2, title: 'VC++深入详解'},
    						{id: 3, title: 'Servlet/JSP深入详解'}
    					]
    				},
    				methods:{
    					add(){
    					  this.books.unshift({
    					      id : this.bookId,
    					      title : this.title
    					  });
    					  this.bookId = '';
    					  this.title = '';
    					}
    				}
    			})
    		</script>
    	</body>
    </html>
    

    v-for与v-if一同使用

    如果渲染一个列表时,对列表中的某些项需要根据条件来判断是否渲染,那么就可以将v-if和v-for联合一起使用。

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<h1>已完成的工作计划</h1>
    			<ul>
    				<li v-for="plan in plans" v-if="plan.isComplete">
    					{{plan.content}}
    				</li>
    			</ul>
    			<h1>未完成的工作计划</h1>
    			<ul>
    				<li v-for="plan in plans" v-if="!plan.isComplete">
    					{{plan.content}}
    				</li>
    			</ul>
    		</div>
    	
    		<script src="vue.js"></script>
    		<script>
    			var vm = new Vue({
    				el: '#app',
    				data: {
    					plans: [
    						{content: '写《Vue无难事》', isComplete: false},
    						{content: '买菜', isComplete: true},
    						{content: '写PPT', isComplete: false},
    						{content: '做饭', isComplete: true},
    						{content: '打羽毛球', isComplete: false}
    					]
    				}
    			})
    		</script>
    	</body>
    </html>
    

    v-bind

    v-bind指令主要用于响应更新HTML元素的属性,将一个或多个属性或者一个组件的prop动态绑定到表达式。

    
    	<nowiki>	<div id="app">
    			<!-- 绑定一个属性 -->
    			<img v-bind:src="imgSrc">
    			
    			<!-- 缩写 -->
    			<img :src="imgSrc">
    			
    			<!-- 动态属性名 (2.6.0+) -->
    			<a v-bind:[attrname]="url">链接</a>
    			
    			<!-- 内联字符串拼接 -->
    			<img :src="'images/' + fileName">
    			
    			<!-- 绑定一个有属性的对象 -->
    			<form v-bind="formObj">
    				<input type="text">
    			</form>
    		</div>
    
     
      <nowiki>
     var vm = new Vue({
    				el: '#app',
    				data: {
    					attrname: 'href',
    					url: 'https://www.phei.com.cn/',
    					imgSrc: 'images/bg.jpg',
    					fileName: 'bg.jpg',
    					formObj: {
    						method: 'get',
    						action: '#'
    					}
    				}
    			})
    

    </nowiki>

    v-bind指令还可以直接绑定一个有属性的对象,代码如下所示:

      <!-- 绑定一个有属性的对象 -->
    			<form v-bind="formObj">
    				<input type="text">
    			</form>
    
    
    <nowiki>var vm = new Vue({
    				el: '#app',
    				data: {
    					
    					formObj: {
    						method: 'get',
    						action: '#'
    					}
    				}
    			})
    

    </nowiki>

    v-model

    v-model指令用来在表单<input>、<textarea>及<select>元素上创建双向数据绑定,

    它会根据控件类型自动选取正确的方法来更新元素。

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<input type="text" v-model="message">
    		</div>
    	
    		<script src="vue.js"></script>
    		<script>
    			var vm = new Vue({
    				el: '#app',
    				data: {
    					message: 'Hello World'
    				}
    			})
    		</script>
    	</body>
    </html>
    

    在浏览器Console窗口输入,并回车:

    vm.message="welcome"
    
    

    这时输入框中的文字也变为welcome

    在输入框中输入hello world,

    这时在浏览器Console窗口输入vm.message,并回车

    也显示:


    "hello world"
    

    这就是所谓的创建双向数据绑定。

    v-on

    v-on指令用于监听DOM事件,并在触发时运行一些Javascript代码

    <nowiki><!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<p>
    				<!--(1)click事件直接使用JavaScript语句-->
    				<button v-on:click="count += 1">Add 1</button>
    				<span>count: {{count}}</span>
    			</p>
    			<p>
    				<!--(2)click事件直接绑定一个方法-->
    				<button v-on:click="greet">Greet</button>
    				<!--缩写语法-->
    				<button @click="greet">Greet</button>
    			</p>
    			<p>
    				<!--(3)click事件使用内联语句调用方法-->
    				<button v-on:click.once="say('Hi')">Hi</button>
    			</p>
    			<a href="/login" v-on:click.prevent="login">登录</a>
    		</div>
    
    		<script src="vue.js"></script>
    		<script>
    			var vm = new Vue({
    				el: '#app',
    				data: {
    					count: 0,
    					message: 'Hello, Vue.js!'
    				},
    				// 在选项对象的methods属性对象中定义方法
    				methods: {
    					greet: function() {
    						// 方法内this指向vm
    						alert(this.message)
    					},
    					// 对象方法的简写语法
    					say(msg) {
    						alert(msg)
    					},
    					login(event){
    						// ...
    						
    						//event.preventDefault();
    					}
    				}
    			})
    		</script>
    	</body>
    </html>
    

    </nowiki>

    说明:

    • 方法是在选项对象的method属性中定义的,该属性是一个对象属性,在method属性中定义的方法,可以直接通过Vue实例来访问。
    • 一定不要使用箭头函数来定义method方法。
    • 当Vue实例销毁时,所有的事件处理器都会被自动删除,所以无须担心如何清理他们。
    • 在使用v-on指令绑定事件处理器时,就可以使用$event传入原始的DOM事件对象,然后在事件处理器方法中访问原生的事件对象
    <a href="/login" v-on:click="login($event)">登录</a>
    
    //...
    // 在选项对象的methods属性对象中定义方法
    				methods: {
    					
    					login(event){
    						// ...
    						
    						event.preventDefault();
    					}
    				}
    

    事件修饰符

    在事件处理程序中调用event.preventDefault()是非常常见的需求,为了解决这个问题,Vue.js提供了事件修饰符,让我们可以专注于纯粹的数据逻辑,而不需要考虑如何处理DOM事件细节。

    Vue提供了如下修饰符:

    为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。

    • stop
    • prevent
    • capture
    • self
    • once
    • passive
    <nowiki><nowiki><nowiki><!-- 阻止单击事件继续传播 -->
    <a v-on:click.stop="doThis"></a>
    
    <!-- 提交事件不再重载页面 -->
    <form v-on:submit.prevent="onSubmit"></form>
    
    <!-- 修饰符可以串联 -->
    <a v-on:click.stop.prevent="doThat"></a>
    
    <!-- 只有修饰符 -->
    <form v-on:submit.prevent></form>
    
    <!-- 添加事件监听器时使用事件捕获模式 -->
    <!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
    <div v-on:click.capture="doThis">...</div>
    
    <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
    <!-- 即事件不是从内部元素触发的 -->
    <div v-on:click.self="doThat">...</div></nowiki></nowiki>
    

    </nowiki>

    针对前面调用event.preventDefault()方法来阻止默认的链接跳转行为的需求,使用事件修饰符就可以轻松实现相同的功能。

     <a href="/login" v-on:click.prevent="login">登录</a>
    
    //...
    // 在选项对象的methods属性对象中定义方法
    				methods: {
    					
    					login(event){
    						// ...					
    						
    					}
    				}
    

    按键修饰符

    在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

    <!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
    <input v-on:keyup.enter="submit">
    <!-- 使用回车键的按键码 -->
    <input v-on:keyup.13="submit">
    
    

    为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:

    • .enter
    • .tab
    • .delete (捕获“删除”和“退格”键)
    • .esc
    • .space
    • .up
    • .down
    • .left
    • .right

    要想在同时按下Ctrl+某个键时触发keyup.ctrl ,那么需要用Ctrl的虚拟机代码17来代替Ctrl修饰键

    <input @keyup.17.67="doSomething">
    

    .exact修饰符

    .exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。

    <!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
    <button v-on:click.ctrl="onClick">A</button>
    
    <!-- 有且只有 Ctrl 被按下的时候才触发 -->
    <button v-on:click.ctrl.exact="onCtrlClick">A</button>
    
    <!-- 没有任何系统修饰符被按下的时候才触发 -->
    <button v-on:click.exact="onClick">A</button>
    

    鼠标按钮修饰符

    • .left
    • .right
    • .middle

    这些修饰符会限制处理函数仅响应特定的鼠标按钮。

    v-text

    v-text元素用于更新元素的文本内容

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="gbk">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<span v-text="message"></span>
    		
    			<!-- 等价于
    			<span v-text>{{message}}</span>
    			-->
    		</div>
    	
    		<script src="vue.js"></script>
    		<script>
    			var vm = new Vue({
    				el: '#app',
    				data: {
    					message: 'Hello Vue.js'
    				}
    			})
    		</script>
    	</body>
    </html>
    

    如果只是更新部分文本内容,那么还是用{{Mustache}}插值形式。

    v-html

    v-html指令用于更新元素的innerHTML,该部分内容作为普通的HTML代码插入,不会作为Vue模板进行编译。


    		<div id="app">
    			<div v-html="hElt"></div>
    		</div>
    
     
    var vm = new Vue({
    				el: '#app',
    				data: {
    					hElt: "<h1>《Vue.js无难事》</h1>"
    				}
    			})
    

    在网站上动态渲染任意的HTML是非常危险的,因为很容易导致XSS攻击。

    切记,只在可信的内容上使用v-html,永远不要在用户提交的内容上使用v-html.

    v-once

    v-once指令可以让元素或组件只渲染一次。之后再次渲染是,元素/组件及其所有的子节点被视为静态内容并跳过。

     <nowiki><!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title></title>
    		<style>
    			a {
    				margin: 20px;
    			}
    		</style>
    	</head>
    	<body>
    		<div id="app">
    			<h1>{{title}}</h1>
    			<a v-for="nav in navs" href="nav.url" v-once>{{nav.name}}</a>
    		</div>
    	
    		<script src="vue.js"></script>
    		<script>
    			var vm = new Vue({
    				el: '#app',
    				data: {
    					title: 'v-once指令的用法',
    					navs: [
    						{name: '首页', url: '/home'},
    						{name: '新闻', url: '/news'},
    						{name: '视频', url: '/video'},
    					]
    				}
    			})
    		</script>
    	</body>
    </html>
    

    </nowiki>

    v-pre

    v-pre指令也不需要表达式,用于跳过这个元素和它的子元素的编译过程。

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<h1 v-pre>{{message}}</h1>
    		</div>
    	
    		<script src="vue.js"></script>
    		<script>
    			var vm = new Vue({
    				el: '#app',
    				data: {
    					message: 'Vue.js无难事',
    				}
    			})
    		</script>
    	</body>
    </html>
    

    v-cloak

    v-cloak指令可以隐藏未编译的Mustache标签直到实例准备完毕。

    <nowiki> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style> [v-cloak] { display: none; } </style> </head> <body> <div id="app"> <h1 v-cloak>{{message}}</h1> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { message: 'Vue.js无难事', } }) </script> </body> </html></nowiki>