title: Vue基础篇(二)
tags:
  - Vue
categories:
  - 前端
top_img: false
cover: '/upload/cdn0files/20200724163921.jpg'
abbrlink: 70eafe5c
date: 2020-07-23 14:02:13
updated: 2020-07-23 15:02:13

模板语法

插值表达式

利用插值表达式来输出信息:

<div id="app">
    <h1>
        {{msg}}
    </h1>
</div>

<script type="text/javascript">
	var app = new Vue({
		el:"#app",
		data:{
			msg:"hello Vue",
		},
	})
</script>

v-once 属性:

<h1 v-once>{{msg}}</h1>

v-once 是只渲染生成一次,此时如果在控制台更改 app.msg 的值则它并不会改变

插值表达式还支持简单运算:

字符串拼接:

<h1>{{firstname + lastname}}</h1>

运算:

<h1>{{1 + 2}}</h1>

输出结果就是 3 而不是 1 + 2

还支持三元运算:

<div>{{isVip?"VIP用户":"普通用户"}}</div>

isViptrue 则显示 VIP用户,反之则显示 普通用户

v-html

v-html 也可以用来输出信息,但是这么做并不推荐,因为不是怎么安全,可能会引发 XSS 问题。

<div id="app">
    <div>{{htmlTxt}}</div>
	<div v-html="htmlTxt"></div>
</div>

<script type="text/javascript">
	var app = new Vue({
		el:"#app",
		data:{
			htmlTxt:"<h1>hello</h1>"
		},
	})
</script>

v-bind 属性绑定

v-bind 是动态属性绑定,可以简写为一个冒号 :

<div id="app">
    <div v-bind:id="idName"></div>
    <div :id="idName"></div>
</div>

<script type="text/javascript">
	var app = new Vue({
		el:"#app",
		data:{
			idName: "test"
		},
	})
</script>

这样就可以对属性就行修改。

v-on 事件绑定

v-on 是事件绑定,可以绑定监听事件,也可简写为 @

<div id="app">
	<button type="button" v-on:click="changeBg">改变背景</button>
	<button type="button" @click="changeBg">改变背景</button>
</div>

<script type="text/javascript">
	var app = new Vue({
		el:"#app",
		methods: {
            changeBg () {
                document.body.style.background = "skyblue";
            }
        }
	})
</script>

举个小例子,按钮每被点击一次,显示的数字就 +1 :

<div id="app">
	<h1>点击次数:{{count}}</h1>
	<button type="button" @click="count+=1">点击</button>
	<button type="button" @click="clickEvent">点击</button>
</div>

<script type="text/javascript">
	var app = new Vue({
		el:"#app",
		data:{
			count: 0
		},
		methods:{
			clickEvent () {
				this.count++;
			}
		}
	})
</script>

属性内可以使用简单表达式,所有两个按钮都可以修改 count 的数据

v-model 输入绑定

<div id="app">
	<input type="text" v-model="userName" />
	<input type="text" @input="userName = $event.target.value" :value="userName" />
    
	<h3>输入的内容: {{userName}}</h3>
</div>

<script type="text/javascript">
	var app = new Vue({
		el:"#app",
		data:{
			userName:"",
		},
	})
</script>

这两种方法都可以获取到输入框内的值,只不过被简化成了 v-model 指令了。

v-if 判断

例如:

<div id="app">
    <img src="" v-if="isShow" />
</div>

<script type="text/javascript">
	var app = new Vue({
		el:"#app",
		data:{
			isShow: true
		},
	})
</script>

如果把 isShow 的值修改为 false 那么图片就不会显示。

v-for 列表渲染

循环渲染一个列表

<div id="app">
	<ul>
		<li v-for="item in stars">
			{{item}}
		</li>
	</ul>
</div>

<script type="text/javascript">
var app = new Vue({
	el: "#app",
	data: {
		stars: ["蔡徐坤", "范冰冰", "李晨", "苏有朋"]
	}
})
</script>

这就是一个简单的循环列表,但是这么做是不合理的,Vue 的建议是给列表的每一项加上独一无二的 key 值,循环对象数组:

<div id="app">
	<ul>
		<li v-for="(item,index) in students" :key="index">
			<h4>学生姓名:{{item.name}}</h4>
			<p>年龄:{{item.age}}------学校:{{item.school}}</p>
		</li>
	</ul>
</div>

