第一章 :Vue核心
一、简介
1.1内容
1.2 什么是vue
一套用户构建用户界面的渐进式JavaScript框架 (vue可以自底向上逐层的应用)
- 简单:只需要一个轻量而小巧的核心库
- 复杂:可以引入各种各样的vue插件
1.1 特点
- 1、组件化模式、提高代码复用率、且让代码更好维护
- 2、声明式编码、无需DOM、提高开发效率
1.2 初始vue
- 1、想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象
- 2、root容器中的代码依然要符合html规范,只不过混入了一些特殊的Vue语法
- 3、root容器里的代码被称为【Vue模板】
1.3 初识vue细节点
-
1、注意区分:JS表达式和JS代码
表达式:一个表达式会生成一个值,可以放在任何一个需要值的地方 a+b x==y?a:b JS代码:if、for循环
1.4 模板语法
-
1、插值语法
功能:往往用于指定标签体内容 写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性
-
2、指令语法
功能:用于解析标签(包括:标签属性、标签体内容、绑定事件....) 备注:Vue中有很多指令,且形式都是v-???
-
3、vue里的两种数据绑定
v-bind:单向绑定 简写 : v-model:双向数据绑定 v-model指令只能应用在表单类(输入类)元素,因为用户可以与之进行交互
例如input、textarea
1.5、el和data的两种写法
data和el都有两种写法
1、el两种写法
(1)new Vue时候配置el属性
(2)先创建Vue实例,随后再通过vm.$mount('#root')指定el的值
2、data的两种写法
(1)对象式
(2)函数式
以后在使用组件的时候,data必须使用函数式,否则就会报错
3、一个重要的原则:
由Vue管理的函数一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了
-
1.6 MVVM
Vue在一定程度上遵循MVVM模型
- M:模型(model):对应data中的数据
- V:视图(View):模版
- VM:视图模型(ViewModel):Vue实例对象
因此在文档中经常会使用
vm
(ViewModel 的缩写) 这个变量名表示 Vue 实例。注意:1、data中的所有属性,最后都出现在了vm身上 2、vm身上所有的属性以及Vue原型上所有的属性,在Vue模板中都可以直接使用
二、事件代理
2.1 Object.definePrototype
- 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
- 通过使用defineProperty可以对对象进行高级的限制
- Object.defineProperty(obj, prop, descriptor)
2.2 什么是数据代理
数据代理:通过一个对象代理对另一个对象中的属性的操作(读/写)
2.3 Vue是如何应用数据代理的
基本原理:
通过Object.defineProperty()把data对象中所有属性添加到vm上
为每一个添加到vm上的属性,都指定一个getter/setter
在getter/setter内部去操作(读/写)data中对应的属性
原理分析 通过vm读name、改name、通过vm读age、改age都是数据代理。
数据代理做了什么事?把data中的数据放到vm身上,有了数据代理,我们读取name、address就不需要_data中读取,可以直接通过vm.data、vm.address获取
三、事件处理
3.1事件基本使用
- 使用v-on:xxx或@xxx绑定事件,其中xxx是事件名
- 事件回调需要配置在methods对象中,最终会在vm上
- methods中配置的函数,不要用箭头函数,否则this就不是vm了
- methods中配置的函数,都要被Vue所管理的函数,this的指向是vm或者组件实例对象 5.@click=“demo”和@click($event)效果一样,但是后者可以传参
3.2事件修饰符
- 阻止冒泡 .stop
- 阻止默认事件 .prevent
- 事件只触发一次 .once
修饰符可以连着用,先阻止冒泡,然后阻止默认事件等等
3.3 键盘事件
九个常用的别名
-
键盘上任何一个键都有自己的编码,例如enter等于13编码
-
特殊的键,tab必须配合keydown使用才有效
-
系统修饰键,ctrl\alt\shift\meta这四个也很特殊。
- 按下修饰键的同时再按下其他键然后释放那个键才生效
- 配合keydown,立即生效
-
可以通过键码,keydown.13,但是不推荐了,因为不同键盘,键码不统一
四、计算属性
4.1 插值语法实现姓名案例
分析: 这种写法没有问题,但是不符合vue模板语法简洁风格,如果我只想要姓中前三位,无论我输入多少位,只需要前三位,那么模板语法就会越来越长。
4.2 methods语法实现姓名案例
分析:data中的数据,任何一个数据发生改变,如果模板中用到这个数据,vue模板都会重新解析。 模板中自己调用方法,方法也会重新调用,如果我们改变data中的数据会不断的调用.
4.3 computed语法实现姓名案例
计算属性
-
定义:要用的属性不存在,通过已有的属性计算出来。
-
原理:底层就是借助了Object.defineprototype方法提供的getter和setter
-
优势:与methods实现相比那,内部有缓存机制(复用),效率更高,调试方便。
-
get什么时候调用? 1、初次读取fullname的时候,get会被调用。2、所依赖的数据发生(firstname,lastname)变化时
-
set什么时候被调用?当fullname被修改的时候
-
备注
计算属性最终会出现在vm上,直接读取使用即可 如果计算属性要被修改,必须写set函数去响应修改,且set中要引起计算时所依赖的数据去发生变化
简写
注意:简写的计算属性,表面上虽然是一个函数,但是实际上是执行了函数往wm身上放了一个叫fullname的值(是这个函数执行的结果)
五、 监视属性
5.1 watch语法实现姓名案例
总结
-
当监视属性变化时,回调函数自动调用,进行相关操作
-
监视属性必须存在,才能进行监视
-
监视有两种写法:
(1) new Vue传入watch配置 (2) 通过vm.$watch监视
5.2 深度监视
深度监测
- Vue提供的watch默认是不监测对象内部值的改变的(一层)
- 配置deep:true可以监测对象内部值的改变(多层)
备注
- Vue自身可以监测对象内部值的改变,但是Vue提供的watch默认是不可以的
- 使用Watch时根据数据的内部结构,决定是否采取深度监视
- 默认不开启深度监视是为了效率
5.3 监视简写
什么情况写可以简写?
配置中不需要immediate、deep的时候可以简写
第一种new Vue配置的watch简写
第二种,vm.$watch简写
5.4 监视(侦听)属性和计算属性的区别
总结
- 计算属性里面是不能开启异步任务去维护数据,靠的就是返回值
- watch不是靠返回值,watch靠自己亲自去写代
computed能完成的用watch一定能完成,watch能完成的computed不一定能完成,例如异步操作
原则
- 所有被vue管理的函数最好写成普通函数(尤其函数内部用到vm的时候),这样this的指向才是vm或者组件实例对象
- 所有不被vue所管理的函数(定时器的回调函数、ajax放入回调函数、Promise的回调函数等),最好写成箭头函数,这样this的指向才是vm或者组件实例对象
监听属性实现姓名案例,命令式且重复的。
六、class和style绑定
class
绑定class样式--字符串,适用于:样式的类名不确定,需要动态绑定的
:class="mood"
绑定class样式--数组,适用于:要绑定的样式个数不确定、名字也不确定
:class="classArr"
绑定class样式--对象,适用于:要绑定的样式个数确定、名字也确定,用不用不确定
:class="classObj"
classObj:{
a:false,
b:false
}
style
-
写法1:
:style="{fontSize:fsize+'px'}"
-
写法2:
:style="styleObj" styleObj:{ fontSize:'40px' }
-
写法3
:style="[styleObj1,styleObj2]" :style="styleArr" styleArr:[{color:red},{fontSize:40px}]
七、条件渲染
v-if、v-show
- v-show的底层实现就是调整display、不展示的DOM没有被移除
- v-if为false的时候,结构也不存在了 3.使用v-if的时候,元素可能无法获取到,而使用v-show可以拿到
哪个更好? 频率高的用v-show、频率低的用v-if
v-if、v-else-if、v-else
- 逻辑等价于js中的if、else if 、else
- v-else-if必须配合v-if,v-if一定是一开始被使用的,不能被断
- template只能配合v-if不能配合v-show,template的存在不影响结构
八、列表渲染
8.1 基本列表
v-for指令,用于展示列表数据
特殊点: 基础列表,key不要漏掉!!key必须是唯一的。
-
可以遍历数组、对象、字符串
数组最多
-
还可以遍历指定次数(这种非常罕见)
8.2 key的作用和原理
1. 用index作为key会有什么问题?
-
如果对数据进行逆序的添加、删除等破坏顺序操作,产生没有必要的DOM更新,界面效果是没有问题的,但是效率低
-
如果结构中还包括输入类的DOM:会产生错误的DOM更新,界面有问题
分析:新的虚拟DOM和旧的虚拟DOM进行Diff算法对比,key为0的老刘和旧的虚拟DOM张三都是index为0,所以老刘30会转换为真实DOM,但是老刘后面的input和左边一样,直接复用,所以张三的输入框被老刘直接复用了。 2.用id作为key?
分析:004 老刘和旧的虚拟DOM进行对比,发现不一样,那么直接生成真实DOM
2.没有key会怎么样?
如果没有写key,那么vue会自动把index作为key,vue并不知道哪些是你的vue列表唯一标识。所以没有写key会出问题,因为index作为key不靠谱,尤其是在列表最前面插入数据
3.虚拟DOM中key的作用是?
key是虚拟DOM对象的标识,当数据发生变化时,vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与旧虚拟【DOM】的差异比较,比较规则如下:
4.对比规则?
-
旧虚拟DOM中找到了新虚拟DOM相同的key:
-
- 若虚拟DOM中内容没变,直接使用之前的DOM
-
- 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
-
-
旧虚拟DOM中没有找到了新虚拟DOM相同的key:
-
- 创建新的真实DOM,随后渲染到页面
-
5.开发中如何选择key
-
最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号,学号等
-
如果不存在数据的逆序添加、删除等破坏结构的顺序,可以使用index
8.3 列表过滤
当computed能实现的时候,我们使用computed
8.4 列表排序
分析:使用计算属性,我们在上面使用计算属性进行过滤的时候,在这个基础上做排序。 计算属性返回filePerson的时候,不用着急返回,在过滤完以后,进行排序,排完顺序一起返回。
排序
sort方法,我们要清楚,sort方法能收到什么?需不需要写返回值?改不改变原数组?
九、Vue技术-数据更新
Vue怎么知道我把Data改了?
我们可以写一个watch配置去监测data中的数据改变,然后做一些动作,这个是Vue留给程序员的配置。Vue还会有一个默认的还会有默认的监视,会监视data,一旦发生变化会更新用到data的地方。底层用到的是一套的监视逻辑。
9.1 Vue监测原理
Vue监测数据变化的原理
-
vue会监视data中所有层次的数据
-
如何监视对象中的数据
通过select实现监视,且要在new Vue时就传入要监测的数据 1.对象中后追加的属性,vue默认不做响应式处理 2.如果给后追加的属性做响应式,请使用如下api Vue.set(vm._data.student,'sex','男') 等同于 vm.$set(vm._data.student,'sex','男') 3.如何监测数组中的数据? 通过包裹数组更新元素的方法实现,本质就是做了两件事 重新解释模板,进而更新页面 4. 在Vue修改数组中的某个元素一定要使用如下方法 1、使用这些api、push、pop、shift、unshift、splice、sort、reverse 2、Vue.set()或者vm.$set()
注意:
Vue.set()和vm.$set()不能给vm或vm的根数据对象添加属性!!!!
9.2 模拟数据监测
相比于Vue,我们模拟的不完善的地方
- vue里面可以直接vm.name,我们模拟的这个需要vm._data.name,因为vue做了数据代理
- 我们没有考虑对象里面还有对象,我们只考虑一层,vue考虑了n层,底层写了递归,直到没有对象了 vue监测数据就是靠set!
9.3 Vue.set使用
Vue.set(vm._data.student,'sex','男')
等同于
vm.$set(vm._data.student,'sex','男')
简写(vue内部数据代理了,所以直接通过vm.student)
Vue.set(vm.student,'sex','男')
注意:我们不能在data的根下面直接加一个属性,如果想要添加公司名称,我们可以定义一个对象,往对象里面加。
9.4 数组监测
只要你调用数组的这几个变更方法,能够被vue监测到,会促发视图更新
还可以通过以下方法
Vue.set(vm.student.hobby,1,'羽毛球')来改变hobby数组中第二个元素
9.5 大练习
<div id="root">
<button @click="student.age++">年龄+1</button>
<button @click="addSex">添加性别属性,默认值男</button>
<button @click="modSex">修改性别</button>
<button @click="addFriend">在列表首位添加以为朋友</button>
<button @click="modFriend">修改列表首位</button>
<button @click="addhobby">添加一个爱好</button>
<button @click="modhobby">修改第一个爱好</button>
<h2>学生姓名:{{student.name}}</h2>
<h2>学生年龄:{{student.age}}</h2>
<h2 v-if="student.sex">学生性别:{{student.sex}}</h2>
<!-- 遍历对象 -->
<h2>朋友们</h2>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}}--{{f.age}}
</li>
</ul>
<!-- 遍历数组 -->
<h2>爱好</h2>
<ul>
<li v-for="(f,index) of student.hobby" :key="index">
{{f}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false; //阻止vue在启动生产生产提示
const vm= new Vue({
el: "#root",
data: {
student:{
name:'tom',
age:18,
hobby:['羽毛球','棒球','篮球'],
friends:[
{name:'Jerry',age:25},
{name:'Tony',age:36}
],
}
},
methods: {
addSex(){
// this就是vm
// Vue.set(this.student,'sex','男')
this.$set(this.student,'sex','男')
},
modSex(){
this.student.sex='女'
},
addFriend(){
// 使用了unshift,是vue支持的七种之一
this.student.friends.unshift({name:'vina',age:18})
},
modFriend(){
// this.student.friends[0]='xxx' //这种修改方式是无效的,原因是数组的第0项没有set\get
this.student.friends[0].name='kkk' //这种方式是奏效的,原因是第0项中的name是有set和get的
},
addhobby(){
this.student.hobby.push('学习')
},
modhobby(){
// this.student.hobby.splice(0,1,'开车')
// Vue.set(this.student.hobby,0,'开车')
this.$set(this.student.hobby,0,'开车')
}
},
});
</script>
十、收集表单数据
-
收集表单数据:
若:
<input type="text">
则v-model收集的就是value的值,用户输入的就是value值若
<input type="radio">
,则v-model收集的是value值,且要给标签配置value值若
<input type="checkbox">
,1、没有配置input的value属性,那么收集的就是checked(勾选或者未勾选,是布尔值) 2、配置input的value属性 (1)v-model的初始值是非数组,那么收集的就是checked(勾选或者未勾选,是布尔值) (2)v-model的初始值是数组,那么收集的就是value组成的数组
备注(v-model的三个修饰符):
lazy、number、trim
十一、过滤器
过滤器:
-
定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)
-
语法:
1、注册过滤器 Vue.filter(name,callback) new Vue({filters:{}) 2、使用过滤器 {{xxx | 过滤器}} v-bind="xxx | 过滤器"
-
过滤器也可以接受额外的参数,多个过滤器可以串联
-
过滤器并没有改变原本数据,是产生对应的新的数据
全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
过滤器有两种用法:插值语法中使用以及v-bind中使用
<h4 :x="msg | mySlice">v-bind方式使用过滤器</h4>
十二、vue内置指令
- v-bind:单项绑定解析表达式,可以简写为 :xxx
- v-model:双向数据绑定
- v-for:遍历数组/对象/字符串
- v-on: 绑定时间监听,可以简写为@
- v-if: 条件渲染(动态控制节点是否存在)
- v-else
- v-show
-
v-text
作用:向其所在的节点中渲染文本内容 与插值语法区别:v-text灰替换掉节点中的内容,{{xxx}}不会、
-
v-html
相比于v-text,v-html可以解析dom结构 安全性问题: v-html有安全性问题,在网站上动态渲染任意html是非常危险的,容易导致XSS攻击 一定要在可信的内容上使用v-html,永远不要用在用户提交的内容上
-
v-clock
没有值的直接使用
- 本质上是一个特殊的属性,Vue实例创建完毕后并接管容器后,会删掉v-cloak属性
- 使用css配合v-cloak可以解决网速慢时页面展示出插值语法未经解析的问题
<h2 v-cloak>{{name}}</h2>
配合标签选择器 `[v-cloak]{ display: none; }` vue工作的时候会删掉v-cloak
4.v-once
v-once没有值的直接使用,所在的节点在初次动态渲染以后,就被视为静态内容了
以后数据的改变不会引起v-once所在的结构的更新,可以用于优化性能
5.v-pre
1.可以让vue跳过气所在节点的编译过程
2.可以利用它跳过:没有使用指令语法,没有使用插值语法的节点,会加快编译
6.自定义指令
注意:
1.指令命名的时候,多个单词需要用-连接
v-big-number
2.
自定义指令何时调用?
-
语法
局部指令
new Vue({ directives:{指令名:配置对象} }) new Vue({ directives:{指令名:回调函数} })
全局指令
Vue.directive(指令名,配置对象) Vue.directive(指令名,回调函数)
-
配置对象中常用的3个回调函数
1. bind:指令与元素成功绑定时调用 2. inserted:指令所在元素被插入页面时调用 3. update:指令所在模板结构被重新解析时调用
备注:
1.指令定义是不加v-,使用时需要加v-
2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名
需求1:定义v-big指令,和v-text功能类似。但灰绑定的数值放大10倍
回调函数式的:
1.指令与元素成功绑定时(一上来)
2.指令所在的模板被重新解析时,都会引起自定义指令调用
全局写法
需求2:定义v-fbind,和正常v-bind功能一样,但是可以让其绑定的input默认获取焦点
全局写法
十三、生命周期
13.1 生命周期
- 又名:生命周期回调函数、生命周期函数、生命周期钩子
- 是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数
- 生命周期函数的名字不可更改,但是函数的具体内容是由程序员来编写的
- 生命周期函数的this指向是vm或者组件实例对象
更新流程
只要修改data,就会进入更新流程
销毁流程
vm.$destroy() 完全销毁一个实例,清理它与其他实例的连接,解绑它全部指令以及事件监听器。
当我们页面不需要vm了,我们就把vm销毁了,但是销毁vm之前的模板还会在的,vm没了,但是它的工作成果还在,再更新data就不起作用了。
1、beforeDestroy
能访问到数据,但是所有对数据的修改都不会触发更新,因为已经进入了销毁流程中了
在此阶段:关闭定时器、取消订阅消息,解绑自定义事件等收尾工作
13.2 生命周期总结
四对生命周期钩子函数
-
beforeCreate
指的是数据检测、数据代理创建之前,(指的不是vm创建之前)
2.created
创建完毕
3.beforeMount
4.mounted
做一些初始化的事情,发送ajax请求,启动定时器,绑定自定义事件,订阅消息等初始化操作
5.beforeUpdate
6.updated
7.beforeDestroy
收尾性工作,清除定时器、解绑自定义事件、取消订阅消息等收尾工作
8.destroyed
关于销毁Vue实例
1、销毁后借助Vue开发者工具看不到任何信息
2、销毁后自定义事件会失效,但是原生的DOM事件依然有效
3、一般不会在beforeDestroy操作数据,即便操作数据也不会触发更新
第二章 :组件化编程
为什么要用组件?
传统方式编写应用存在问题:1、依赖关系混乱,不好维护 2、代码复用率不高
组件的定义?
实现应用中局部功能代码和资源的集合
模块?
复用JS,简化js的编写,提高js的运行效率
组件
复用编码,简化项目编码,提高运行效率
模块化
组件化
非单文件组件
一个文件中包含有n个组件,
单文件组件
一个文件中只包含有1个组件 (a.vue),一个.vue一个组件
一、非单文件组件
1.1 步骤
1、定义组件(创建组件)
2、注册组件
全局注册
局部注册
1.2 如何定义一个组件
使用Vue.extend(options)创建,其中options和new Vue(options)时传入的options几乎一样,但是也是有点区别的:
区别如下:
1、el不需要写,因为最终所有的组件都要经过一个vm管理,由vm决定服务于哪个容器
2、data必须写成啊还是农户,避免组件被敷用时。数据存在引用关系
1.3 如何注册组件
1、局部注册:靠new Vue的时候传入components选项
2、全局注册:靠Vue.component('组件名',组件)
1.4 关于组件名
一个单词组成的:
第一种:纯小写 school
第二种:首字母大写 School
多个单词组成:
第一种(kebab-case):my-school
第二种(CamelCase):MySchool(需要Vue脚手架支持)
备注:
组件名尽可能回避HTML中已经有的元素名称,例如h2、H2都不行
可以使用name配置置顶组件在开发者工具中呈现的名字(大型开发、组件库会这么做)
关于组件标签
第一种写法<school></school>
第二种写法<school/>
不使用脚手架时,<school/>会导致后续组件不能渲染
一个简写方式
const school=Vue.extend(options)可以简写为:const school=options
简写表面没有调用Vue.extend,实际上还是调用了Vue.extend
1.5组件嵌套
const student=Vue.extend({
name:'student',
template:`<div>
<h2>学生姓名:{{name}}</h2>
<h2>学生年纪:{{age}}</h2>
<h2></h2>
</div>`,
data(){
return {
name:'vina',
age:18
}
}
})
const school=Vue.extend({
name:'school',
template:`<div>
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<student></student>
<h2></h2>
</div>`,
data(){
return {
name:'zenlayer',
address:'上海'
}
},
// 局部注册组件,嵌套
components:{
student
}
})
new Vue({
el:"#root",
components:{
school
}
})
1.6 VueComponent构造函数
-
school组件本质上是一个名为VueComponent的构造函数,且不算程序员定义的,是Vue.extend生成的。
-
<school></school>
或者<school/>
。Vue解析时会帮我们创建school组件的实例对象。即Vue会帮我们执行:new VueComponent(option) -
特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!! 4.关于this指向:
(1)组件配置中:data函数、methods中的函数,watch中的函数,computed中的函数,他们的this均是【VueComponent实例对象】 (2)new Vue()配置中:data函数、methods中的函数,watch中的函数、computed中的函数,他们的this均是【Vue实例对象】
1.7 Vue实例和组件实例
VueComponent实例对象,以后坚持vc,也可以称为组件实例对象
Vue实例对象,以后简称为vm
vc有的vm都有,但是vm有的el,vc没有,el是根实例特有的
因为组件是可复用的 Vue 实例,所以它们与
new Vue
接收相同的选项,例如data
、computed
、watch
、methods
以及生命周期钩子等。仅有的例外是像el
这样根实例特有的选项。
1.8 一个重要的内置关系
VueComponent.prototype.proto===Vue.prototype
为什么有这个关系?
让组件实例对象(vc)可以访问到Vue原型上的属性和方法
Vue原型上有很多方法,如果没有VueComponent.prototype.proto===Vue.prototype这个关系,那么vue原型上的东西只有vm能用,vc不能用,利用原型链,使得vc可以使用vue原型上的方法。
必须要有原型的基础
1.9 data必须是一个函数
大白话:防止一个组件被多次使用的时候存在数据的引用关系
官方:每个实例可以维护一份被返回对象的独立的拷贝
二、单文件组件
2.1 编写单文件组件的步骤
1. 第一步:写组件
2. 第二步:汇总所有组件的App
3. 第三步:main.js去创建vue实例,并且指明为哪个容器服务
4. 第四步:页面展示
第三章 Vue脚手架
一、认识脚手架
1.1 关于不同版本的Vue
1、vue.js与vue.runtime.xxx.js区别
vue.js是完整版的Vue,包含:核心功能+模板解析器
vue.runtime.xxx.js是运行版的Vue,只包含:核心功能,没有模板解析器
2、因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接受到的createElement函数去指定具体的内容
1.2 vue inspect > output.js
Vue脚手架隐藏了所有webpack相关的配置,若想查看具体的webpack配置,执行vue inspect > output.js
可以显示,这么做就是防止程序员去破坏配置。
1.3 vue.config.js
使用vue.config.js配置文件可以怼脚手架进行个性化定制,详情见:cli.vuejs.org/zh/config/#…
下面五个名字默认的配置文件不能改,如果我们想改,vue也提供了渠道,让我们可以修改默认的配置。
如果我们想要自定义入口文件,可以使用如下办法:
二、组件相关知识点
2.1 ref属性
-
被用来给元素会这子组件注册引用信息(id的替代者)
-
应用在html标签上获取真实的DOM元素,应用在组件标签上是组件实例对象(vc)
-
使用方法:
- 打标识:
<h1 v-text="msg" ref="title"></h1>
- 获取:
this.$refs.title
- 打标识:
2.2 props属性
注意点:不可以传key、ref等作为props命名
如何修改Props的值?
props是只读的,vue底层会检测到你对props的修改,如果发生修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data的数据。
2.3 mixin混入
-
功能:可以把多个组件共用的配置提取成一个混入对象
-
使用方法:
第一步:定义混入,例如:
第二步:使用混入
(1)全局:Vue.mixin(xxx)
(2) 局部:mixins:['xxx']
2.4 插件
Vue里面的插件,本质上就是一个对象,但是必须包含install
Vue给我们提供api,用来应用(使用)插件
-
功能:用于增强Vue
-
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件的使用者传递的数据
-
定义插件:
对象.install=function(Vue,options){ //1.添加全局过滤器 Vue.filter(...) //2.添加全局指令 Vue.directive(...) //3.配置全局混入 Vue.mixin(...) //4.添加实例方法 Vue.prototype.$myMathod=function(){....} Vue.protitype.$myProperty=xxx }
4.使用插件:Vue.use()
2.5 todo-list案例
-
组件化编码流程(通用)
1. 拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突 2. 实现动态组件:考虑好数据的存放位置,数据是一个组件在用还是一些组件在用: 1)一个组件在用:放在组件自身即可 2)一些组件在用:放在他们共同的父组件上(状态提升) 3. 实现交互:从绑定事件开始
-
props适用于
(1)父组件==》子组件通信 (2)子组件==》父组件通信(要求父先给子一个函数)
-
使用v-model要切记:v-model绑定的值,因为props是不可以修改的
-
props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做
2.6 浏览器的本地存储
localStorage和sessionStorge统称为webStorage
1.存储内容大小一般支持5M组呕呕 2.浏览器听过window.localStorage和window.sessionStorage属性来实现本地存储机制 3.相关api
4.备注
1.sessionStorage存储的内容会随着浏览器窗口关闭而消失 2.LocalStorage存储的内容,需要手动清除才会消失 3.xxxxxStorage.getItem(xxx)如果xxx对应的value获取不到,那么getItem的返回值时null 4.JSON.parse(null)结果依然是null
2.7 绑定自定义事件实现子给父传递事件
子给父传递事件两种写法:
第一:通过父组件给子组件传递函数类型的props实现:子给父传递数据
APP(父)
<School :getSchoolName="getSchoolName"></School>
getSchoolName(name){
console.log("收到了学校名称:",name)
},
school(子)
props:['getSchoolName'],
this.getSchoolName(this.name)
第二:通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(v-on)
APP(父)
<Student v-on:zidingyi="getStudent"></Student>
getStudent(name){
console.log("getStudent被调用了!!",name)
}
student(子)
// 触发student组件实例对象上的
this.$emit('zidingyi',this.name)
第三:通过父组件给子组件绑定一个自定义事件实现:子给父传递数据 (ref)
这种方法灵活性很强
APP(父)
<student ref="student"></student>
mounted() {
this.$refs.student.$on('zidingyi',this.getStudent)
},
student(子)
// 触发student组件实例对象上的
this.$emit('zidingyi',this.name)
分析两种方法
- 必须都得在父组件中配置回调
- 通过props,在子组件中必须亲自去调用。通过自定义事件,在子组件中通过$emit触发这个事件
解绑事件
// 解绑一个自定义事件
this.$off('zidingyi') //解绑一个
this.$off(['zidingyi','demo'])//解绑多个
this.$off() //解绑所有
自定义事件总结
1.一种组件见通信方式,适用于:子组件--》父组件 2.使用场景:A是父组件,B是子组件,B想给A传递数据,那么就要在A中给B绑定自定义事件(事件的回调在A中) 3.绑定自定义事件:
1:第一种方式:在父组件中:<Demo @zidingyi="test"/>或者<Demo v-on:zidingyi="test"/>
2:第二种方式,在父组件中
` <student ref="student"></student>
mounted() {
this.$refs.student.$on('zidingyi',this.getStudent)
},
`
3:若想让自定义事件只触发一次,可以使用once修饰符,或者$once方法
4. 触发自定义事件: this.off('zidingyi') 6. 组件也可以绑定原生的DOM事件,需要使用native修饰符 7.注意:通过 this.on('zidingyi',回调)绑定的自定义事件,回调要么配置在methods中,要么是箭头函数,否则this指向会出现问题
2.8 全局事件总线
实现任意组件间的通信,但是父子之前没必要麻烦事件总线,
-
x必须让所有的组件都能找到
Vue.prototype.P={a:1,b:2}
-
保证x可以调用到off,$emit
实践
main.js(安装全局事件总线)
在创建vm的时候,在beforeCreate中安装全局事件总线,为什么要在vm中安装呢,因为这个傀儡必须具有$on、$emit熟悉,我们要么定义一个vc,要么就在vm中安装
school
在school中,给傀儡$bus绑定事件,回调留在school中,但是我们用完了一定要把$bus上面的hello事件解绑了,因为vc消失,傀儡依旧在
Student
在school中,
本质:
全局事件总线的本质就是自定义事件,只不过是绑定在vm身上
2.9 消息订阅与发布
报纸的订阅与发布‘
1.订阅报纸:住址
2.邮递员送报纸:报纸
消息的订阅与发布
1.订阅消息:消息名(手机号)
2.发布消息:消息内容
- 需要数据的人订阅消息,订阅的名字很重要。提供数据的人发布数据。
- 原生的JS没办法轻松实现订阅与发布,借助第三方库(推荐pubsub-js)
实践
是一种组件间的通信方式,适用于任意组件间的通信
第一步:安装
npm i pubsub-js
第二步:引入+订阅
import pubsub from 'pubsub-js'
mounted() {
pubsub.subscribe('hello',function(value,data){
console.log("有人发布了hello消息,hello消息的回调执行了",value,data)
})
},
第三步:引入+发布
import pubsub from 'pubsub-js'
methods: {
sendStudentName(){
// this.$bus.$emit('hello',666)
pubsub.publish('hello',666)
}
},
第四步:取消订阅
beforeDestroy() {
// this.$bus.$off('hello')
pubsub.unsubscribe(this.pubId)
},
2.10 nextTick
-
语法
this.$nextTick( callback )
-
作用:在下一次DOM更新结束后执行其指定的回调
-
什么时候用?
当改变数据后,要基于更新后的DOM进行某些操作是,要在nextTick所指定的回调函数中执行
三、过渡与动画
3.1案例对比
CSS3实现动画,需要手动的切换类名
Vue实现动画,两个类名一个动画,transition包裹发生动画的DOM,无需手动切换类名
3.2 知识点
1.transition这个标签里面有个布尔值的appear属性, :appear="true"或者appear,设置节点在初始渲染的过渡