双向绑定
咱们直接,学过vue应该都知道声明式渲染——双向绑定v-model
,这个通常同差值表达式{{}}
一起使用,说多了也没用,如果我们的input
框的type
类型是text
,那么所绑定的变量值就同里面输入的值一样,与input
里面的value
值就无关了,而如果type
类型为是checkbox
,那么就比较复杂了,直接看代码:
<template>
<div id="app">
<label><input v-model="message" type="checkbox" value="里面的值是叫花鸡" name="" id="">叫花鸡</label>
<p>第一个:{{message}}</p>
<label><input v-model="messages" type="checkbox" name="" id="">叫花鸡</label>
<p>第二个:{{messages}}</p>
</div>
</template>
<script>
export default {
name: 'App',
data(){
return{
//第一个是数组形式。
message:[],
//第二个是字符串形式。
messages:""
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
从结果可以看出如果给变量定义的是字符串,那么无论你给input是否定义value属性,它的值始终都是true和false,而如果变量定义的是数组,那么它的值是同value属性值相同。直接看下图:
处理用户事件
其实事件绑定
相信大家都很了解,说白了就是v-on:(事件绑定)
,例如:
<button v-on:click="add">按钮</button>
<!--上面的同下面的一样。--!>
<button @click="add">按钮</button>
这些都没啥,最主要的是你必须知道事件修饰符
,看例子吧:
1.阻止冒泡事件
冒泡事件就是从当前节点出发,找到父亲节点并将其触发,并且会一直冒泡而直到html根元素为止。
<div @click.stop="fn2"></div>
2.捕获事件
与冒泡事件相反,它是从html根元素开始依次移动并触发到当前元素为止。
<div class="div2" @click.capture="fn2"></div>
3.阻止默认事件
<a href="https://example.com" @click.prevent="fn2">Click me</a>
上面这个例子非常好理解,大家应该知道超链接的作用就是导航到指定的url,但是我们我们使用了prevent
修饰符,它会执行方法fn2
,而不会导航到指定的url。
监听数据变化
看到这个题目,相信大家第一个想到的就是侦听器
,它的用法也是相当地简单,直接看代码:
上面就是侦听器最简单的使用,即我们要监听的变量发生了变化——就会触发侦听器。但是这里我想说的重点就是侦听器的进阶使用。
侦听器的进阶使用
获取前一次的值
有时候我们想要获取前一次的值,这个也是相当滴简单哒,只需要在我们监听的变量里面添加参数即可,第一个参数是新值,第二个是旧值。
watch:{
count(value,oldValue){
let str = `count变量的旧值为${oldValue},新值为${value}`;
let p = document.createElement('p');
p.innerHTML = str;
document.body.appendChild(p);
}
}
动态绑定v-bind
有时候我们修改一些特性节点时不一定非得在html里面直接修改,这样显得代码非常的臃肿。我们可以使用v-bind
动态绑定,可以简写为:
,直接代码:
<template>
<div id="app">
<img src="#" v-bind:alt="imgText" />
</div>
</template>
上面的alt属性就是当img没显示时,就会出现一行数据,这行数据就是alt的属性值。
<script>
export default {
name: "app",
// 数据
data() {
return {
imgText:'周杰伦演唱会图片'
};
}
};
</script>
模板中使用表达式
模板中进行计算
<template>
<div id="app">
<ul>
<li>{{ goods[0].index + 1 }}---{{ goods[0].name }}</li>
<li>{{ goods[1].index + 1 }}---{{ goods[1].name }}</li>
<li>{{ goods[2].index + 1 }}---{{ goods[2].name }}</li>
</ul>
</div>
</template>
<script>
export default {
name: "app",
// 数据
data() {
return {
goods:[
{
index:0,
name:"扫地机器人"
},
{
index:1,
name:"华为手机"
},
{
index:2,
name:"戴尔笔记本"
}
]
};
}
};
</script>
模板中使用三元表达式
在差值表达式里面也可以使用三元表达式,直接看代码:
<template>
<div id="app">
<p>{{ flag?'你已经通过了考试':'你还没有通过考试' }}</p>
<button @click="exchange">转换</button>
</div>
</template>
<script>
export default {
name: "app",
// 数据
data() {
return {
flag:true
};
},
methods:{
exchange(){
this.flag = !this.flag;
}
}
};
</script>
在模板中写方法
<template>
<div id="app">
<p>{{ message.split('').reverse().join('') }}</p>
</div>
</template>
<script>
export default {
name: "app",
// 数据
data() {
return {
message:"优课达--学的比别人好一点~"
};
}
};
</script>
另外,在模板中也可以直接写js表达式,但是一般不要这样,因为会使得html代码显得臃肿。
条件渲染语句
里面的v-if
和v-else
以及v-else-if
语句就不说了,直接看个例子理解一下:
<p v-if="questions[0].type === 'PICK'">{{ questions[0].content }}</p>
<p v-else-if="questions[1].type === 'MULT'">{{ questions[1].content }}</p>
<p v-else>题目还没有加载进来...</p>
<script>
export default {
name: "app",
// 数据
data() {
return {
questions:[
{
type:"PICK",
content:"这是一道选择题"
},
{
type:"MULT",
content:"这是一道多选题"
},
{
type:"ESSAY",
content:"这是一道论述题"
}
]
};
}
};
</script>
我想说的重点是v-if
和v-show
的区别,它俩区别用两点就可以看出:
- v-if指令是如果不满足条件的话,则此标签在dom中根本不存在。
- v-show指令则是如果不满足条件,只是将标签的display属性设置为none。
列表渲染语句
vue里面的列表渲染核心就是v-for
循环指令,我们直接看个简单的例子:
循环渲染数字
<div id="app">
<ul>
<li v-for="item in 5" :key="item">{{ item }}</li>
</ul>
</div>
里面的:key属性就是Vue工程为了保证每个item都是唯一的,所以需要一个key,这个属性值一般都是从后台取到的数据的id,但是我们可以给它赋值为索引。
循环渲染数组
这里的v-for
遍历数组对象和js的遍历数组是一样的,代码:
<ul>
<!--第一个参数item是成员属性值,第二个参数是成员索引-->
<li v-for="(item,index) in nameList" :key="index">{{ item }}</li>
</ul>
<script>
export default {
name: "app",
// 数据
data() {
return {
nameList:["张淮森","周逸依","梁澄静","宁古薄","丘约靖"]
};
}
};
</script>
循环渲染对象
渲染对象相较于渲染数组不同的是,成员变量
变成了键值对
,看代码:
<ul>
<!--
value:对象的每一项的值,
key:对象中每一项的键,这个一般不常用。
index:索引
-->
<li v-for="(value,key,index) in book" :key="index">值:{{ value }}--键:{{ key }}--索引:{{ index }}</li>
</ul>
<script>
export default {
name: "app",
// 数据
data() {
return {
book:{
bookName:'指环王',
author:'JK 罗琳'
}
};
}
};
</script>
遍历数组中的对象
遍历数组中的对象就更加简单了,看例子吧,简单理解:
<ul>
<li v-for="(item,index) in books" :key="index">
{{ index+1 }}----{{ item.title }}----{{ item.author }}----{{ item.publishedTime }}
</li>
</ul>
<script>
export default {
name: "app",
// 数据
data() {
return {
books: [
{
title: '《魔戒》',
author: '约翰·罗纳德·瑞尔·托尔金',
publishedTime: '1954'
},{
title:'《哈利·波特》',
author:'J·K·罗琳',
publishedTime:'1997'
},{
title:'《人性的弱点》',
author:'戴尔•卡内基',
publishedTime:'2008'
}
]
};
}
};
</script>
计算属性
这个学过的都知道,这东西和Methods
很像,但是这个相较于后者一般都是用于差值表达式中,例子:
<div id="app">
<p>原字符串:{{ message }}</p>
<p>反转后的字符串:{{ reverseMessage() }}</p>
</div>
<script>
export default {
name: 'app',
data: function () {
return {
message: '优课达--学的比别人好一点~',
};
},
methods: {
reverseMessage: function () {
return this.message.split('').reverse().join('');
},
},
};
</script>
这里我就必须说下计算属性的两个性质了:依赖
和缓存
。
- 依赖:案例中的
message
就是计算属性的依赖。 - 缓存:上一次计算得到的值。
这里我结合上面的代码示例解释一下:
计算属性computed
:
- 当
message
发生变化(即依赖变化),reverseMessage
会重新计算并返回计算结果。 - 当
message
没有变化(即依赖没发生变化),reverseMessage
会返回缓存的值,而不会去计算。
方法methods
:
- 每次访问的时候,都会执行里面的方法逻辑,然后返回结果。
总的来说,计算属性明显性能更优,因为避免了不必要的代码执行。
动态class
动态绑定我在上面说过了,其实就是v-bind:
,我接下来要说的是动态样式绑定
,语法如下所示:
<!--下面的isActive就是一个在data里面的boolean属性值-->
<div class="base" v-bind:class="{ 'active': isActive }"></div>
.active {
border: 1px solid green;
}
上面的引号规则可以用外单内双
或者外双内单
都是可以的。
<!-- 外双内单 -->
<div v-bind:class="{ 'base-active': isActive }"></div>
<!-- 外单内双 -->
<div v-bind:class='{ "base-active": isActive }'></div>
亦或者是多类名,即一个标签里面的class属性有多个值。
<div v-bind:class='{ "base-active": isActive,"base":true}'></div>
方法形式
我们在上面讲的都是变量形式,我现在需要说的是方法形式。说白了就是将里面的变量
换为了方法
,原本是返回变量的boolean
值,而换成方法形式则是返回方法值,例如,下面的方法返回值类型就是boolean
。
<span :class="{ 'new-appear': isActive(item.type) }">新</span>
data:function(){
return {
liListData: [
{
imgUrl:'https://m.360buyimg.com/babel/jfs/t1/30057/19/14881/720/5cbf064aE187b8361/eed6f6cbf1de3aaa.png',
text: '话费',
type: 'NEW',
},
]
}
},
methods:{
isActive: function(type) {
if (type === 'NEW') {
return true;
}
return false;
}
}
表达式形式
对于上面的代码感觉过于臃肿,我们直接使用表达式岂不是更简单,看代码:
<span :class="{ 'new-appear': item.type === 'NEW' }">新</span>
另外,我们也可以使用计算机属性的形式,我们可以变换一下:
<span :class="{ 'new-appear': hoverObj }">新</span>
computed: {
hoverObj: function () {
return {
hover: this.index === 1,
};
},
},
动态样式绑定中的数组写法
我在上面说的都是关于对象的写法,那么数组的写法也是非常简单,直接往里面添加类名即可,如下:
<div v-bind:class="['red-style', 'font-style']"></div>
另外,在数组中还可以使用三元表达式,代码:
<div
v-bind:class="['red-style', 'font-style',isChoosed ? 'redbg' : 'bluebg']"
></div>
最后,在数组里面仍然也可以使用对象,看代码:
<div v-bind:class="['red-style', 'font-style',{'redbg':isChoosed}]"></div>
动态style
我们上面讲的:class
是外部样式,那么我接下来讲的:style
则就是行内样式了。还是一样,我们先讲对象语法,再讲数组语法。
对象语法
<div :style="{background:'red',fontWeight:700,fontSize:'20px'}"></div>
/*大家仔细看里面的区别,*/
<div :style="{background:'red','font-weight':700,'font-size':'20px'}"></div>
但是,如果里面的样式过多了,那么就需要将动态样式给提取出来了,这样会使html代码显得很简洁。
<div :style="flexStyle"></div>
data:function(){
return {
flexStyle: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
alignItems: 'center',
flexWrap: 'no-wrap',
fontWeight: 700 ,
},
}
}
那么,如果我想设置一个如下面的例子,代码这样子写可以吗:
data:function(){
return {
bg: {
background: `url(${imgList[currentIndex]}) no-repeat center / contain`,
},
}
}
答案明显是不能的,记住了,这个例子只能用下面的这样子写,如果我们写在data变量里面的话,即如果写成上面的那样,会报错,显示你的imgList
未定义,这是因为此时的bg和imgList都属于全局变量,这里不能互相引用。
数组语法
数组语法同:class
大同小异,但是同:class
不同的一点就是它数组里面是变量,不需要加引号,而后者里面的是类名,需要加引号。
<div :style="[fontStyle,boxStyle]">这里是文字</div>
data() {
return {
fontStyle: { color: 'red', fontSize: '33px' },
boxStyle:{width: '200px', height: '200px', border: `1px solid black`}
};
},
这里面亦可以使用三元表达式,如下:
<div :style="[fontStyle, isActive ? boxStyle : colorBox]">这里是文字</div>
到这里,基本整理完毕。