Web前端开发之VUE03——vue插值表达式、MVVM设计模式、基础指令

目录

vue插值表达式:

MVVM设计模式:

v-bind:

v-on:

 v-on中事件对象的传递: 

 v-on修饰符:

v-model:

v-model修饰符:

 v-text和v-html:

v-show和v-if:

 v-for:

 vue中js导入图片:

v-for的更新检测:

v-for数组改变时的更新过程:

 虚拟DOM:

 diff算法:

 key作用:

动态class:

 动态style:

商品的案例:

过滤器:

计算属性computed:

计算属性-缓存:

 计算属性的完整写法:


vue插值表达式:

MVVM设计模式:

VUE的设计模式,可以实现双向绑定,同时对view和model的变化进行同时改变。

v-bind:

 

v-on:

 

 v-on中事件对象的传递: 

 v-on修饰符:

 

 详细修饰符见:详细修饰符https://cn.vuejs.org/v2/guide/events.html

v-model:

进行表单的value属性和我们变量互相绑定到一起。

 示例代码:

<template>
	<form action="" @keydown.enter.prevent>
		<label for="name">username:</label>
		<input type="text" id="name" v-model="username" @keydown.enter="printLog">
		<label for="passwd">password:</label>
		<input type="password" id="passwd" v-model="password" @keydown.enter="printLog">
	</form>

</template>

<script>
export default {
	data() {
		return {
			username: '',
			password: '',
			testVal:''
		}
	},
	methods:{
		printLog(){
			console.log(this.testVal)
		}
	}
}
</script>

<style>

</style>

<!--当我们绑定复选框这一类标签,一定要使用v-model绑定到所有的复选框-->
<!--并且双向绑定的变量一定要使用数组做初始化,以储存我们选中的复选框value值-->
<!--另外如果使用非数组变量,会存储复选框的checked属性,即true-->

v-model修饰符:

 v-text和v-html:

 示例:

<template>
	<div>
		<div v-text="text1"></div>
		<div v-html="html1"></div>
		<div v-text="text1"></div>
	</div>
</template>

<script>
export default {
	data() {
		return {
			text1:'<h1>1234</h1>',
			html1:'<h1>1234</h1>',
			// textTemp:'我会被覆盖'
		}
	}
}
</script>

<style>

</style>

v-text或v-html会覆盖插值表达式。

v-show和v-if:

 v-for:

v-for的示例代码:

<template>
	<div class="box">
		<ul>
			<!--需要值和索引时的遍历方法-->
			<li v-for="(item,index) in arr">
				{{ index }}-name:{{ item.name }}-age:{{ item.age }}
			</li>
			<!--不需要索引值时的遍历方法-->
			<li v-for="item in arr" :key="item.name">
		<span>
			name:{{ item.name }}
		</span>
				<span>
			age:{{ item.age }}
		</span>
			</li>
			<!--循环数组中的对象-->
			<li v-for="item in arr">
				<div v-for="(val,key) in item">
					<span>{{ key }}:</span><span>{{ val }}</span>
				</div>
			</li>
			<!--遍历数字-->
			<li v-for="num in nums">当前:{{num}}</li>
		</ul>
	</div>
</template>

<script>
export default {
	data() {
		return {
			arr: [{name: 'XiXi', age: 22}, {name: 'ZhuZhu', age: 18}, {name: 'LanLan', age: 38}, {name: 'ShuShu', age: 28}],
			nums:5
		}
	},
	methods: {}
}
</script>

<style>
ul {
	margin: 0;
	padding: 0;
}

li {
	list-style: none;
}
</style>

 vue中js导入图片:

vue项目中导入本地图片,在html和css中都是和原来一样的,而js不一样,需要将图片当作模块引入,因其是webpack支持的,会将路径当作模块。下面是一段示例代码。

<template>
	<img :src="url">
	<img :src="url2" alt="error">
	<img src="./assets/1.jpg" alt="">
	<img src="" alt="" class="testBGI">
</template>

<script>
//JS中我们无法直接使用路径,由于是Webpack在底层支持我们,导致我们的路径不能按正常路径指向
//由于JS中我们默认路径为模块,所以我们直接将图片当作模块导入就好了
import img from '@/assets/1.jpg'

