笔记整理来源于对B站上coderwhy老师的Vuejs教程的思考和回顾。
视频链接为:https://www.bilibili.com/video/BV17j411f74d?p=62
零、起步 Vuejs介绍篇
安装Vue的方式
创造一个Vue实例对象的语法格式
<script src="../js/vue.js">{{item}}</script>
<script>
const app = new Vue({
el:'#app', //用于挂载要管理的元素 string
data:{ //data属性:通常用于存储一些数据 Object|Function
message:''
}
methods:{ //定义属于Vue的一些方法,可以在其他地方调用,也可以在指令中使用
}
})
</script>
MVVM模型
官网的MVVM模型图例
各层级的主要功能详解
- View层
- 视图层
- 在前端开发中,通常就是DOM层
- 主要的作用是给用户展示各种信息
- 在View层中,只是负责对数据进行格式化展示,在Vue中有模板语法,用两个大括号来显示data中的值
- Model层
- 数据层
- 数据可能是我们固定的死数据,更多的是来自我们服务器,从网络上请求下来的数据
- 在MVVM中,Model层仅仅是存储数据就够了,对于数据的处理并不在Model层,所以在Vue中,只是一个类似于json对象的东西
- VueModel层(整个模式的重点)
- 视图模型层
- 视图模型层是View和Model沟通的桥梁
- 一方面实现了Data Binding,也就是数据绑定,将Model的改变实时的反映到View中
- 另一方面它实现了DOM Listener,也就是DOM监听,当DOM发生一些事件(点击、滚动、touch等)时候,可以监听到,并在需要的情况下改变对应的Data。
在Vue中,使用了双向绑定技术,就是View的变化能够实时让Model发生变化,而model的变化也能够实时的更新到View中。不同的MVVM框架,实现双向数据绑定的技术不同,Vue中主要采用数据劫持&发布-订阅模式的方式,通过ES5提供的Object.defineProperty()方法来劫持各属性的getter、setter,并在数据发生变动时通知给订阅者,触发相应监听回调。并且由于是在不同数据上触发同步,可以精确的将变更发送给绑定的视图,而不是对所有的数据都执行一次检测。
实现双向数据绑定大致可以划分为三个模块:Observer、Compile、Watcher。
- Observer 数据监听器
负责对数据对象的所有属性进行监听(数据劫持),监听到数据发生变化后通知订阅者 - Compiler 指令解析器
扫描模板,并对指令进行解析,然后绑定到指定事件 - Watcher 订阅者
关联Observer和Compile,能够订阅并收到属性变动的通知,执行指令绑定的相应操作,更新视图。Update()是它自身的一个方法,用于执行Compile中绑定的回调,更新视图
MVC、MVP、MVVM特点及三者区别
参考链接:https://blog.csdn.net/Ancecis/article/details/104204326
Vue的生命周期
概念:实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载DOM、渲染→更新→渲染、销毁等一系列过程,通俗的称就是Vue实例从创建到销毁的过程,也就是生命周期。
实例生命周期钩子:每个Vue实例在被创建时都需要经过一系列的初始化过程,同时在这个过程就会运行一些叫做生命周期钩子的函数,给用户在不同阶段添加自己代码的机会。有8个声明周期钩子函数:beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed
参考文档:https://blog.csdn.net/CC_Together/article/details/105594222
模板语法
- 插值操作:{{}}
- 数据绑定最常见的形式就是Mustache语法{{}}的文本插值
- Mustache标签会替代对应数据对象上的msg属性的值,无论何时,绑定的数据对象上msg的属性发生了改变,插值处的内容就会实现更新。
- 通过使用v-once指令,也能够执行一次性的插值操作,当数据改变时候,插值处的内容不会更新。
<span>Message:{{ msg }}</span>
<span v-once>这个将不会改变:{{ msg }}</span>
- 原始HTML:v-html
- 将请求得到的数据按照HTML格式进行解析并显示对应的内容
- 该指令后面往往会跟上一个string类型,会将string的html解析出来并进行渲染
<h2>{{url}}</h2>
<h2 v-html="url"></h2>
<script>
const app = new Vue({
el:'#app',
data:{
url:'<a href="http://www.baidu.com">百度一下</a>'
}
});
</script>
- v-text、v-pre、v-cloak
- v-text:与Mustache相似,都是用于数据显示在界面中,通常情况下,只接受一个string类型
<!-- 假设message中存储的数据为 你好啊-->
<h2>{{message}}, 李银河!</h2>
<h2 v-text="message">, 李银河!</h2>
- v-pre:用于跳过这个元素和它的子元素的编译过程
<h2>{{message}}</h2>
<h2 v-pre>{{message}}</h2>
- v-cloak:在vue解析之前,属性中会含有属性v-cloak,等代码解析后自动删除v-cloak中的样式
<style>
[v-cloak] {
display: none;
}
</style>
<div id="app" v-cloak>
<h2>{{message}}</h2>
</div>
- 绑定属性:v-bind
- 动态绑定属性
<!-- 动态绑定图片地址和网页链接地址,随着用户的输入进行改变-->
<img v-bind:src="imgURL" alt="">
<a v-bind:href="aHref">百度一下</a>
<!--语法糖的写法 以后都用这种写法-->
<img :src="imgURL" alt="">
<a :href="aHref">百度一下</a>
- 动态绑定class对象:对象语法/数组语法方式
<!--对象语法的用法-->
<div id="app">
<!--当下面的布尔值为true的时候,这个类就会被添加到这个class上-->
<!--<h2 v-bind:class="{类名1: true, 类名2: boolean}">{{message}}</h2>-->
<h2 class="title" v-bind:class="{active: isActive, line: isLine}">{{message}}</h2>
<h2 class="title" v-bind:class="getClasses()">{{message}}</h2>
<button v-on:click="btnClick">按钮</button>
</div>
<!-- 数组语法的用法 更常用-->
<!--如果为'active'则识别为字符串active-->
<h2 :class="['active','line']"> Hello World</h2>
<!--如果为active则识别为变量,可动态赋值-->
<h2 :class="[active,line]"> Hello World</h2>
<!--和普通的类同时存在,并不会冲突-->
<h2 :class="title" :class="['active','line']"> Hello World</h2>
- 动态绑定style:对象语法、数组语法
(写CSS属性名的时候采用fontSize/font-size的写法)
<!-- 对象语法的绑定格式 -->
<!--<h2 :style="{key(css属性名): value(属性值)}">{{message}}</h2>-->
<!--'50px'必须加上单引号, 否则是当做一个变量去解析-->
<!--<h2 :style="{fontSize: '50px'}">{{message}}</h2>-->
<!--finalSize当成一个变量使用-->
<!--<h2 :style="{fontSize: finalSize}">{{message}}</h2>-->
<h2 :style="{fontSize: finalSize + 'px', backgroundColor: finalColor}">{{message}}</h2>
<h2 :style="getStyles()">{{message}}</h2>
<!-- 数组语法的绑定格式 -->
<div id="app">
<h2 :style="[baseStyle, baseStyle1]">{{message}}</h2>
</div>
一、计算属性(computed)
1.1 计算属性的基本使用
- 概念
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。所以我们可以在Vue实例中引出一个计算属性computed{} 用于对复杂逻辑的描述 - 计算属性的setter和getter
- 一般情况下,我们默认只有getter,我们通常只是使用getter来读取我们的属性
<script>
const app = new Vue({
el:'#app',
data:{
firstName: 'Kobe',
lastName: 'Bryant'
},
computed:{
fullName:function(){
return this.firstName + ' ' +this.lastName //{{fullName}} 返回值为Kobe Bryant
}
}
})
</script>
- 但是实际上每个计算属性都包含一个getter和一个setter
computed:{
fullName:{
set:function(newValue){
const names = newValue.split(' ');
this.firstName = names[0];
this.lastName = names[1];
}
get: function(){
return this.firstName + ' ' + this.lastName
}
}
}
1.2 计算属性和methods对比
- 我们可以将同一函数定义为一个方法而不是一个计算属性,计算属性里的定义的值相当于一个属性,可以直接用{{}}方式读出
- 计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。— 多次访问某个变量未改变的计算属性会立即返回之前的计算结果,而不必再次执行函数,而调用方法总会再次执行函数
二、事件监听(v-on)
2.1 事件监听基本使用
v-on的语法糖:@
<button @click="increment">+</button>
<button @click="decrement">-</button>
2.2 事件监听的参数问题
- 情况一:如果该方法不需要额外参数,那么方法后面的()可以不添加,但是如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去
- 情况二:如果需要同时传入某个参数,同时需要event时,可以通过$event传入事件
2.3 修饰符
- .stop:阻止事件冒泡
- .prevent:阻止自动提交
<input type="submit" value="提交" @click.prevent="submitClick">
- .{keyCode | keyAlias}:只当事件是从特定键触发时才触发回调
<input type="text" @keyup.enter="keyUp">
- .native:监听组件根元素的原生事件
- .once:只触发一次回调
三、条件判断(v-if)
3.1 v-if / v-else-if / v-else
v-if的原理:后面的条件为false时,对应的元素以及其子元素不会渲染(也就是根本不会有对应的标签出现在DOM中)
<h2 v-if="score>=90">优秀</h2>
<h2 v-else-if="score>=80">良好</h2>
<h2 v-else-if="score>=60">及格</h2>
<h2 v-else>不及格</h2>
3.2 条件渲染案例
<div id="app">
<span v-if="isUser">
<!--点击用户账号文字 可以自动聚焦到for对应的位置 也就是输入框-->
<label for="username">用户账号</label>
<!-- 为了避免复用:之前输入的值仍存在输入框中,可以设置key作为标识-->
<input type="text" id="username" placeholder="用户账号" key="username">
</span>
<span v-else>
<label for="email">用户邮箱</label>
<input type="text" id="email" placeholder="用户邮箱" key="email">
</span>
<button @click="isUser = !isUser">切换类型</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isUser: true
}
})
</script>
3.3 v-show
- 与v-if的区别:当v-if 的条件为false时候,不会有对应的元素在DOM中,而v-show当条件为false时,仅仅是将元素的display属性设置为none。
- 开发中选择依据:当需要再显示与隐藏之间切片很频繁时,使用v-show,当只有一次切换时,通过使用v-if。
四、循环遍历(v-for)
4.1 遍历数组
语法格式如下
<ul>
<!-- 假设movies为Vue实例对象data中的一个数组-->
<!--不需要使用索引值时写法 -->
<li v-for="item in movies">{{item}}</li>
<!-- 需要获取索引值时写法-->
<li v-for="(item,index) in movies">{{index+1}}.{{item}}</li>
</ul>
4.2 遍历对象
- 如果只是获取一个值,那么获取到的时value
<li v-for="item in info">{{item}}</li>
- 如果要获取key和value
<li v-for="(value, key)" in info>{{value}}-{{key}}<li>
- 如果要获取key、value、index
<li v-for="(value, key, index)" in info>{{value}}-{{key}}-{{index}}<li>
官方推荐使用v-for时候最好给对应的元素或者组件加上key属性,这样diff算法就可以正确识别此节点,找到正确位置区插入新的节点,可以提高插入节点引起更新时的性能
4.3 数组方法的响应式
- 当在数组中删除或插入元素的时候,能够引起DOM更新的方法有:push、pop、shift、unshift、splice、sort、reverse
- 当在数组中修改元素时,不能引起dom更新
for循环的三种常用写法
//假设已经知道一系列书(以数组形式存储books[]),其单价this.books[i].price和本数this.book[i].count,写出计算书的总价totalPrice的方法
computed:{
totalPrice1(){
let totalPrice = 0;
for(let i = 0; i <this.books.length;i++){
totalPrice += this.books[i].price * this.books[i].count
}
return totalPrice
},
//for (let i in/of this.books)
totalPrice2(){
let totalPrice = 0;
for (let i in this.books) {
totalPrice += this.books[i].price * this.books[i].count
}
return totalPrice
},
//for(let item of this.books)
totalPrice3(){
let totalPrice = 0;
for(let item of this.books){
totalPrice += this.books[i].price * this.books[i].count
}
}
}
三个高阶函数filter、map、reduce
- filter: filter中的回调函数有一个要求,必须返回一个boolean值,当返回true时,函数内部会自动将这次回调的n加入到新的数组中;当返回false时,函数内部会过滤掉这次的n
let newNums = nums.filter(function(n)){
return n < 100; //新数组存储为旧数组中小于100的数
}
- map:依次对数组中的数进行某个操作(比如每项同时扩大为原来的两倍)
let new2Nums = newNums.map(function (n){
return n * 2 //将数组中的数乘以2放入新的数组中
}),
- reduce:对数组中的所有内容进行汇总,要么逐项相加/相乘
//语法格式:数组名.reduce(function(preValue, n){},0)
//当为元素数组时:写n 当为对象组成的数组时:写对象名
let total = new2Nums.reduce((function(preValue, n){
return preValue + n //返回数组中所有数的总和
//return preValue * n
//返回数组中所有数相乘的乘积
},0)
- 箭头式编程写法
let total = nums.filter(n => n < 100)
.map(n => n * 2).reduce((pre, n)
=> pre + n); //依次对num数组进行以下操作:筛选小于100的项→所得的每个项乘二→将所有项相加
五、书籍购物车案例
六、v-model的使用
6.1 v-model的基本使用
- 基本概念:表单控件在实际开发中是非常常见的,特别对于用户信息的提交,需要大量表单,使用v-model指令来实现表单元素与数据的双向绑定。
- v-model其实是一个语法糖,背后本质上是包含两个操作:v-bind绑定一个value属性、v-on指令给当前元素绑定input属性
- 语法格式如下
<input type="text" v-model="message">
6.2 v-model和radio/checkbox/select
v-model结合radio
<div id="app">
<label for="male">
<!--value获取属性值,v-model通过绑定sex
实现动态绑定选项实现数据保存在app的表单数据中-->
<input type="radio" id="male" value="男" v-model="sex">男
</label>
<label for="female">
<input type="radio" id="female" value="女" v-model="sex">女
</label>
<h2>您选择的性别是: {{sex}}</h2>
</div>
v-model结合checkbox
- 单选框:v-model即为布尔值,input的value不影响v-model的值
<input type="checkbox" id="agree" v-model="isAgree">同意协议
- 多选框:当是多个复选框时,因为可以选中多个,所以对应的data中属性是一个数组,当选中某一个时,就会将input的value添加到数组中
<!-- 遍历originHobbies数组中的每一个项-->
<label v-for="item in originHobbies" :for="item">
<input type="checkbox" :value="item" :id="item" v-model="hobbies">{{item}}
</label>
v-model结合select
- 和check一样,select也分为单选和多选情况
- 单选语法格式为
<select name="abc" v-model="fruit">
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
</select>
- 多选语法格式为
<select name="abc" v-model="fruits" multiple>
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
</select>
- 值绑定:真实开发中,input的值大多是从网络获取或定义在data中的,我们需要动态的给value赋值
<label v-for="item in 可选数组列表名" :for="item">
<input type="checkbox" :value="item" :id="item" v-model="">{{选中的项组合的数组名}}</label>
6.3 修饰符
- lazy修饰符:默认情况下,v-model默认是在input事件中同步输入框的数据的,也就是说一旦有数据发送改变对应的data中的数据就会自动发送改变,lazy修饰符可以让数据在失去焦点或者回车时才会更新。
- number修饰符:默认情况下,在输入框中无论我们输入的是数字还是字母,都会被当作字符串类型进行处理,但是如果我们喜欢处理的是数字类型,最好直接将内容当作数字处理,number修饰符可以让我们在输入框中输入的内容自动转换成数字类型。
- trim修饰符:如果输入的内容首位有很多空格,通常我们希望将其去除。trim修饰符可以过滤内容左右两边的空格。
<input type="text" v-model.lazy="message">
<input type="number" v-model.number="message">
<input type="text" v-model.trim="message">