<script type="text/javascript">
var app = new Vue({
	el: "#app",
	data: {
		students: [{
			name: "小明",
			age: 18,
			school: "北大",
			touxiang: "http://pic1.zhimg.com/50/v2-deff985cfcb7690bc71fdf8676438146_hd.jpg"
		}, {
			name: "小红",
			age: 17,
			school: "清华"
		}, {
			name: "小白",
			age: 20,
			school: "北大"
		}]
	}
})
</script>

还是上面那个对象数组,进行循环对象:

<ul>
	<li v-for="(item,index) in students[0]" :key="index">{{item}}</li>
</ul>

条件循环渲染:

<ul>
	<li v-for="(item,index) in students" v-if="item.age%2==0" :key="index">
		<h4>索引值:{{index}}------学生姓名:{{item.name}}</h4>
		<p>年龄:{{item.age}}------学校:{{item.school}}</p>
	</li>
</ul>

这里是先循环再进行判断,即使把 v-if 写在前面也是先循环再判断

常用的指令就这几个,更多和详细指令请参考官方文档:Vue 官方文档

侦听属性

示例:

<div id="app">
	{{msg}}
	<ul>
		<li v-for="(item,index) in arr" :key="index">{{item}}</li>
	</ul>
</div>
		
<script type="text/javascript">
var app = new Vue({
	el:"#app",
	data:{
		msg:"hello Vue",
		arr:["小红","小黑","小白"]	
	},
	watch:{
		msg (val) {
			console.log("监听事件被触发---msg");
			console.log(val);
		},
		arr (val) {
			console.log("监听事件---arr");
			console.log(val);
			this.msg="监听到用户数据被修改"
		}
	}
})
</script>

arr 这个数组的值被修改时,比如增加一条数据时,监听事件 arr 被触发,然后这个事件修改了 this.msg 的值,然后也就触发了监听事件 msg

控制台输出

计算属性

<div id="app">
	<h1>{{firstname+lastname}}</h1>
	<h1>{{fullname}}</h1>

	<!-- 逆序显示一个单词 -->
	<h1>{{ word.split("").reverse().join("") }}</h1>
	<!-- 性能优化。和上面那个例子类似 -->
	<h1>{{reverseWord}}</h1>

	<!-- 循环性能优化 -->
	<ul>
		<li v-for="(item,index) in oddStudents" :key="index">
			<h2>{{item.name}}</h2>
			<h2>{{item.age}}---{{item.school}}</h2>
		</li>
	</ul>
			
	<!-- set和get属性 -->
	<h1>{{msg}}</h1>
	<h1>{{reverseMsg}}</h1>
</div>
		
<script type="text/javascript">
var app = new Vue({
	el:"#app",
	data:{
		firstname:"张",
		lastname:"三",
		word:"music",
		students: [{
			name: "小明",
			age: 18,
			school: "北大"
		}, {
			name: "小红",
			age: 17,
			school: "清华"
		}],
		msg:"hello Vue"
	},
	computed:{
		fullname () {
			// 会将计算结果进行缓存
			return this.firstname+this.lastname;
		},
		reverseWord () {
			return this.word.split("").reverse().join("");
		},
		oddStudents () {
			let results = this.students.filter((item,i)=>{
				return item.age%2==0
			});
			return results;
		},
		reverseMsg:{
			get () {
				return this.msg.split("").reverse().join("");
			},
			set (val) {
				console.log(val);
				this.msg = val.split("").reverse().join("");
			},
			// get只能取值然后作用在其他地方,但是set可以设置值本身
		}
	},
})
</script>

那么在例子中 {{firstname+lastname}}{{fullname}} 有什么区别呢,因为在计算属性中,只要计算一次,就会将计算结果进行缓存,所以当这个数据需要大量显示的时候,我们可以使用计算属性来提高性能,就不用每显示一次就要进行计算一次。

循环优化的原理:在前面的例子中我们有一个条件循环偶数年龄的学生,我们先进行计算得出偶数学生的数组,就不用循环之后再进行判断,直接把偶数的对象先计算出来再使用,只循环需要的,而且它最大的优点就是可以先把计算结果先缓存下来,只要内容不改变他就可以直接拿来用,从而提高性能

事件传参

<div id="app">
	<ul>
		<li v-for="(item,index) in stars" @click="clickEvent(index,item,$event)" :key="index">索引值:{{index}}------内容:{{item}}</li>
	</ul>
</div>