export default {
	data(){
		return {
			url:"https://img-blog.csdnimg.cn/a79c372160be45909aed3a2cd5a8ba79.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA4oaQ5L2g5oya54ix55qE5by65ZOl4oaS,size_20,color_FFFFFF,t_70,g_se,x_16",
			url2:img
		}
	}
}
</script>

<style>
img{
	width: 200px;
	height: 200px;
}
.testBGI{
	background-image: url("./assets/1.jpg");
	background-position: center;
	background-size: contain;
}
</style>

v-for的更新检测:

<template>
<div v-for="item in arr">{{item}}</div>
	<button @click="revBtn">reverseArr</button>
	<button @click="getBtn">get top 3</button>
	<button @click="changeBtn">change one of them</button>
	<button @click="sortBtn">sort</button>
</template>

<script>

export default {
	data(){
		return {
			arr:[1,3,5,2,7],
		}
	},
	methods:{
		revBtn(){
			//reverse改变原数组,所以变化
			this.arr.reverse()
		},
		getBtn(){
			//slice方法并不会修改原数组,所以不会变化
			this.arr.slice(0,3)
		},
		changeBtn(){
			//因改变某元素的值,所以变化
			this.arr[1]=11
		},
		sortBtn(){
			//因改变原数组,所以变化
			this.arr.sort().reverse()
		}
	}
}
</script>

<style>

</style>

v-for数组改变时的更新过程:

 虚拟DOM:

 

 diff算法:

 

 key作用:

首先看看下面的代码:

<template>
	<div>
		<ul>
<!--			无key属性的添加-->
			<li v-for="(item,index) in arr" :key="index">
				{{item}}: <input type="text" name="" id="" v-model.lazy.number="value[index]">
			</li>
		</ul>
		<button @click.stop="addElem">添加</button>
	</div>
</template>

<script>
export default{
	data(){
		return{
			arr:['first','second','third'],
			value:[1,2,3,4]
		}
	},
	methods:{
		addElem(){
			this.arr.splice(0,0,'zero')
		}
	}
}
</script>

<style>

</style>

 key值用索引和不用是一样的结果,所以当我们使用key来辨别更新后的元素时,元素的值还是会错乱。下面我们来看看如何解决这一问题。

<template>
	<div>
		<ul>
<!--			key属性的添加-->
			<li v-for="(item,index) in arr" :key="index">
				{{item}}: <input type="text" name="" id="" v-model.lazy.number="value[index]">
			</li>
		</ul>
		<button @click.stop="addElem">添加</button>
<!--		key属性使用字符串绑定,并不完美,当item值相同依旧会出现问题-->
		<ul>
			<li v-for="item in arr2" :key="item">
				{{item}}: <input type="text" name="" id="">
			</li>
		</ul>
		<button @click.stop="addElem2">添加</button>
<!--		下面我们使用id的方法来解决这一问题-->
		<ul>
			<li v-for="item in arr3" :key="item.id">
				{{item.name}}: <input type="text" name="" id="">
			</li>
		</ul>
		<button @click.stop="addElem3">添加</button>
	</div>
</template>

<script>
let objArr=[]
for (let i = 0; i < 10; i++) {
	let obj={}
	obj.id=i+1
	obj.name="text"+(i+1)
	objArr.push(obj)
}
export default{
	data(){
		return{
			arr:['first','second','third'],
			arr2:['first','second','third'],
			arr3:objArr,
			value:[1,2,3,4]
		}
	},
	methods:{
		addElem(){
			this.arr.splice(0,0,'zero')
		},
		addElem2(){
			this.arr2.splice(0,0,'zero')
		},
		addElem3(){
			this.arr3.push({name:"text"+(objArr.length+1),id:objArr.length+1})
		}
	}
}
</script>

<style>

</style>

 使用id的中间过程如下: 

动态class:

 动态style:

 根据class和style的动态方法,给出示例代码:

<template>
<div>
	<span :class="{changeStyle:isTake}">我是动态的class</span>
	<button @click.stop="changeColor">changeColor</button>
	<br>
	<span :style="{backgroundColor:color}">我是动态style样式</span>
	<button @click.stop="changeStyleColor">randChangeColor</button>
