学习视频 bilibili 动力节点
老杜Vue视频教程,Vue2 Vue3实战精讲,一套通关vue【动力节点】
Vue2学习笔记
- Vue程序初体验
- 1 实例与容器只能是一对一的关系
- 2 插值语法
- 3 指令语法
- 3.1 v-once 只渲染元素和组件一次
- 3.2 条件渲染
- 3.2.1 v-if 表达式的值决定标签是否渲染到浏览器
- 3.2.1.1 template 标签使用v-if
- 3.2.2 v-show 控制标签是否可见属性
- 3.2.3 v-if和v-show该如何选择
- 3.2.4 v-for 列表渲染
- 3.2.5 列表过滤(使用计算属性)filter筛选 sort 排序 与 :key的作用
- 3.3 v-bind 动态修改标签原有属性的值
- 3.4 v-model 双向绑定表单value属性值
- 3.5 v-on 事件绑定
- 3.5.1 事件修饰符
- 3.5.2 按键点击事件
- 3.5.3 事件回调函数中的this
- 3.6 v-text、v-html
- 3.7 v-cloak、v-pre
- 4 Vue实例可以访问哪些属性
- 4.1 Vue的实例对象如何访问data对象中的值
- 4.1.1 Object.defineProperty方法,给实例对象增加属性
- 4.1.2 数据代理
- 5 computed:计算属性
- 6 watch:侦听属性
- 6.1 深度监听
- 6.2 深度监听方式的不同,获得的值不同
- 6.2 后期添加监视
- 7 Vue中的this
- 8 class、style绑定
- 8.1 class绑定
- 8.2 style绑定
- 9 创建表单数据
- 10 directives:自定义指令
- 11 组件的使用
- 11.1 组件的嵌套
- 12 $nextTick:页面渲染完成后执行
- 13 js中的函数reduce
Vue程序初体验
-
下载Vue.js文件
并在页面中引入:<script src="../js/vue.js"></script>
-
VScode资源管理器 文件夹折叠
第3步中对话框内容Explorer:Compact Folders
- 配置用户代码片段
找到要配置的语言
"Print to console": { //提示信息
"prefix": "log", //缩写
"body": [
"console.log('$1');", //$1是光标停留的位置
"$2" //$2是点击Tab键后光标会转移到这里
],
"description": "Log output to console" //描述信息,可以删除
},
-
Vscode 更改默认字符编码
-
使用开发版本的Vue时,控制台会提示以下信息
关闭提示的方法:- 可以通过设置
Vue.config
中的productionTip
来开启/阻止 vue 在启动时生成生产提示。Vue.config.productionTip = false
- 修改vue.js文件中的代码
- 可以通过设置
-
控制台中提示安装DevTools
在Edge中安装DevTools,在扩展中搜索DevTools安装后设置,在允许访问文件URL前打勾 -
DevTools作用:调试工具
-
VsCode快捷键
1 实例与容器只能是一对一的关系
示例:
<body>
<div class="app">
第一个容器:{{name }}
</div>
<div class="app">
第二个容器:{{name}}
</div>
<script>
new Vue({
el : '.app',
data : {
name : 'lili'
}
})
</script>
</body>
上述代码to中class=app有两个{{name}}容器,对应同一个实例,运行结果显示只能对应第一个出现的实例
运行结果:第一个容器:lili 第二个容器:{{name}}
- 反之仅有一个容器,而出现两个实例,则只对应第一个出现的实例
2 插值语法
- 在{{表达式}}中,表达式可以写什么?
<h1>1.data中声明的变量和函数</h1> <h1>{{msg}}</h1> <h1>{{sayHello()}}</h1><br> <h1>2. 常量</h1> <h1>{{'字符串常量'}}</h1> <h1>{{10000}}</h1><br> <h1>3. 合法的JavaScript表达式</h1> <h1>{{1 + 1}}</h1> <h1>{{'msg' + '字符串'}}</h1> <h1>{{msg + '字符串'}}</h1> <h1>{{gender ? '男' : '女'}}</h1><br> <h1>4. 访问全局变量,例如:Math、Data</h1> <h1>{{Math.ceil(3.14)}}</h1> <h1>{{Date.now()}}</h1>
3 指令语法
-
指令:让HTML标签的某个属性的值产生动态的效果
-
指令语法:
1. 以“v-”开始
2. 指令写在标签的属性位置 -
格式:
<HTML标签 指令 : 参数 = ’表达式‘
- 不需要参数,不需要表达式。例如:v-once
- 需要参数,不需要表达式。例如:v-if=’表达式‘
- 需要参数,需要表达式。例如:v-bind:参数=’表达式‘
-
表达式:和插值语法中
{{表达式}}
中的表达式是一样的
3.1 v-once 只渲染元素和组件一次
<h1 v-once>{{msg}}</h1>
3.2 条件渲染
3.2.1 v-if 表达式的值决定标签是否渲染到浏览器
- 当if条件判断为false时,该标签不会渲染到浏览器,并不是隐藏
<h1 v-if="a > b">{{ifmsg}}</h1>
- 当v-if、v-else-if、v-else的标签是一个组合时,必须是紧挨在一起,两个标签中间不能有任何标签,否则会报错
<div id="app">
<div>{{bt}}</div>
<button @click="bt++">点我</button><br>
<!-- 当v-if、v-else-if、v-else的标签是一个组合时,必须是紧挨在一起,两个标签中间不能有任何标签,否则会报错 -->
<span v-if="bt % 3 === 0">除以3余数为0</span>
<span v-else-if = "bt % 3 ==1 ">除以3余数为1</span>
<span v-else>除以3余数为2</span>
</div>
<script>
const vm = new Vue({
el : '#app',
data : {
bt : 0,
}
})
</script>
3.2.1.1 template 标签使用v-if
- 作用:避免了在多个标签中使用相同的条件语句,增加开销
- 为什么要用它:
template只是一个占位符,template标签本身不会被渲染到页面
<template v-if="bt % 5 == 0">
<div>template只是一个占位符</div>
<div>template不会被渲染到页面</div>
<div>避免了在多个标签中使用相同的条件语句,增加开销</div>
</template>
3.2.2 v-show 控制标签是否可见属性
- 使用:
v-show = 'true'
或者v-show=’false‘
- 作用:控制标签的属性display,当
v-show=’false
‘时,style="display: none“
隐藏该标签;
<div id="app">
<span v-show="false">v-show条件渲染</span>
</div>
<script>
const vm = new Vue({
el : '#app',
})
3.2.3 v-if和v-show该如何选择
如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
3.2.4 v-for 列表渲染
- v-for可遍历数组,对象,字符串,可指定遍历的次数
- v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。
items : [
item1,item2,item3
]
- 数据源是数组,第二个参数是下标,
v-for=’(item,index)‘ in items
object:{
key1 : value1,
key2 : value2,
}
-
数据原是对象,第二个参数是key,第三个参数是下标index,
v-for=’(value,key,index) in Object‘
-
示例
<div id="app">
<!-- 以列表方式展示 -->
<ul >
<li>ID</li>
<li>姓名</li>
<li>年龄</li>
<li>选择</li>
</ul>
<ul v-for="(vip,index) in vips">
<li>{{index+1}}</li>
<li>{{vip.name}}</li>
<li>{{vip.age}}</li>
<li><input type="checkbox"></li>
</ul>
<!-- 以表格方式展示 -->
<table>
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
<th>选择</th>
</tr>
<tr v-for="(vip,index) in vips">
<td>{{index+1}}</td>
<td>{{vip.name}}</td>
<td>{{vip.age}}</td>
<td><input type="checkbox"></td>
</tr>
</table>
</div>
<script>
const vm = new Vue({
el : '#app',
data : {
vips : [
{
'id':'1',
'name':'jack',
'age':'20'
},
{
'id':'2',
'name':'lili',
'age':'30'
},
{
'id':'3',
'name':'mali',
'age':'40'
},
],
}
})
</script>
3.2.5 列表过滤(使用计算属性)filter筛选 sort 排序 与 :key的作用
JS 数组中的 filter 方法
关于数组方法Array.prototype.filter()方法中 在回调函数体中是否需要使用return的超详细解析
:key
的作用:当数据发生改变时,在内存中对两个相同的key来比较内容,如果不同则会更新有差异的dom中的内容,相同的内容则不更新,以减少开销:key
的值通常使用数据库中的主键。indexOf()
:字符串.indexOf('字符')
返回字符在字符串中的位置下标
示例:"abdcddd".indexOf("")
空字符在任何字符串中位置下标返回0filter
和箭头函数
可遍历的对象.filter(对象中的元素 => 表达式)
表达式为ture的元素会重新组合一个对象- 下面这个方法为什么要加
return
?使用filter筛选对象,需要表达式返回一个boolean
结果,当箭头函数只有一条语句时,不需要加{}
,会自动返回表达式的计算结果,但是当有{}
时,需要使用return
来返回{}
中表达式的计算结果
this.heros.filter(hero => {
return hero.name.indexOf(this.keyWord)>=0)
}
-
sort()
排序:可遍历的对象.sort((a,b) => a.要比较的数据部分 - b.要比较的数据部分)
- sort方法会改变原数据的结构
- a - b :升序
- b - a : 降序
-
示例:
<div id="app">
<h1>输入要搜索的内容</h1>
<input type="text" placeholder="请输入关键字" v-model="keyWord">
<!-- placeholder属性:在对话框中显示指定内容 -->
<input type="text" placeholder="输入搜索的关键字" v-model="keyWord">
<h1>排序</h1>
<!-- 可以在@click中直接对vue属性进行操作 -->
<button @click="selectSort = 1">升序</button>
<button @click="selectSort = 2">降序</button>
<button @click="selectSort = 0">原序</button>
<table >
<tr>
<th>ID</th>
<th>姓名</th>
<th>能量</th>
<th>选项</th>
</tr>
<!-- :key属性的作用:当数据发生改变时,在内存中通过对比相同的key来比较内容,如果不同则会更新dom
:key默认是数据的index,但是当插入的元素位于最上面是,会引起很大的开销,并且会出很大的错误(参考视频p44)
所以通常使用数据库中的主键作为key的值
-->
<tr v-for="hero in newHeros" :key="hero.id">
<td>{{hero.id}}</td>
<td>{{hero.name}}</td>
<td>{{hero.power}}</td>
<td><input type="checkbox"></td>
</tr>
</table>
</div>
<script>
const vm = new Vue({
el : '#app',
data : {
keyWord : '',
selectSort : 0,
heros : [
{'id': '001','name':'达尔文','power':'10000'},
{'id': '002','name':'达文西','power':'12000'},
{'id': '003','name':'古尔丹','power':'11000'},
{'id': '004','name':'萨尔','power':'15000'},
],
},
computed : {
newHeros (){
let newHeros = this.heros.filter(hero => hero.name.indexOf(this.keyWord) >= 0)
if(this.selectSort === 1){
// 排序:可遍历的对象.sort((a,b) => a.要比较的数据部分 - b.要比较的数据部分)
// sort方法会改变原数据的结构
// a - b :升序 b - a : 降序
newHeros.sort((a,b)=>a.power - b.power)
}else if(this.selectSort === 2){
newHeros.sort((a,b)=>b.power - a.power)
}
return newHeros
},
}
})
</script>
3.3 v-bind 动态修改标签原有属性的值
<HTML标签 v-bind:参数 = '表达式'>
- 参数在大部分情况下是该标签支持的属性名
- 重要:标签的冒号前后不能有空格
编译前:
<HTML标签 v-bind:参数 = '表达式'>
编译后:
<HTML标签 属性=‘表达式的执行结果’>
例如:
<a v-bind:href ='address'>网址链接</a>
编译后:
<a href = "https://www.baidu.com">网址链接</a>
- v-bind标签比较常用,可简化为:
<a v-bind:href ='address'>网址链接</a> <a :href ='address'>网址链接</a>
3.4 v-model 双向绑定表单value属性值
- 原型:
<input type="text" v-model:value="msg">
- 只能用于获取
<input><select><textarea>
标签的value
属性,所以可以省略value,简写为:
<input type="text" v-model="msg">
- 表单内容与组件双向绑定,当表单内容有变化时,v-model绑定的data中的属性的数据也会发生改变
v-model.number
修饰符number,可以让vue接收到的数据为数字,而不是字符串v-model.trim
修饰符trim,去除字符串开始和结尾的空格v-model.lazy
修饰符lazy,懒加载,用于文本域,作用:当焦点从文本域离开后,用户输入的文字vue才会接收到。如果不加lazy,则是用户输入一个字,vue就接收一个字
3.5 v-on 事件绑定
- 重点:
- 鼠标点击,键盘等事件绑定缩写
- “事件”参数 的传递
<!--
v-on:click 简写为 @click
v-on:keydown 简写为 @keydown
v-on:mouseover 简写为 @mouseover
@wheel 鼠标滚轮滚动事件
-->
<body>
<div id="app">
<!-- 1. js代码实现事件绑定 -->
<button onclick="hello1()">hello1</button>
<!-- 2. vue实现事件绑定 -->
<button v-on:click="hello2()">hello2</button>
<!-- 3. v-on可缩写为@,并且“()"也可以省略。 -->
<button @click="hello3">hello3</button>
<!-- 4. 默认会将点击事件作为参数传递到实例中,如果只传递“事件”这一个参数,则不能加() -->
<button @click="hello4">hello4</button>
<!-- 5.如果需要传递多个参数,使用$event占位符来传递“事件”这个参数, -->
<button @click="hello5($event ,'jack')">hello5</button>
</div>
<script>
function hello1(){
console.log('hello1');
}
const vm = new Vue({
el : '#app',
data : {
msg : 'hello2',
},
methods : {
hello2 : function(){
console.log('hello2');
},
// :function可不写
hello3 (){
console.log('hello3');
},
hello4 (e){
console.log(e);
},
hello5 (e,name){
console.log(e , name);
},
}
})
</script>
</body>
3.5.1 事件修饰符
- 事件修饰符的示例使用了下面的实例
const vm = new Vue({
el : '#app',
data : {
msg : '事件修饰符',
},
methods : {
san (){
console.log('最外层div');
},
er (){
console.log('中间的div');
},
yi (){
console.log('里面的button');
},
stopEvent(){
alert("阻止了a标签的默认行为(跳转到百度)")
},
testPssive(){
for(let i = 0;i < 100000; i ++){
console.log(this.msg);
}
}
}
- 默认情况下,事件发生时以冒泡形式传递,冒泡是从最内层到最外层
<div @click="san">
<div @click="er">
<button @click="yi">默认事件冒泡</button>
</div>
</div><br>
<!-- 结果:
里面的button
中间的div
最外层div
-->
- .stop 停止事件冒泡,事件不再向后传递
<div @click="san">
<div @click.stop="er">
<button @click="yi">停止事件冒泡</button>
</div>
</div><br>
<!--
结果:
里面的button
最外层div
-->
- .capture 事件捕获模式,捕获是从外层到内层
<!-- 事件捕获模式,示例1 -->
<div @click.capture="san">
<div @click.capture="er">
<button @click.capture="yi">事件捕获模式1</button>
</div>
</div><br>
<!--
结果:
最外层div
中间的div
里面的button
-->
<!-- 事件捕获模式,示例2,中间层先捕获了动作,然后是内层,冒泡到最外层 -->
<div @click="san">
<div @click.capture="er">
<button @click="yi">事件捕获模式2</button>
</div>
</div><br>
<!--
结果:
中间的div
里面的button
最外层div
-->
<!-- 事件捕获模式,示例3,最外层先捕获了动作,然后是中间层,最后轮到内层 -->
<div @click.capture="san">
<div @click.capture="er">
<button @click="yi">事件捕获模式3</button>
</div>
</div><br>
<!--
结果:
最外层div
中间的div
里面的button
-->
- .self 如果是“我自己元素”上发生事件就执行对应的程序,如果是别的元素传递过来的则不执行
<div @click="san">
<div @click.self="er">
<button @click="yi">.self只执行自己发生的事件</button>
</div>
</div><br>
<!--
结果:
里面的button
最外层div
-->
- .once 事件只执行一次
<!-- .once 事件只执行一次 -->
<div @click="san">
<div @click.once="er">
<button @click="yi">.once事件只执行一次</button>
</div>
</div><br>
<!--
连续点击两次button按钮,结果:
里面的button
中间的div
最外层div
里面的button
最外层div
-->
- .prevent 阻止事件的默认行为发生
<!-- .prevent 阻止事件的默认行为 -->
<a href="http://www.baidu.com" @click.prevent="stopEvent">prevent阻止事件的默认行为</a><br><br><br>
- .passive 立即执行事件的默认行为 @wheel滚动事件
<style>
.divList{
width: 300px;
height: 200px;
background-color: aqua;
overflow: auto;
}
.item{
width: 300px;
height: 200px;
}
</style>
// 滚动时运行的函数
testPssive(){
for(let i = 0;i < 100000; i ++){
console.log(this.msg);
}
}
<div class="divList" @wheel.passive="testPssive">
<div class="item">div1</div>
<div class="item">div2</div>
<div class="item">div3</div>
</div>
<!-- 结果:
@wheel滚动事件触发后,在滚动鼠标滚轮时,会产生卡顿,控制台一直输出
当@wheel带有事件修饰符.passive时,滚动鼠标滚轮图片会立即更新,无卡顿
-->
3.5.2 按键点击事件
链接
知识点:
event.key
触发事件的按键
event.target
触发事件的标签
event.target.value
如果触发事件的标签是input则返回input文本框中的内容
使用v-modle也能获取到input文本框中的内容
- 按键点击事件
1.1@keyup
按键抬起时执行函数
1.2@keydown
按键被按下时执行函数
1.3event.key
获得按键的值
示例:
<label>输入:<input type="text" @keyup="getInfo" v-modle="value"></label>
methods : {
getInfo(event){
this.result = event.key
}
}
- 按键修饰符
- ctrl、alt、shift、meta组合键的使用方法
- tab键只能在keydown事件触发
<label>回车键:<input type="text" @keyup.enter="getInfo"></label><br>
<label>回退键:<input type="text" @keyup.backspace ="getInfo"></label><br>
<label>删除键:<input type="text" @keyup.delete="getInfo"></label><br>
<!-- tab键只能触发keydown事件 -->
<label>tab键:<input type="text" @keydown.tab="getInfo"></label><br>
<!-- 四个特殊的按键
ctrl、alt、shift、meta
keydown事件:只要按下ctrl键,keydown事件就会触发
keyup事件:按下ctrl键,同时按下其他组合键,松开组合键之后,keyup事件才能触发
-->
<label>ctrl与c的组合键keydown:<input type="text" @keydown.ctrl="getInfo"></label><br>
<label>ctrl与c的组合键keyup:<input type="text" @keyup.ctrl.c="getInfo"></label><br>
3.5.3 事件回调函数中的this
- 重点:
- vue实例的方法中使用的
this
指的就是vue实例的对象自己 - 方法如果使用的是箭头函数 ,
this
指向的时window
- vue实例的方法中使用的
- 示例
<div id="app"> <h1 >{{count}}</h1> <button @click="count++">不调用函数</button> <button @click="add">调用函数</button> </div> <script> const vm = new Vue({ el : '#app', data : { count : 0, }, methods :{ add(){ this.count ++; // this.$data.count ++; // this._data.count ++; } } }) </script> // 结果 两个按钮都能实现<h1>标签内的数字加1
3.6 v-text、v-html
v-text
等同于标签属性innerText
v-html
等同于标签属性innerHtml
- 两个标签都会覆盖标签内原有的内容
- 示例:
<div v-text="msg">原有的内容</div>
<div v-html="msg">原有的内容</div>
msg : '<h1>新的内容</h1>'
<-- 结果:
<h1>新的内容</h1>
新的内容
-->
3.7 v-cloak、v-pre
v-cloak
:当vue.js文件或者vue实例没有加载完成前,页面会显示{{msg}},使用v-cloak指令后,在没有完成加载前页面上什么都不会显示v-pre
:不涉及vue的内容,就不会经过vue的渲染,直接显示在页面上,节省开销
<div id="app">
<!-- 当vue.js文件或者vue实例没有加载完成前,页面会显示{{msg}},
使用v-cloak指令后,在没有完成加载前页面上什么都不会显示 -->
<div v-cloak>{{msg}}</div>
<div v-pre>不涉及vue的内容,就不会经过vue的渲染,直接显示在页面上,节省开销</div>
</div>
<script>
setTimeout(()=>{
const vm = new Vue({
el : '#app',
data : {
msg : '延迟3秒加载',
}
})
},3000)
</script>
4 Vue实例可以访问哪些属性
- 以$开头的属性,可以看作是公开的属性,是给程序员使用的
- 以_开头的属性,可以看作是私有的属性,一般程序员很少用
- 通过vue的实例对象也可以访问原型对象的属性
4.1 Vue的实例对象如何访问data对象中的值
4.1.1 Object.defineProperty方法,给实例对象增加属性
- 作用:给某一个对象新增属性
Object.defineProperty(实例对象,'给实例新增的属性名称',
{
value : '属性的值',
wriitable :boolean //true:属性值可修改,false:不可修改
})
- 示例
<script>
let person = {}
Object.defineProperty(person,'name',{
value : 'zhangsan',
writable : true
})
</script>
// 结果
person.name
'zhangsan'
person.name = 'lisi'
'lisi'
person.name
'lisi'
- get与set方法
使用get和set方法时,不能使用配置属性value和writable
let person = {}
//临时变量
let temp
Object.defineProperty(person,'name',{
// value : 'zhangsan',
// writable : true,
get : function(){
console.log('@@ get方法执行了 @@');
return temp;
},
//set方法中val参数用来接收用户的赋值
set :function(val){
console.log('@@ set方法执行了 @@');
temp= val;
},
//该属性是否可遍历(可枚举、可迭代),默认:false
enumerable: true,
//该属性是否可以被删除,默认:false
configurable: true
})
在遍历person对象的属性时可以看到,在没有进行get或者set操作前,是无法获得到person对象的那么属性的
验证configurable
配置项
4.1.2 数据代理
-
Vue为什么要做数据代理? 通过Vue的实例直接访问data中的数据
-
通过代理对象proxy访问或修改目标对象target中的name属性
//目标对象 let target = { name : 'zhangsan' } //代理对象 let proxy = {} //代理对象新增的属性名,必须与目标对象的属性名相同 Object.defineProperty(proxy,'name',{ get : function(){ return target.name }, set : function(val){ target.name = val } }) //结果 target.name 'zhangsan' proxy.name 'zhangsan' proxy.name = 'lisi' 'lisi' target.name 'lisi'
5 computed:计算属性
链接
-
概念:基于现有的属性,计算出一个新的属性,依据属性的变化,自动更新。
-
作用:减少重复计算,增加代码运行效率。
如使用method中的方法来计算,当程序多次用到同一个方法的计算结果时,会调用多次方法。 -
使用方法:配置computed,
B属性名(){有关A属性的代码}
,在HTML中使用B属性 -
computed中属性的两种调用机制:
- 在第一次调用计算属性中的属性时
- 计算属性中关联的Vue中其他属性发生改变时
-
computed的属性的set方法很少用,有简写形式
-
computed中属性的简写形式很像methods中的方法,所以很容易和methods中的方法在调用的时候弄混,关键就是有没有括号
- computed中属性的使用方法:{{computed的属性名}}
- methods中的方法使用:{{methods的方法()}}
-
示例:
<div id="app"> <label>输入字符串:<input type="text" v-model="info"></label><br> <label>反转字符串:{{reversal}}</label><br> <label>反转字符串:{{reversal}}</label><br> <label>反转字符串:{{reversal}}</label><br> <label>反转字符串:{{reversal}}</label><br> <label>反转字符串:{{reversal}}</label><br> <h1>computed简写形式</h1> <label>反转字符串:{{reversal_1}}</label><br> <label>反转字符串:{{reversal_1}}</label><br> <label>反转字符串:{{reversal_1}}</label><br> <label>反转字符串:{{reversal_1}}</label><br> <label>反转字符串:{{reversal_1}}</label><br> </div> <script> const vm = new Vue({ el : '#app', data : { info : 'abc', }, computed : { reversal: { get(){ console.log('执行计算属性的get方法'); return this.info.split('').reverse().join('') }, set(val){ console.log(val); } }, // 计算属性的set方法很少用,计算属性的简写: reversal_1(){ return this.info.split('').reverse().join('') } }, }) </script> //结果: 在程序中5次调用reversal方法,但是只会在第1次运行reversal方法或者info属性值发生改变时调用reversal方法,其余4次都时从缓存中读取,提升了程序的运行效率
6 watch:侦听属性
链接
- 作用: 某一个属性值变化后,可获得变化前后的值
- 监听哪个属性,就将该属性名作为监听的属性名
- handler的写法是固定的,里面两个参数,第一个参数是属性现在的值,第二个参数是属性原来的值
- immediate的值默认是false,在第一次进入页面页面时,如果没有发生数据变化watch并不会立即监听只有发生数据改变,hander才会有操作,但是如果将immediate设置为true,在第一次进入页面时就会绑定值.
<div id="app">
<label>输入:<input type="text" v-model="num"></label><br>
</div>
<script>
const vm = new Vue({
el : '#app',
data : {
num : '',
},
watch : {
// 监视哪个属性,就用属性名作为监视属性的名
num : {
// immediate为true:第一次加载组件就开始监听,为false,加载完成后,以后有变化再监听
immediate : true,
// handler方法是固定写法,里面两个参数,第一个参数是属性现在的值,第二个参数是属性原来的值
handler(newValue, oldValue){
console.log('原来的值'+oldValue+' '+'现在的值'+newValue);
}
},
// 如果没有设置项可以用简写形式
num(newValue, oldValue){
console.log('原来的值'+oldValue+' '+'现在的值'+newValue);
}
}
})
</script>
6.1 深度监听
- 深度监听:
deep : true
- 使用深度监听时不能使用简写形式
<div id="app">
<label>深度监听:<input type="text" v-model="a.b.c"></label>
</div>
<script>
const vm = new Vue({
el : '#app',
data : {
a : {
b : {
c : ''
}
},
},
watch : {
// 监听最内层c,注意要加单引号
'a.b.c'(){
// console.log('c的值有变化');
},
// 深度监听:不能使用简写形式
a : {
deep : true,
handler(){
console.log('深度监听');
}
}
}
})
</script>
6.2 深度监听方式的不同,获得的值不同
下面是data中属性的结构
data : {
a : {
b : {
c : ''
}
},
- 当使用下面这种配置deep时
vm.$watch('a',{
deep : true,
handler (newA,oldA){
console.log(oldA.b.c,newA.b.c);
}
})
//结果:
旧的c的值与新的c的值相同都为新c的值
这是因为handler中的两个参数传递的都是a这个对象,而a中只有地址
- 当使用a.b.c来监听c的值时
vm.$watch('a.b.c',{
deep : true,
handler (newC,oldC){
console.log(oldC,newC);
}
})
//结果
旧c的值与新c的值不同
handler中的两个参数就是c的新值和旧值
6.2 后期添加监视
语法:vm.$watch('监视属性的名',{ 配置项,handle(新值,旧值){执行语句}})
- 示例见1.6.1的内容
7 Vue中的this
Vue中的this
8 class、style绑定
8.1 class绑定
- 数组绑定是最常用的绑定方式,适用于名字不确定,数量也不确定的情况
- 对象绑定适用于,名字和数量都确定,但不确实是否使用
- 重要,所有class的属性名在vue中最好都加单引号
<style>
.static {
width : 100px;
height: 100px;
border: 1px;
}
.active{
background-color: aquamarine;
}
.text-danger{
color: red;
}
</style>
<div id="app">
<div class="static active text-danger">{{msg}}</div><br>
<!-- 数组绑定是最常用的绑定方式,适用于名字不确定,数量也不确定的情况 -->
<div class="static" :class="classArray">{{msg}}数组绑定</div><br>
<!-- 对象绑定适用于,名字和数量都确定,但不确实是否使用 -->
<div class="static" :class="classObj">{{msg}}对象绑定</div><br>
</div>
<script>
const vm = new Vue({
el : '#app',
data : {
msg : 'class绑定之',
classArray : ['active', 'text-danger'],
classObj : {
'active' : true,
'text-danger' : true,
}
}
})
</script>
8.2 style绑定
- 注意vue中无论是数组还是对象形式,属性和值最好都加引号
<style>
.static{
border: 1px solid black ;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div id="app">
<!-- 静态写法 -->
<div class="static" style="background-color: aquamarine;color: #000;">基本写法</div><br>
<!-- 字符串形式 -->
<div class="static" :style="styleString">style绑定字符串形式</div><br>
<!-- 对象形式 ,无论是key还是value都需要加引号-->
<div class="static" :style="styleObject">style绑定对象形式</div><br>
<!-- 数组形式,数组中的style样式是以对象形式存在的 -->
<div class="static" :style="styleArray">style绑定数组形式</div><br>
</div>
<script>
const vm = new Vue({
el : '#app',
data : {
msg : 'style绑定',
styleString : 'background-color: aquamarine;color: #000;',
styleObject : {
'background-color' : 'aquamarine',
'color' : '#000'
},
styleArray : [
{'background-color' : 'aquamarine'},
{'color' : '#000'}
]
}
})
</script>
9 创建表单数据
知识点:
-
v-model.number
修饰符number,可以让vue接收到的数据为数字,而不是字符串 -
v-model.trim
修饰符trim,去除字符串开始和结尾的空格 -
v-model.lazy
修饰符lazy,懒加载,用于文本域,作用:当焦点从文本域离开后,用户输入的文字vue才会接收到。如果不加lazy,则是用户输入一个字,vue就接收一个字 -
阻止表单的提交:
4.1第一种方法:<button @click.prevent="send">注册</button>
阻止button点击的默认行为发生,调用vue中的相关方法
4.2第二种方法:<form @submit.prevent="send">
阻止表单的submit事件,执行vue中的相关方法 -
JSON.stringify(this.user)
:将数据对象json化
<body>
<div id="app">
<!-- 阻止表单提交,第二种方法,阻止表单的submit事件,执行vue的send方法 -->
<form @submit.prevent="send">
<h1>{{msg}}</h1>
<!-- `v-model.number`修饰符number,可以让vue接收到的数据为数字,而不是字符串 -->
<label>用户名:<input type="text" v-model.trim="user.username"></label><br>
<label>密码: <input type="password" v-model="user.password" /></label><br>
<!-- `v-model.trim`修饰符trim,去除字符串开始和结尾的空格 -->
<label>年龄:<input type="number" v-model.number="user.age"></label><br>
<label>
性别:<input type="radio" name="gender" value="1" v-model="user.gender">男
<input type="radio" name="gender" value="0"v-model="user.gender">女
</label><br>
<label>爱好:
<!-- checkbox作为复选框时,需指定每个选项的value值,v-model的结果是一个数组 -->
<input type="checkbox" value="travel"v-model="user.hobby">运动
<input type="checkbox" value="sport"v-model="user.hobby">旅游
<input type="checkbox" value="sing"v-model="user.hobby">唱歌
</label><br>
<label>
学历:
<select v-model="user.education">
<option value="">请选择学历</option>
<option value="zk">大专</option>
<option value="bk">本科</option>
<option value="ss">硕士</option>
</select>
</label><br><br>
<label>简介:
<textarea cols="30" rows="10" v-model.lazy="user.introduce"></textarea>
</label><br>
<label></label>
<!-- checkbox作为单选框时不需要指定value的值,选中则value为true,没有选中则value为false -->
<input type="checkbox" v-model="user.agreement">阅读并接收协议</label><br>
<!-- 表单的提交:第一种方法,阻止button点击的默认行为发生,调用vue中的send方法 -->
<!-- <label><button @click.prevent="send">注册</button></label><br> -->
<label><button >注册</button></label><br>
</form>
</div>
<script>
const vm = new Vue({
el : '#app',
data : {
msg : '收集表单数据',
user : {
username : '',
password : '',
age : '',
gender : 1,
hobby : [],
education : '',
introduce : '',
agreement : '',
},
},
methods :{
send(){
console.log(JSON.stringify(this.user));
}
}
})
</script>
10 directives:自定义指令
- 自定义指令分为全局指令和局部指令,定义时的代码位置不同。全局指令写在vue实例的外部
- 自定义指令可以使用函数式和对象式,两者区别在于函数式指令在dom与指令初次绑定时和模板重新解析时调用,共调用两次。对象式定义的指令在元素被渲染到页面后还会调用一次,一共3次。
- 函数式和对象式在什么情况下使用?函数式定义的指令针对操作dom自身属性时使用,对象式指令适用于操作dom的父、子、兄弟等其他节点时使用
- 自定义指令的参数:第一个参数
ele
就是dom本身,第二个参数binding
(绑定关系),包含了几乎除dom外其他有关的所有数据,例如:指令名(v-bind-color
),表达式(username
),表达式的值(123
),方法名('bind-color'
)等 - 自定义指令的
this
,都指向window
- 局部指令的配置项:
directives
,方法名就是标签内定义的名字,去了v-
后,记得加括号。例如:标签内的属性名v-bind-color1
那么方法名就是bind-color1
- 全局指令使用
directive
,没有s
<div id="app">
<!-- 分别由局部指令的函数式和对象式完成 -->
<div>
<div v-bind-color="username"></div>
</div>
<div>
<input type="text" v-model-color="username">
</div>
<!-- 分别由全局指令的函数式和对象式完成 -->
<div>
<div v-bind-color1="username"></div>
</div>
<div>
<input type="text" v-model-color1="username">
</div>
</div>
<script>
// 全局指令,函数式
Vue.directive('bind-color1', function (ele, binding) {
ele.innerText = binding.value;
ele.style.color = 'red'
})
// 全局指令,对象式
Vue.directive('model-color1', {
// 当使用该指令时,将调用该函数
bind(el, binding) {
el.value = binding.value;
},
// 元素已经被插入页面后调用
inserted(ele, binding) {
ele.parentNode.style.backgroundColor = 'blue';
},
// 模板中心解析后,将调用该函数
update(el, binding) {
el.value = binding.value;
}
})
const vm = new Vue({
el: '#app',
data: {
username: "123",
},
directives: {
// 函数式自定义指令,缺点:在代码执行阶段还没有渲染页面,所以无法找到除自己外的其他元素
// 参数ele就是dom标签元素本身
// 参数binding是绑定关系的一个对象,对象里面包含指令名(v-bind-color),表达式(username),表达式的值(123),方法名('bind-color')等
'bind-color'(ele, binding) {
console.log(binding);
ele.innerText = binding.value;
ele.style.color = 'red'
},
// 对象式自定义指令
'model-color': {
// 当使用该指令时,将调用该函数
bind(el, binding) {
el.value = binding.value;
},
// 元素已经被插入页面后调用
inserted(ele, binding) {
ele.parentNode.style.backgroundColor = 'blue';
},
// 模板重新解析后,将调用该函数
update(el, binding) {
el.value = binding.value;
}
}
}
});
</script>
11 组件的使用
组件的使用分三步:
- 创建组件。重要提示:
- template中只能包含一个根元素。如果有多个元素,使用v-if、v-else-if将他们连起来
- data必须使用函数,不能使用对象的形式
const vc = Vew.extend({
template : `
//Html 部分
`,
data : function(){
return {
// 这里的内容与vue的data中内容相同
}
},
})
- 注册组件
2.1 局部注册,在vue实例中增加配置项
components :{
组件的名字 : vc
}
2.2 全局注册`Vue.component("组件的名字",vc)`,示例:`Vue.component(vc,vc)`
-
使用组件
在标签中引用<组件的名字></组件的名字>:<vc></vc>
<body>
<div id="app">
<login></login>
</div>
<script>
const login = Vue.extend({
template: `
<div>
<input type="text" v-model="username">
<input type="password"v-model="password">
<button @click="login">登录</button>
</div>
`,
// data必须使用函数,不能使用对象的形式
data: function(){
return {
username: '',
password: ''
}
},
methods: {
login() {
console.log(this.username, this.password)
}
}
})
const vm = new Vue({
el: '#app',
components: {
login: login
}
})
</script>
</body>
11.1 组件的嵌套
使用组件时,一定将3个步骤落实到位,1.创建,2. 注册,3. 使用
<body>
<div id="root"></div>
<script>
// 使用组件的3个步骤,1.创建,2 注册,3 使用,一定要把这3个步骤落实
const x1 = Vue.extend({
template: '<div>x1组</div>',
})
const y1 = Vue.extend({
template: '<div>y1组件</div>',
})
const x = Vue.extend({
template: `
<div>
<div>x组件</div>
<x1></x1>
</div>
`,
components: {
x1: x1
}
})
const y = Vue.extend({
template: `
<div>
<div>y组件</div>
<y1></y1>
</div>
`,
components: {
y1: y1
}
})
const app = Vue.extend({
template: `
<div>
<div>app组件</div>
<x></x>
<y></y>
</div>
`,
components: {
x: x,
y: y
}
})
const root = new Vue({
el: '#root',
template : `<app></app>`,
components: {
app
}
});
</script>
</body>
结果:(浏览器的Vue Devtool插件的截图)
12 $nextTick:页面渲染完成后执行
链接
vue执行完渲染后会执行this.nextTick()里面的callback函数。
// $nextTick:当代码执行完毕后,才开始执行函数中的代码
this.$nextTick(function(){
this.$refs.inputInfo.focus()
})
13 js中的函数reduce
链接
作用:参数a,从0开始计数,箭头函数的返回值就是a下一次的值;参数b是遍历list的对象
this.list.reduce((a, b) => a + (b : (a + 1) : 0), 0);
// this.list.reduce((a, b是list的遍历对象) => a + (b : (a + 1) : 0), a的起始值);