第二章 Vue 核心技术
2.1 Vue 入门开发
2.1.1 创建工程和 安装vue 模块
2.1.3 编写HTML页面!
编写步骤:
-
采用
el选项: 元素element的缩写,指定被 Vue 管理的 Dom 节点入口(值为选择器 ),必须是一个普通的HTML 标签节点,一般是 div。
data选项:指定初始化数据,在 Vue 所管理的 Dom 节点下,可通过模板语法来进行使用
-
标签体显示数据: {{xxxxx}}
-
表单元素双向数据绑定: v-model
-
注意:el的值不能为 html 或 body
源码实现:
2.2 分析 MVVM 模型
常见面试题:什么是 MVVM 模型?
MVVM是 Model-View-ViewModel 的缩写,它是一种软件架构风格
Model:模型, 数据对象(data选项当中 的)
View:视图,模板页面(用于渲染数据)
ViewModel:视图模型,其实本质上就是 Vue 实例
它的哲学思想是:
通过数据驱动视图
把需要改变视图的数据初始化到 Vue中,然后再通过修改 Vue 中的数据,从而实现对视图的更新。
声明式编程
按照 Vue 的特定语法进行声明开发,就可以实现对应功能,不需要我们直接操作Dom元素
命令式编程:Jquery它就是,需要手动去操作Dom才能实现对应功能。
2.3 Vue Devtools 插件安装
Vue Devtools 插件让我们在一个更友好的界面中审查和调试 Vue 项目。
谷歌浏览器访问:chrome://extensions,然后右上角打开 开发者模式 ,打开的效果如下
将 Vue.js_devtools_5.1.0.zip直接拖到上面页面空白处,会自动安装
效果如下则安装成功
当你访问Vue开发的页面时,按 F12可访问Vue 标签页
2.4 模板数据绑定渲染
可生成动态的HTML页面,页面中使用嵌入 Vue.js 语法可动态生成
- {{xxxx}} 双大括号文本绑定
- v-xxxx 以v-开头用于标签属性绑定,称为指令
2.4.1 双大括号语法
![]() |
2.4.2 
一次性插值
通过使用 v-once指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。
![]() | |
2.4.3 
输出HTML指令
格式: v-html=‘xxx’
作用:
如果是HTML格式数据,双大括号会将数据解释为普通文本,为了输出真正的 HTML,你需要使用v-html指令。
Vue 为了防止 XSS 攻击,在此指令上做了安全处理,当发现输出内容有 script 标签时,则不渲染
XSS 攻击主要利用 JS 脚本注入到网页中,读取 Cookie 值(Cookie一般存储了登录身份信息),读取到了发送到黑客服务器,从而黑客可以使用你的帐户做非法操作。
XSS 攻击还可以在你进入到支付时,跳转到钓鱼网站。
案例源码:
![]() | |
效果图
![]() | |
2.4.4 
元素绑定指令
完整格式: v-bind:元素的属性名=‘xxxx’
缩写格式: :元素的属性名=‘xxxx’
作用:将数据动态绑定到指定的元素上案例源码:
案例源码
2.4.5 
事件绑定指令
完整格式: v-on:事件名称=“事件处理函数名”
缩写格式: @事件名称=“事件处理函数名” 注意: @ 后面没有冒号
作用:用于监听 DOM 事件
案例源码: 每点击1次,数据就加1
![]() | |
2.4.6 完整源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-模板数据绑定渲染</title>
</head>
<body>
<div id="app">
<h3>1、双大括号输出文本内容</h3> 10 <!--文本内容-->
<p>普通文本:{{ message }}</p>
<!--使用JS表达式-->
<p>JS表达式:{{ number + 1 }}</p>
<h3>2、一次性插值 v-once </h3>
<span v-once> 这个将不会改变: {{ message }}</span>
<h3>3、v-html 指令输出真正的 HTML 内容</h3>
<p>双大括号:{{ contentHtml }}</p>
<!-- 指令的值不需要使用双大括号获取 -->
<!-- <p>v-html指令:<span v-html="{{contentHtml}}"></span></p> -->
<p>v-html指令:<span v-html="contentHtml"></span></p>
<h3>4、v-bind 属性绑定指令</h3>
<!-- 直接写属性名是获取不到-->
<img src="imgUrl" alt="VueLogo">
<!-- 红色字体是正常的 -->
<img v-bind:src="imgUrl" alt="VueLogo">
<!-- 缩写 -->
<img :src="imgUrl" alt="VueLogo">
<h3>5、v-on 事件绑定指令</h3>
<input type="text" v-model="num">
<button v-on:click="add">点击+1</button>
</div>
<br>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript"> var vm = new Vue({
el: '#app', data: {
message: 'haha', number: 1,
contentHtml: '<span style="color:red">红色字体内容</span>',
imgUrl: 'https://cn.vuejs.org/images/logo.png', num: 2
},
methods: { //指定事件处理方法, 在模板页面中通过 v-on:事件名 来调用
add: function () { //key为方法名console.log('add 被 调 用 ') vm.num++ //每点击1次num加1
}
}
})
</script>
</body>
</html>
2.5 计算属性和监听器
2.5.1 
计算属性
选项定义计算属性
计算属性 类似于methods选项中定义的函数
计算属性 会进行缓存,只在相关响应式依赖发生改变时它们才会重新求值。
函数 每次都会执行函数体进行计算。
需求:输入数学与英语分数,采用methods与computed分别计算出总得分
案例源码:
<body>
2 <div id="app">
3 数学:<input type="text" v-model="mathScore" >
4 英语:<input type="text" v-model="englishScore">
5 总分(方法-单向):<input type="text" v-model="sumScore()">
6 总分(计算属性-单向):<input type="text" v-model="sumScore1">
7 </div>
8 <script src="./node_modules/vue/dist/vue.js"></script>
9 <script type="text/javascript">
10 var vm = new Vue({
11 el: '#app',
12 data: {
13 mathScore: 80,
14 englishScore: 90,
15 },
16 methods: { //不要少了s
17 sumScore: function () {
18 //在控制台输入 vm.sumScore() 每次都会被调用
19 console.info('sumScore被调用')
20 // `this` 指向当前 vm 实例, 减 0 是为了字符串转为数字运算
21 return (this.mathScore-0) + (this.englishScore-0)
22 }
23 },
24 computed: { //计算属性
25 sumScore1 : function () {
26 //在控制台输入vm.sumScore1 不会被重新调用,说明计算属性有缓存
27 console.info('sumScore1被调用')
28 return (this.mathScore - 0) + (this.englishScore -0)
29 }
30 }
31 })
32 </script>
33 </body>
选项内的计算属性默认是
更新总分,而修改总分不会更新数据和英语
函数,所以上面只支持单向绑定,当修改数学和英语的数据才会
2.5.2 计算属性(双向绑定)
计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter
案例源码:
<body>
<div id="app">
数学:<input type="text" v-model="mathScore" ><br>
英语:<input type="text" v-model="englishScore"><br>
总分(方法-单向):<input type="text" v-model="sumScore()"><br>
总分(计算属性-单向):<input type="text" v-model="sumScore1"><br>
总分(计算属性-双向):<input type="text" v-model="sumScore2"><br>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
mathScore: 80,
englishScore: 90,
},
methods: { //不要少了s
sumScore: function () {
//在控制台输入 vm.sumScore() 每次都会被调用
console.info('sumScore被调用')
// `this` 指向当前 vm 实例, 减 0 是为了字符串转为数字运算
return (this.mathScore - 0) + (this.englishScore -0)
}
},
computed: {
//计算属性 默认 getter 只支持单向绑定
sumScore1 : function () {
//在控制台输入vm.sumScore1 不会被重新调用,说明计算属性有缓存
console.info('sumScore1被调用')
return (this.mathScore - 0) + (this.englishScore -0)
},
//指定 getter/setter 双向绑定
sumScore2 : {
get: function () {
console.info('sumScore2被调用')
return (this.mathScore-0) + (this.englishScore-0)
},
set: function (newValue) {//value为更新后的值
// 被调用则更新了sumScore2,然后将数学和英语更新为平均分
var avgScore = newValue / 2
this.mathScore = avgScore
this.englishScore = avgScore
}
}
}
})
</script>
</body>
2.5.3 监听器*
当属性数据发生变化时,对应属性的回调函数会自动调用, 在函数内部进行计算
通过watch选项 或者 vm 实例的$watch()来监听指定的属性
需求:
-
通过 watch 选项 监听数学分数, 当数学更新后回调函数中重新计算总分sumScore3
-
通过 vm.$watch() 选项 监听英语分数, 当英语更新后回调函数中重新计算总分sumScore3
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3TOyElS4-1611456478180)(file:///media\wps139.png)]源码实现:
注意: 在data 选择中添加一个 sumScore3 属性
<body>
<div id="app">
数学:<input type="text" v-model="mathScore" ><br>
英语:<input type="text" v-model="englishScore"><br>
总分(方法-单向):<input type="text" v-model="sumScore()"><br>
总分(计算属性-单向):<input type="text" v-model="sumScore1"><br>
总分(计算属性-双向):<input type="text" v-model="sumScore2"><br>
总分(监听器):<input type="text" v-model="sumScore3"><br>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
mathScore: 80,
englishScore: 90,
sumScore3: 170
},
methods: { //不要少了s
sumScore: function () {
//在控制台输入 vm.sumScore() 每次都会被调用
console.log('sumScore被调用')
// `this` 指向当前 vm 实例, 减 0 是为了字符串转为数字运算
return (this.mathScore - 0) + (this.englishScore -0)
}
},
// 计算属性
computed: {
// 默认 getter 只支持单向绑定
sumScore1 : function () {
//在控制台输入 vm.sumScore1 不会被重新调用 ,说明计算属性有缓存
console.log('sumScore1被调用')
return (this.mathScore - 0) + (this.englishScore -0)
},
//指定 getter/setter 双向绑定
sumScore2 : {
get: function () {
console.log('sumScore2被调用')
return (this.mathScore-0) + (this.englishScore-0)
},
set: function (newValue) {//value为更新后的值
// 被调用则更新了sumScore2,然后将数学和英语更新为平均分
var avgScore = newValue / 2
this.mathScore = avgScore
this.englishScore = avgScore
}
}
},
//监听器方式1:watch选项watch : {
//当数学修改后,更新总分sumScore3 mathScore : function (newValue, oldValue) {
//newValue 就是新输入的数学得分
this.sumScore3 = (newValue-0) + (this.englishScore-0)
}
}
})
//监听器方式2:通过vm对象调用
//第1个参数为监听的属性名,第2个回调函数
vm.$watch('englishScore', function (newValue) {
//newValue 就是新输入的英语得分
this.sumScore3 = (newValue-0) + (this.mathScore-0)
})
</script>
</body>
2.6 Class与Style绑定v-bind
通过 class 列表和 style 指定样式是数据绑定的一个常见需求。它们都是元素的属性,都用v-bind处理,其中表达式结果的类型可以是:字符串、对象或数组。
2.6.1 语法格式
v-bind:class='表达式’或:class=‘表达式’
class的表达式可以为:
字符串:class=‘activeClass’
对象:class=’{active:isActive,error:hasError}’
数组:class=’[“active”,“error”]'注意要加上双引号,不然是获取data中的值
v-bind:style='表达式’或:style=‘表达式’
:style的表达式一般为对象
:style="{color:activeColor,fontSize:fontSize+‘px’}"注意要加上单引号,不然是获取data中的值
注意:对象中的value值 activeColor 和 fontSize 是data中的属性
2.6.2 案例源码
效果图
![]() | |
源码实现:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yWahGhui-1611456478195)(file:///media\wps163.png)]
2.7 条件渲染 v-if
2.7.1 条件指令
v-if是否渲染当前元素
v-else
v-else-if
v-show 与v-if类似,只是元素始终会被渲染并保留在 DOM 中,只是简单切换元素的 CSS 属性 display 来显示或隐藏
2.7.2 案例源码
效果图:
源码实现
2.7.3 v-if 与 v-show 比较
-
什么时候元素被渲染
v-if)如果在初始条件为假,则什么也不做,每当条件为真时,都会重新渲染条件元素 v-show不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换
-
使用场景选择
v-if有更高的切换开销,
v-show有更高的初始渲染开销。
因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行后条件很少改变,则使用 v-if 较好。
2.8 列表渲染 v-for
2.8.1 列表渲染指令
1. v-for 迭代数组
语法: v-for="(alias, index) in array"
说明: alias : 数组元素迭代的别名; index : 数组索引值从0开始(可选)
举例:
2. v-for 迭代对象的属性
语法: v-for="(value, key, index) in Object"
说明: value : 每个对象的属性值; key : 属性名(可选); index : 索引值(可选) 。
举例:
注意: 在遍历对象时,是按Object.keys()的结果遍历,但是不能保证它的结果在不同的JavaScript引擎下是顺序一致的。
- 可用 of 替代 in 作为分隔符
2.8.2 案例源码
效果图
![]() | |
源码实现
2.9 事件处理 v-on
2.9.1 事件处理方法
完整格式:v-on:事件名="函数名"或v-on:事件名=“函数名(参数…)”
缩写格式:@事件名="函数名"或@事件名=“函数名(参数…)”
event:函数中的默认形参,代表原生DOM时间
当调用的函数,有多个参数传入时,需要使用原生DOM事件,则通过$event作为实参传入
作用:用于监听DOM事件
案例源码:
2.9.2 事件修饰符
.stop阻止单击事件继续传播event.stopPropagation()
.prevent阻止事件默认行为event.preventDefault(
.once点击事件将只会触发一次
<body>
<div id="app">
<h2>1. 事件处理方法</h2>
<button @click="say">Say {{msg}}</button>
<button @click="warn('hello', $event)">Warn</button>
<br>
<h2>2. 事件修饰符</h2>
<!--单击事件继续传播-->
<div @click="todo">
<!--点击后会调用doThis再调用todo-->
<button @click="doThis">单击事件会继续传播</button>
</div>
<br/>
<!-- 阻止单击事件继续传播,-->
<div @click="todo">
<!--点击后只调用doThis-->
<button @click.stop="doThis">阻止单击事件会继续传播</button>
</div>
<!-- 阻止事件默认行为 -->
<a href="http://www.ceshi.com" @click.prevent="doStop">测试官网</a>
<!-- 点击事件将只会触发一次 -->
<button @click.once="doOnly">点击事件将只会触发一次: {{num}}</button>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
msg: 'Hello, Vue.js',
num: 1
},
methods: {
say: function (event) {
// `this` 在方法里指向当前 Vue 实例
alert(this.msg)
// `event` 是原生 DOM 事件
alert(event.target.innerHTML)
},
//多个参数如果需要使用原生事件,将 $event 作为实参传入
warn: function (msg, event) {
alert(msg + "," + event.target.tagName)
},
todo: function () {
alert("todo ");
},
doThis: function () {
alert("doThis ");
},
doStop: function () {
alert("href默认跳转被阻止 ")
},
doOnly: function() {
this.num++
}
}
})
</script>
</body>
2.9.3 按键修饰符
格式:v-on:keyup按键名或@keyup按键名
常用按键名:
.enter
.tab
.delete(捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<h3>事件处理方法 v-on 或 @事件名</h3>
<button v-on:click="say">say {{msg}} </button>
<!-- $event代表的是原生的dom事件 -->
<button @click="warn('hello',$event)">warn</button>
<h3>2,事件修饰符</h3>
<!-- 2.1阻止冒泡 -->
<div @click="todo">
<button @click="doThis">单击事件会继续传播</button>
</div>
<div @click="todo">
<button @click.stop="doThis">阻止单击事件会继续传播</button>
</div>
<!-- 2.2阻止事件的默认行为 -->
<a href="http://www.baidu.com" @click.prevent="doStop">跳转</a>
<!-- 2.3点击事件只会触发一次 -->
<button @click.once="doOnly">点击事件只会出发一次{{num}}</button>
<h3>按键修饰符</h3>
<input type="text" @keyup.enter="keyEnter">
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
msg:"hello test",
num:1
},
methods: {
say:function(event){
//event代表dom原生事件 vue.js会自动将它传入进来
alert(this.msg);
alert(event.target.innerHTML);
},
warn:function(name,event){
//如果函数有多个参数,而又需要使用原生事件,则需要使用$event作为参数传入
alert(name);
alert(event.target.tagName);
},
doThis:function(){
alert("doThis...");
},
todo:function(){
alert("todo...");
},
doStop:function(){
alert("doStop...");
},
doOnly:function(){
this.num++;
},
keyEnter:function(){
alert("按了回车键")
}
},
})
</script>
</body>
</html>
2.10 表单数据双向绑定v-model
单向绑定:数据变,视图变;视图变(浏览器控制台上更新html),数据不变;上面的都是单向绑定
双向绑定:数据变,视图变;视图变(在输入框更新),数据变;
2.10.1 基础用法
v-model指令用于表单数据双向绑定,针对以下类型:
text 文 本
textarea 多行文本
radio 单选按钮
checkbox 复选框
select 下拉框
2.10.2 案例源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="demo">
<!-- @submit.preven阻止事件的默认行为 -->
<form action="#" @submit.prevent="submitform">
姓名(文本):<input type="text" v-model="name">
<br><br>
性别(单选按钮):
<input name="sex" type="radio" value="1" v-model="sex"/>男
<input name="sex" type="radio" value="0" v-model="sex" />女 <br><br>
技能(多选框):
<input type="checkbox" name="skills" value="java" v-model="skills">Java开发
<input type="checkbox" name="skills" value="vue" v-model="skills">Vue.js开发
<input type="checkbox" name="skills" value="python" v-model="skills">Python开发
<br><br>
城市(下拉框):
<select name="citys" v-model="city">
<option v-for="c in citys" :value="c.code">
{{c.name}}
</option>
</select> <br><br>
说明(多行文本):
<textarea cols="30" rows="5" v-model="desc"></textarea>
<br><br>
<button type="submit">提交</button>
</form>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el:"#demo",
data:{
name:"",
sex:0,
skills:["vue"],//默认选中vue
citys:[
{code:"bj",name:"北京"},
{code:"sh",name:"上海"},
{code:"heb",name:"哈尔滨"}
],
city:"sh",
desc:""
},
methods: {
submitform:function(){
//处理提交表单
//发送ajax异步处理
alert(this.name + ","+this.sex+","+this.skills+","+this.city+","+this.desc);
}
},
})
</script>
</body>
</html>