</div>
</template>

<script>
import {getRandInt} from "./assets/JS/MyTools"
export default {
	data(){
		return{
			isTake:true,
			color:'blue'
		}
	},
	methods:{
		changeColor(){
			this.isTake=!this.isTake
		},
		changeStyleColor(){
			this.color=`rgba(${getRandInt(0,255)},${getRandInt(0,255)},${getRandInt(0,255)})`
		}
	}
}
</script>

<style>
.changeStyle{
	color:cadetblue;
}
</style>

通过上面所学我们做一个

商品的案例:

<template>
	<div :class="{'myTable':true}">
		<table :class="{'table':true,'table-hover':hoverStyle}">
			<thead>
			<tr>
				<th v-for="item in tableHeadTitle">{{item}}</th>
			</tr>
			</thead>
			<tbody>
				<tr v-for="item in objArr" :key="item.id">
					<td v-for=" val in item">{{val}}</td>
					<td><a href="#" @click.prevent="deleteLine(item.id)">delete</a></td>
				</tr>
			</tbody>
		</table>
		<div class="addPart">
			<input type="text" name="" id="" placeholder="资产名称" v-model.lazy.trim="prodName">
			<input type="text" placeholder="0" v-model.lazy.number="prodPrice">
			<button @click.stop="addProduct" class="btn btn-success btn-sm">add production</button>
		</div>
	</div>
</template>

<script>
import 'bootstrap/dist/css/bootstrap.min.css'
import {slightCopy} from "@/assets/JS/MyTools";
let objArr=[
	{
		id:100,
		name:'外套',
		price:299,
		initTime:new Date()
	},{
		id:101,
		name:'鞋子',
		price:199,
		initTime:new Date()
	},{
		id:102,
		name:'手机',
		price:3450,
		initTime:new Date()
	},{
		id:103,
		name:'雨伞',
		price:38,
		initTime:new Date()
	}
]
export default {
	data(){
		return{
			tableHeadTitle:['ProdID','ProdName','Price','InitialTime','Func'],
			objArr:objArr,
			hoverStyle:true,
			prodName:"",
			prodPrice:0,

		}
	},
	methods:{
		deleteLine(getID){
			let getIndex=this.objArr.findIndex(function (ele) {

				return ele.id===getID
			})
			this.objArr.splice(getIndex,1)
		},
		addProduct(){
			if (this.prodName===''||this.prodPrice===''){
				alert('please write in something')
				return false
			}else{
				let flag=true
				for (const objArrElement of objArr) {
					if (objArrElement.name===this.prodName){
						flag=false
						return console.log('匹配到相同项:'+this.prodName)
					}
				}
				if (flag){
					this.objArr.push({
						id:this.objArr[this.objArr.length-1].id+1,
						name:this.prodName,
						price:this.prodPrice,
						initTime:new Date()
					})
				}else return false
			}
		}
	}
}

</script>

<style>
body{
	box-sizing: border-box;
	vertical-align: middle;
}
tr:hover{
	cursor: pointer;
}
.myTable{
	width: 800px;
	border: 1px solid #c1c1c1;
	border-radius: 3px;
}
.addPart{
	display: flex;
	margin: 5px;
	width: 500px;
	justify-content: space-between;
}

</style>

综合上面的案例:

  1. 我们要添加一个bootstrap包,使用yarn add bootstrap,在项目中添加bs包。并且如果想要全页面使用的化,我们就要在main.js中导入,代码类似“import 'bootstrap/dist/css/bootstrap.min.css'”。
  2. 我们要将包添加一个单vue组件时,也是用上面的代码“import 'bootstrap/dist/css/bootstrap.min.css‘ ”放入script中即可。

过滤器:

在我们之前使用的art-template中我们接触过过滤器。在vue中书写方式类似:

 由于3.x版本之后的vue已废弃原先的filter方法,下面给出解决方案。


详见VUE官方文档https://v3.cn.vuejs.org/guide/migration/filters.html#_2-x-%E8%AF%AD%E6%B3%95

下面给出,vue5的替代办法代码示例:

<template>
	<div>
		<div>原型 : <span class="originType">{{ text }}</span></div>
		<div>调用prototype自定义字符串方法 : <span>{{ text.reverse() }}</span></div>
		<div>调用方法 : <span>{{ reverseString(text) }}</span></div>
		<div>使用计算属性 : <span>{{ reverseText }}</span></div>
	</div>

</template>

<script>
// 这里我们给String原型类中添加了reverse方法
String.prototype.reverse = function () {
	return this.split('').reverse().join('')
}
export default {
	data() {
		return {
			text:"hello, world!"
		}
	},
	methods: {
		reverseString(string) {
			return string.split("").reverse().join('')
		}
	},
	computed: {
		reverseText() {
			return this.text.split('').reverse().join('')
		}
	}
}
</script>

<style>
span {
	font-weight: bolder;
	color: indianred;
}

span.originType {
	color: #2aabd2;
}
</style>

上面我给出了在vue5中的解决方案。

计算属性computed:

 计算属性的使用场景:当一个变量通过其它变量计算而来。

利用computed实现简易计算器:

<template>
	<div>
		<form>
			<input type="number" v-model="a">
			<input type="radio" name="choice" @click="changeSign('+')" checked>+
			<input type="radio" name="choice" @click="changeSign('-')">-
			<input type="radio" name="choice" @click="changeSign('*')">*
			<input type="radio" name="choice" @click="changeSign('/')">/
			<input type="number" v-model="b">
		</form>
		<div>结果:{{ calculate }}</div>
	</div>
</template>

<script>
export default {
	data() {
		return {
			a: 0,
			b: 0,
			sign: '+',
			num: 0
		}
	},
	methods: {
		changeSign(sign) {
			switch (sign) {
				case '+': {
					this.sign = '+'
					break
				}
				case '-': {
					this.sign = '-'
					break
				}
				case '*': {
					this.sign = '*'
					break
				}
				case '/': {
					this.sign = '/'
					break
				}
			}
		}
	},
	computed: {
		calculate() {
			switch (this.sign){
				case "+":{
					return this.a + this.b
				}
				case "-":{
					return this.a - this.b
				}
				case "*":{
					return this.a * this.b
				}
				case "/":{
					return this.a / this.b
				}
			}
			return 0
		}
	}
}
</script>

<style>

</style>

计算属性-缓存:

通过上面的代码:大家一定好奇计算属性和方法的差异在哪里。

下面请看:

 结果:

 从此处我们可以发现计算属性的函数只调用了一次。

 

 计算属性的完整写法:

 当我们使用计算属性实现v-model的双向绑定时,我们会报一个错误。大致如下:

完整写法使用:

<template>
	<div>
		<form>
			<input type="number" v-model="a">
			<input type="radio" name="choice" @click="changeSign('+')" checked>+
			<input type="radio" name="choice" @click="changeSign('-')">-
			<input type="radio" name="choice" @click="changeSign('*')">*
			<input type="radio" name="choice" @click="changeSign('/')">/
			<input type="number" v-model="b">
		</form>
		<div>计算属性结果:{{ calculate }}</div>
		<div>方法结果:{{ calculateMethod() }}</div>
		<input type="text" v-model="calculate">
	</div>
</template>

<script>
export default {
	data() {
		return {
			a: 0,
			b: 0,
			sign: '+',
			num: 0,
			setNum:0
		}
	},
	methods: {
		changeSign(sign) {
			switch (sign) {
				case '+': {
					this.sign = '+'
					break
				}
				case '-': {
					this.sign = '-'
					break
				}
				case '*': {
					this.sign = '*'
					break
				}
				case '/': {
					this.sign = '/'
					break
				}
			}
		},
		calculateMethod() {
			switch (this.sign){
				case "+":{
					return this.a + this.b
				}
				case "-":{
					return this.a - this.b
				}
				case "*":{
					return this.a * this.b
				}
				case "/":{
					return this.a / this.b
				}
			}
			return 0
		}
	},
	computed: {
		calculate:{
			set(setNum){
				this.setNum=setNum
			},
			get(){
				switch (this.sign){
					case "+":{
						return this.a + this.b
					}
					case "-":{
						return this.a - this.b
					}
					case "*":{
						return this.a * this.b
					}
					case "/":{
						return this.a / this.b
					}
				}
				return 0
			}
		}
	}
}
</script>

