Vue2基础3
条件渲染
案例:如图
使用v-if
1 | <div id="app"> |
使用v-show
1 | <div id="app"> |
区别
1 | 1. v-show的原理是将被此指令标记的DOM元素的display属性设置为none,从而实现隐藏的效果 |
列表渲染
案例:将数组数据展示在页面上
1 | data(){ |
使用v-for指令
1 | <ul> |
这样就完成了最基本的遍历,如果我需要得到每一次遍历的索引,只需要加入一个形参即可
1 | <ul> |
OK,这里其实遗漏了一个很重要很重要的一个属性key
,这个key
就是每一个节点的标识,所以可以直接使用数组每一个对象的id
属性,或者是index
1 | <ul> |
这个key是干嘛的呢?这就要好好扒一扒了,来吧,整活!
虚拟DOM的DIFF算法
啥啊这是,怎么从key直接跳到了什么虚拟DOM的DIFF算法了?走错片场了?
没有没有,要解释key就要先知道这个知识
现在的代码,很简单,就是比刚刚多了一个添加一个人的按钮和一个input框
1 | <div id="app"> |
说明问题
然后点击添加一个人,你会发现一个很严重的错误,输入塌陷
加入:key="index"
之后,一样出现这个错误
加入:key="item.id"
之后,我们发现,这个错误就消失了
既然意识到了错误和解决错误的方法,那我们就来好好捋一下为什么,下面看图,图有点乱,请仔细观看
key为index的情况
解释几个点吧:
1、粉色的×表示匹配失败,不可以复用,蓝色的√表示匹配成功,可以复用
2、左下角的橙色的删除号表示该元素直接删除
3、下半部分的橙色箭头表示直接复用之前生成的真实DOM节点
4、左半部分的绿色箭头表示需要从虚拟节点重新生成真实DOM节点
key为id的情况
key不写的情况
如果不写key的话,Vue默认将index作为key,所以这种情况和key为index的情况是一样的
总结
1 | 1、key的作用 |
列表过滤
需求:输入姓关键词,回车出现名字中带有该关键词的
1 | <div id="app"> |
列表排序
1 | <button @click="sortByAge">按年龄排序</button> |
修改列表第一个人的信息(奏效)
1 | <button @click="updatePerson">修改第一个人的年龄为20</button> |
彻底修改列表一个人的信息(失效)
1 | <button @click="updatePersonComplete">彻底修改一个人的信息</button> |
为什么这种方式修改数据,Vue没有检测到呢?
这就要讲到Vue监测数据变化(响应式)的原理了
响应式原理
之前我在讲数据代理的时候,其实已经讲到了Vue响应式的原理,现在我们来正式给小伙伴讲一讲
Vue监测数据分为两种,一种是数组,还有一种是对象。我们先从监测对象开始,然后再讲监测数组。
监测对象
前期准备
1 | <div id="app"> |
我们先来回顾一下数据代理是什么
先输出一下vm
对象
我们在data
中配置的对象先经过Vue
加工变成Observer
对象
然后将其放到vm
对象上的_data
属性中
然后将_data
中的数据全部代理到vm
对象上
让我们可以直接使用{{}}
读取vm
身上的属性
这就是数据代理
我们修改了vm
身上的属性实际上修改的是_data
中的数据 , 然后页面就更新成了修改后的新的数据
或者直接修改_data
中的数据,页面也会更新为修改后的数据
这样看来,响应式数据的原理是在_data
中.还记得我之前提到的数据劫持吗?
Vue的响应式就是通过数据劫持来实现的,而数据劫持又是通过Object.defineProperty
实现的,_data
的每一个属性都有一个setter函数,当_data
中任何一个数据
发生了改变,都会走这个setter方法,那么在这个时候,我就可以执行一遍重新渲染页面的方法,从而使得页面数据更新
监测数组
我们先来观察一下_data
中的hobbies数组的样子,我们发现它没有给每一个元素设置一个getter/setter,那它是怎么实现响应式的呢
这里就不绕弯了
Vue里面对于数组的监测是
通过包装数组方法,先对页面进行更新,然后再调用原生的数组上的方法对数组进行更改
有以下这几种
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
Vue中的push不是原生的push
所以只有当你使用以上这些方法的时候,Vue才会监测到,然后对页面进行更新,这就解释了先前的那个案例,直接将数组第一个元素替换的时候,Vue并没有监测到.
但如果数组元素是对象,它一样还是会有getter/setter
过滤器
功能:先将数据作出处理再将数据进行显示
案例:显示格式化后的时间
1 | <div id="app"> |
以上这个过滤器叫局部过滤器,还有一种过滤器,叫全局过滤器
1 | <div id="app"> |
注意点:过滤器不是必要的,因为我们使用计算属性或者方法都可以实现,这只是一种方式
自定义指令
指令是什么?
指令就是v-on开头的一些语法,就是自己封装一些逻辑
需求1:定义一个v-big指令,会把绑定的数值放大10倍。
1 | <div id="app"> |
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。
1 | <div id="app"> |
这两个都是局部指令,我们来看看全局指令
1 | Vue.directive('fbind',{ |
注意点:
1 | 指令定义时不加v-,但使用时要加v-; |
生命周期
定义:Vue中每一个生命周期都对应着一个钩子(函数),当Vue走到该生命周期阶段的时候,就会自己调用该钩子。
黄色的标签是我加的注释,其他的流程都是从Vue官网查看的
最常用的就是mounted
和destoryed
一般在mounted
钩子中初始化数据(Ajax请求),在destoryed
钩子中删除定时器,解绑自定义事件等收尾工作
组件
模块化的概念
如果所有的js代码都在一个文件中,那么后期维护和更新会非常吃力。所以就有了模块化的概念了,这里可以看看我之前写的JavaScript的模块化规范
组件的定义
用来实现局部功能效果的所有代码和资源的集合(HTML、CSS、JavaScript)
传统开发
我们先来看看传统开发的结构
其存在的问题是
1、代码复用率不高
2、依赖关系混乱,后期难以维护
组件开发
我们来看看官网给我们的图
最上层的就是vm对象,它管理所有的组件对象
在Vue中有两种使用组件化开发的思路
1、非单文件组件
2、单文件组件
非单文件组件
定义组件
1 | const hello = Vue.extend({ |
这里的data配置项我们说过可以写成两种形式
1、函数式
2、对象式
到了组件开发,这个data配置项就必须是函数式
避免组件被复用时,数据存在引用关系。
注册组件
局部注册
1 | new Vue({ |
全局注册
1 | Vue.component('hello',hello) |
使用组件
1 | <div id="app"> |
注意点:
1 | 1.关于组件名: |
单文件组件(脚手架)
这里我们就可以使用脚手架(Vue CLI)啦!
CLI(Command Line Interface)命令行接口,我们就叫它脚手架
首先,你必须要有node和gitbash的环境
在gitbash的命令行中输入以下命令
1 | # 下载脚手架 |
注意
如果你是在idea中的终端运行的vue create 项目名
报了以下错误,有以下两种解决方案
1、以管理员身份打开idea
2、使用命令行到当前目录下使用该命令
这是正常启动成功的界面
脚手架的HelloWorld案例界面
观察项目结构
main.js
1 | // 引入Vue |
我们之前是这么写的
1 | import Vue from 'vue' |
我们运行,发现报错了,报错如下
大概意思是脚手架使用的运行时版本的Vue,它没有模板解析器
你可以将模板放入render函数中,或者使用完整版的Vue
来解决问题
使用完整版Vue
1 | import Vue from 'vue/dist/vue' |
发现不报错了,页面也正常显示了
使用render函数
1 | import Vue from 'vue' |
一个参数省略小括号
1 | import Vue from 'vue' |
直接写返回语句省略花括号和return
1 | import Vue from 'vue' |
换个参数名
1 | import Vue from 'vue' |
为什么要使用残缺版的Vue呢?
模板解析器占了Vuejs源码的1/3的体积,为了减少打包后的体积,所以就将模板解析器删去,用更小的render函数来完成该任务
App.vue
1 | <template> |
我们可以看到一个vue文件可以分为三部分
第一部分是用来写HTML结构的
第二部分是用来写JavaScript的
第三部分是用来写样式的
index.html
1 |
|