<script type="text/javascript">
var app = new Vue({
	el:"#app",
	data:{
		stars: ["蔡徐坤", "范冰冰", "李晨", "苏有朋"],
	},
	methods:{
		clickEvent (index,value,$event) {
			console.log(index);
			console.log(value);
			console.log(event);
		}
	},
})
</script>

既能传入事件对象也能传入参数

输出

事件修饰符

<div @click="one">
	<button type="button" @click.stop="two">点击</button>
</div>

事件修饰符 .stop 用来阻止冒泡事件,如果没有加修饰符的话,当点击事件 two 被触发时,事件 one 也会被触发,加上修饰符之后就不会了

<form method="post">
	<input type="submit" value="提交1"/>
	<input @click.prevent="" type="submit" value="提交2"/>
</form>

默认情况下点击 提交1 会有一个 POST 请求被提交,通过 .pervent 修饰符阻止默认行为

<button type="button" @click.once="">只触发一次点击</button>

.once 修饰符是只触发一次,第二次点击就没有效果了

<input type="text" @keydown.enter="search" value="回车" />

keydown 是按键绑定,监听键盘按键的动作

<input type="text" @keydown.enter.f1="search" value="回车和F1" />

同时绑定两个按键

<button type="button" @click.ctrl="ctrlEvent">按住Ctrl事件</button>

按住 Ctrl 键再点击按钮才会触发事件,但是如果按住 Ctrl 和其他键也会触发,就需要精确的只识别 Ctrl 键:

<button type="button" @click.ctrl.exact="ctrlEvent">按住Ctrl事件</button>
<script type="text/javascript">
Vue.config.keyCodes.f1 = 112
var app = new Vue({
	el:"#app",
	data:{
					
	},
})
</script>

自定义按键修饰符

Class 与 Style 样式绑定

<style type="text/css">
	.active {
		background: skyblue;
	}
	.page {
		height: 200px;
		width: 200px;
	}
</style>

<div id="app">
	<div class="page" :class="{active:isTrue}"></div>
	<!-- 通过对象的方式决定是否存在某个类 -->
    
	<!-- 还可以直接放置对象: -->
	<div class="page" :class="styleObj"></div>

	<!-- 还可以直接放置数组 -->
	<div class="page" :class="styleArr"></div>

	<!-- 还可以放置字符串 -->
	<div class="page" :class="styleStr"></div>

	<!-- 数组和对象混合使用 -->
	<div class="page" :class="styleArrObj"></div>
</div>

<script type="text/javascript">
var app = new Vue({
	el: "#app",
	data: {
		isTrue:true,
		styleObj:{active:true,test:true,"col-g-6":true},//可以写多个
		styleArr:["col-xs-12","red-bg"],
		styleStr:"abc cde efj",
		styleArrObj:["abc",{active:true}]
	}
})
</script>

内联样式

<div id="app">
	<!-- CSS内联样式变量拼接 -->
	<div style="width: 100px;height: 100px;background-color: skyblue;" 
				:style="{border: borderWidth+'px solid red',padding:paddingWidth+'px'}"></div>
			
	<!-- CSS内联样式放置对象 -->
	<div :style="styleObj"></div>
			
	<!-- CSS数组的方式拼接 -->
	<div :style="styleSrr"></div>
</div>

<script type="text/javascript">
var app = new Vue({
	el:"#app",
	data:{
		borderWidth:10,
		paddingWidth:30,
		styleObj:{
			width:"200px",
			height:"300px",
			"background-color":"skyblue"
		},
		styleSrr:[
			{
				width:"200px",
				height:"300px",
				"background-color":"skyblue"
			},{
				border:"5px solid yellow"
			}
		]
	}
})
</script>

动态组件

<div id="app">
	<div>
		<component :is="com"></component>
	</div>
			
	<button @click="chooseContent(1)">首页</button>
	<button @click="chooseContent(2)">列表</button>
	<button @click="chooseContent(3)">新闻</button>
	<button @click="chooseContent(4)">个人</button>
</div>

<script type="text/javascript">
// 创建组件
let com1 = Vue.component('index-com',{
	name:'index',	// 可以给组件定义名字,在is的值上使用
	template:`<h1>首页内容</h1>`
})
let com2 = Vue.component('list-com',{
	template:`<h1>列表内容</h1>`
})
let com3 = Vue.component('new-com',{
	template:`<h1>新闻内容</h1>`
})
let com4 = Vue.component('me-com',{
	template:`<h1>个人内容</h1>`
})
			