<style>

</style>

侦听器:

用于侦听某个变量是否发生改变。

 深度侦听:

 下面以一个产品表格的本地存储版本结束本节:

<template>
	<div :class="{'myTable':true}">
		<table :class="{'table':true,'table-hover':hoverStyle}">
			<thead>
			<tr>
				<th v-for="item in tableHeadTitle">{{ item }}</th>
			</tr>
			</thead>
			<tbody>
			<tr v-for="item in objArr" :key="item.id">
				<td v-for=" val in item">{{ val }}</td>
				<td><a href="#" @click.prevent="deleteLine(item.id)">delete</a></td>
			</tr>
			<tr>
				<td>汇总数据:</td>
				<td colspan="2">总价值:{{ totalPrice }}</td>
				<td colspan="2">均价:{{ avgPrice }}</td>
			</tr>
			</tbody>
			<tfoot>
			<tr>
				<td :colspan="tableHeadTitle.length" v-show="objArr.length<=0" v-text="tableText"></td>
			</tr>
			</tfoot>
		</table>
		<div class="addPart">
			<input type="text" name="" id="" placeholder="资产名称" v-model.lazy.trim="prodName">
			<input type="text" placeholder="0" v-model.lazy.number="prodPrice">
			<button @click.stop="addProduct" class="btn btn-success btn-sm">add production</button>
		</div>
	</div>
</template>

<script>
let originObjArr=[]
let getLocalStorageData=JSON.parse(localStorage.getItem("originObj"))
if(getLocalStorageData===null){
	originObjArr= [
		{
			id: 100,
			name: '外套',
			price: 299,
			initTime: new Date()
		}, {
			id: 101,
			name: '鞋子',
			price: 199,
			initTime: new Date()
		}, {
			id: 102,
			name: '手机',
			price: 3450,
			initTime: new Date()
		}, {
			id: 103,
			name: '雨伞',
			price: 38,
			initTime: new Date()
		}
	]
}else{
	originObjArr=getLocalStorageData.newObj
}

export default {
	data() {
		return {
			tableHeadTitle: ['ProdID', 'ProdName', 'Price', 'InitialTime', 'Func'],
			objArr: originObjArr,
			hoverStyle: true,
			prodName: "",
			prodPrice: 0,
			tableText: '# notice: this table is a null table!'
		}
	},
	methods: {
		deleteLine(getID) {
			if (this.objArr.length <= 1) {
				if (!confirm('当前项目已是最终项!')) {
					return false
				}
			}
			let getIndex = this.objArr.findIndex(ele => ele.id === getID)
			this.objArr.splice(getIndex, 1)
		},
		addProduct() {

			if (this.prodName === '' || this.prodPrice === '') {
				alert('please write in something')
				return false
			} else {
				let flag = true
				for (const objArrElement of originObjArr) {
					if (objArrElement.name === this.prodName) {
						flag = false
						return console.log('匹配到相同项:' + this.prodName)
					}
				}
				if (flag) {
					this.objArr.push({
						id: this.objArr.length > 0 ? this.objArr[this.objArr.length - 1].id + 1 : 1,
						name: this.prodName,
						price: this.prodPrice,
						initTime: new Date()
					})
				} else return false
			}
		}
	},
	computed: {
		totalPrice() {
			let sum = 0
			this.objArr.forEach(ele => sum += ele.price)
			return sum
		},
		avgPrice() {
			let sum = 0
			let getArrLength = this.objArr.length
			this.objArr.forEach(ele => sum += ele.price)
			return sum / getArrLength
		}
	},
	watch:{
		objArr:{
			immediate:true,
			deep:true,
			handler(newVal,oldVal){
				let savedObj={
					newObj:newVal,
					oldObj:oldVal
				}
				localStorage.setItem("originObj",JSON.stringify(savedObj))
			}
		}
	}
}

</script>

<style>
body {
	box-sizing: border-box;
	vertical-align: middle;
}

tr:hover {
	cursor: pointer;
}

.myTable {
	width: 800px;
	border: 1px solid #c1c1c1;
	border-radius: 3px;
}

.addPart {
	display: flex;
	margin: 5px;
	width: 500px;
	justify-content: space-between;
}

</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

言行物恒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值