var app = new Vue({
	el:"#app",
	data:{
		com:com1,
	},
	methods:{
		chooseContent (id) {		// 通过获取id来选择注册的组件
			this.com = this.$options.components['com'+id]
		}
	},
	// 注册组件
	components:{
		com1,com2,com3,com4
	}
})
</script>

组件传值

<div id="app">
	<ul>
	<!-- 从父组件传值到子组件 -->
		<product-com @choosproduct="chooseEvent" v-for="(item,index) in proList" :product="item" :key="'product'+index"></product-com>
	</ul>
	<h1>选择的产品是:{{chooseProduct}}</h1>
</div>

<script type="text/javascript">
// 产品组件
Vue.component("product-com",{
	props:['product'],	// 告知传入的数据从根组件过来
	template:`<li>
		<h3>产品名称:{{product.title}}</h3>
		<h4>产品描述:{{product.brief}}</h4>
		<p>产品价格:{{product.price}}</p>
		<button @click="chooseEvent(product)">选择</button>
		</li>`,
	data () {
		return {
						
		}
	},
	methods:{
	// 子组件向父组件传值必须有一个触发事件
		chooseEvent (product) {
			this.$emit("choosproduct",product)
		}
	}
})
			
// 根组件
var app = new Vue({
	el:"#app",
	data:{
		proList:[
			{
				title:"产品1",
				price:"10",
				brief:"描述1"
			},{
				title:"产品2",
				price:"20",
				brief:"描述2"
			}
		],
		chooseProduct:""
	},
	methods:{
		chooseEvent (data) {
			this.chooseProduct = data.title;
		}
	}
})
</script>

生命周期

<div id="app">
	<h1>{{msg}}</h1>
	<div :class="className"></div>
	<hello-com v-if="isShow"></hello-com>
	<hello-com v-show="isShow"></hello-com>
</div>

<script type="text/javascript">
let helloCom = Vue.component("hello-com", {
	template: "<div><h1>{{hello}}</h1> <button @click='changeData'>修改数据</button> </div>",
	data: function() {
		return {
			hello: 'helloWorld'
		}
	},
	methods:{
		changeData () {
			this.hello = "helloXiaoMing"
		}
	},
	beforeCreate () {
		console.log('brforeCreate')
		// 此时数据data和事件方法methods还未绑定到app对象上
	},
	created() {
		console.log('create')
		// 数据和方法绑定到应用对象上
	},
	beforeMount() {
		// 渲染之前,根据数据生成的DOM对象是获取不到的
		console.log('brforeMount')
	},
	mounted() {
		// 渲染之后,可以获取到生成的DOM对象
		console.log('mounted')
	},
	beforeUpdate() {
		console.log('beforeUpdate')
		// 数据更改,但内容未更改之前
	},
	updated() {
		console.log('update')
		// 内容已经更新完毕
	},
	beforeDestroy() {
		console.log('beforeDestory')
		// 应用销毁之前
	},
	destroyed() {
		console.log('destory')
		// 应用销毁之后
	},
})
			
var app = new Vue({
	el: "#app",
	data: {
		msg: "helloVue",
		className: "redBg",
		isShow:true
	},
	components:{
		'hello-com':helloCom
	},
	beforeCreate() {
		console.log('brforeCreate')
		// 此时数据data和事件方法methods还未绑定到app对象上
		console.log(this)
		console.log(this.msg)
	},
	created() {
		console.log('create')
		// 数据和方法绑定到应用对象上
		console.log(this)
		console.log(this.msg)
	},
	beforeMount() {
		// 渲染之前,根据数据生成的DOM对象是获取不到的
		console.log('brforeMount')
		let dom = document.querySelector("redBg")
		console.log(dom)
	},
	mounted() {
		// 渲染之后,可以获取到生成的DOM对象
		console.log('mounted')
		let dom = document.querySelector("redBg")
		console.log(dom)
	},
	beforeUpdate() {
		console.log('beforeUpdate')
		// 数据更改,但内容未更改之前
	},
	updated() {
		console.log('update')
		// 内容已经更新完毕
	},
	beforeDestroy() {
		console.log('beforeDestory')
		// 应用销毁之前
	},
	destroyed() {
		console.log('destory')
		// 应用销毁之后
	},
	methods: {
		clickEvent () {

		},
		isShow () {
			this.isShow = !this.isShow
		}
	}
})
</script>

就先到这里,,,