vue - Vue介绍
Posted 格格巫 MMQ!!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue - Vue介绍相关的知识,希望对你有一定的参考价值。
一.初始化Vue脚手架
1.说明
一般脚手架选择最新版本
2.具体步骤
全局安装vue/cli脚手架
切换到项目目录,运行 vue create 加一个非主流库的名字 即可创建一个vue项目
运行 npm run serve 将项目在服务器跑起来
上面为本地服务器地址,下面如果有同事,那就可以访问同一个局域网内的地址
可以看到vue默认为我们创建了一个hello word的组件
3.分析项目结构
用vue脚手架创建了一个项目后会发现如下的结构
首先从根目录的文件入手,第一个.gitignore就不用多说了,git上传的忽略内容
babel.config,我们知道babel在webpack里面是对js语法进行降级而符合兼容性的,这里的功能也是如此
package两个json就不用多说了,lock是包的一些详细信息,package是下载了哪些包,并且配置入口文件,自定义npm指令都在这里
readme是对脚手架的一些基本操作的介绍
进入我们第一个文件夹src
首先assets这个文件目录我们是经常看到的,这里面一般放的是静态资源,一些不会变的图片(logo)、音视频等文件
然后可以看到我们的main.js入口文件,new Vue就是在这里面,还引入了我们的丞相一人之下万人之上的app
然后我们的所有的组件都会写在components这个文件夹下面,除开app这个组件
最后一个目录,也就是我们最后一个步骤,我们的html文件
正式放在这个目录下,注意一下title那个标签用到的是webpack那个便捷生成html的插件,然后他有一些语法这个意思就是到package.json里面去取name作为我们的title
注意:html文件不需要引入vue,不需要引入main.js直接可以开始跑项目
将我们之前写的单文件组件放进去并开启服务器
这里有一个错误困扰了老半天,按理说这里的组件名是没问题的
知识vue官方推荐风格为大驼峰命名或者是-拼接的形式,按理说单单词也没问题的,查阅了一下百度才知道,这里应该只是提醒,只不过呢语法检查的时候把不规范的代码提醒当成了错误,改了名字后就成功执行了
4.render函数
问题抛出:main.js按照标准的写法解析不了
问题其实就出现在我们引入的这个vue包身上,打开这个vue的包可以发现,我们vue的package.json定义好的如果是是用的es6模块化的导入,那么自动引入的是module这个js文件(残缺版Vue,残缺的是模板解析器)
两种解决方法,一个是引入完整版vue,这里不作考虑,第二个办法就是用这个残缺版vue,没有模板解析器就没有,我还有一个东西可以帮我们编写网页,render函数,他会接受一个参数,这个参数也是函数这个函数里面的形参有两个,一个是标签,一个是内容,把这个函数作为render的返回值,那么就会帮我们写出一个网页
最终可以简写为箭头函数也就是我们在main.js里面看到的那个,为什么这里参数就一个app,因为如果传的参数为一个组件就不用传参我们的内容部分了,因为内容都在app里面的
vue文件其实就分为两个部分内容,一个是vue核心(事件、生命周期钩子、监视等),一个就是我们的模板解析器
看下面这张图
我们的esm这个版本就是es6模块化的缩减版vue,带runtime的都是运行版的vue,只包含核心功能,上面两个就是commonjs导入的缩减版vue,这么多vue版本,只有中间那个才是完整的vue版本
那么为什么要给我们分这么多版本?因为要考虑到一个东西,模板解析是拿来解析我们vue后缀文件里面的模板的,这个解析器占用了整个vue文件的三分之一,也挺大的了,最关键的是,我们项目最终上线通过webpack打包,它会自动给我们vue里面的文件分割出来,什么是css部分什么js部分,哪里是html部分,分割成我们浏览器认识的,客户端认识的,不再需要什么.vue后缀的文件了,所以这个时候模板解析器也没什么作用了,那如果既然上线项目根本用不到他,我还打包她干嘛,耗费资源
为什么app等其他组件里面可以写template模板?
因为脚手架给我们安装了一个专门解析.vue里面的模板的解析器,main.js想用也不行
5.修改默认配置
因为我们vue脚手架是基于webpack写出来的,所以那肯定配置都写在webpack.config.js,但是vue给她隐藏起来了,需要输入 vue inspect > output.js这个output.js只是 可以查看webpack.config.js里面的所有配置内容
注意红色部分不能改,粉色部分才可以改(具体可以参考vue cli官网配置项)
如何来修改?
都是基于vue.config.js这个文件来修改的,参考cli官网比如要修改入口文件,找到 pages
同理,lintOnSave改为false可以将语法检查关闭,也就是前面遇到的单单词错误就没得了
二.ref和props
1.ref(打标识)
我有一个需求点击一个按钮显示上面的DOM元素
操作了DOM不太符合vue的规范,所以vue就有一个api ref
相当于id的替代者,所有配置了ref的都可以通过这个$refs这个对象获取DOM元素,都在这个对象里面存起的,但是注意 如果ref在组件标签上,那么获取的将会是vc而且还是这个组件的vc
跟id的区别就是id在组件标签上拿到的就是这个组件标签的dom元素
2.props
让组件接收外部传进来的数据
以前写个组件,想复用,直接复制粘贴在下面即可
那我现在来个需求,如果我要复用你的代码,但是我并不叫这个名字,也并不是这个年龄怎么办,这个时候就要用到我们的props了,首先我们的数据肯定是不能写为固定的了,不能再data里面写死,而是谁用这个数据就写在这个组件标签里面
一般这样一行参数是不是写在父组件里面的,那这些数据需要送往一个地方来存吧,这个地方就是一个全新的配置项 props,且需要写在子组件里面还必须是一个数组形式
这个时候我们就可以随便改我们的数据了
这才是复用嘛。
但是这里还有个小bug如果我想把你传过来的参数以加一岁的形式进行展示,直接在vue语法上age+1是不行的,为什么因为我们传过来的参数有明晃晃的引号,所以相当于传了一个字符串过来,age+1只会当成字符串拼接的方式,这里可以巧妙地用一个小方法
将其动态绑定即可,为什么,因为加了v-bind后,引号里面的内容会作为表达式然后将返回值给到这个age,这个时候age再去➕1就没得问题了。
但是还有一个问题,要从根源上解决问题,限制一下这里输入值的范围,就需要用到props的定义形式了,他有三种定义形式,刚才的直接数组形式为简单声明(开发简单声明使用的多)
接收数据同时限制类型
简单声明一下需要写入的类型,如果不对,控制台就会报错,定义了的话
接收数据同时限制类型➕必要性➕默认值
对于名字和性别首先限制类型,然后设置为必输入项,不能为空,age除了限制类型,还设置了一个默认值,也就是可填可不填不填就采取默认值99,
注意一般required和default不同时出现,为什么自己品,还有就是props接收到的数据 不能改
如果非要强行改,注意到一个点 props的优先级是高于data的,利用这一点,可以在data定义一个数据,用这个数据接收传过来的age值,让我们页面展示的也是data中的这个age值,然后点击事件改的就是这个data中的值
三.mixin(混合)
把多个组件共用的配置提取成一个混合对象
定义了两个组件都可以完成类似的一个功能
那有没有办法能把两个methods融合一下,作为一个来使用,这个时候就要用到我们的 mixin混入了,向外定义一个js文件直接按需导出,一个变量为对象,里面放入我们的methods
然后在我们的组件按需导入,并且一个全新的配置项来了 mixins注意有s,而且它是一个 数组的形式
两边组件都配上后就可以使用共同的方法了
混合里面能写啥?,在我们组建的Vue.extend配置项里面的都可以写,生命周期钩子、data数据等,就相当于在你的vc实例对象里面添加了这个配置项,只要你配置了mixin混合
注意点
混合可以组合,多个混合在同一个js文件暴露,组件导入对应在mixin数组配置项写上对应的名字即可
一个原则:如果你配置项里面没有的,混合可以给你,但是如果你有的数据,就以你自己的为主,像这里,最终x为666
特殊情况:生命周期钩子,不受限制,混合声明了,自己也声明了,那就两个都会执行,但是混合先执行
全局混合:刚才的方式都为局部混合,还有全局混合,写在入口文件里,导入到入口文件,Vue.mixin来配置,这样一配置后,那混合里面的东西,不光是所有组件有了,就连app、vm实例都会有
四.插件
用于增强Vue
就是一个js文件,里面会暴露出一个对象,至关重要的是里面包含一个 install方法并且这个方法的参数为Vue构造函数,第二个参数我们以后传入的数据
标准写法
简写版:
关于里面能写啥,既然Vue构造函数都拿到了,那能写的东西可太多了,把以前写过的过滤器、自定义指令、刚才才说的混合都可以放到这里进行全局配置,最主要的是,你可以自己写方法写到prototype原型对象上去,那么我下面的vm或者vc是不是都可以使用这个方法了,这里的原理有点类似于Node.js里面的中间件,自定义中间件,我在前面定义好req、res了注册了过后,后面的中间件和路由是不是都能拿到这个属性方法了,你现在觉得不像下一步就是真的像了
这里的mixin混合的写法:因为我们混合是一配置,任何组件都会有这些配置项,所以不需要组件来导入,来注册使用之类的,所以就不需要定义名字了,针对于全局声明混合的话
当我们配置好plugins.js后应该在入口文件导入并注册,一个全新的api Vue.use
这样一看是不是跟Node就很像了,并且神奇的是,这样一注册,vm和vc都能使用插件install里 定义的全局过滤器、指令等全局定义的以及往Vue原型对象上添加的属性和方法
验证
可以看到全局定义的过滤器、自定义指令、混合包括自己在原型对象上定义的一个方法,都可以拿来使用
五.scoped样式
让样式在局部生效,防止冲突
我们写的style样式,最终在打包的时候其实是把所有组件的样式混合在一个css文件里面,所以这个时候就容易遇到一个问题,重名的问题
仅需要在我们style标签 加一个属性scoped即课解决,它的原理就是会给你这个组件标签动态生成一个随机生成的属性,然后配合你这个css类名加上属性选择器达成只属于你的样式
特殊:
当我们在App这个组件的style写了一个类选择器字体颜色为红色,意思就是他的子组件,只要class为这个类选择器,都可以用到这个属性,但是如果你给App的style加了一个scoped那么,这个时候就只有App自身的组件标签可以用这个了,子组件都用不到了
我们的style是可以指定使用语言的,可以指定预编译语言,比如less,但是直接使用是不行的,需要安装对应的解析器
注意:如果脚手架的webpack为最新版本5及以上可以安装最新版less,否则安装less8以下的(6.7左右),npm view webpack versions可以查看这个包目前有哪些版本
上面的注意当我没说,最新的脚手架已经使用了最新的webpack了
安装了less-loader后即可使用less来写css
六.TODOList案例
做这个案例主要是为了能够熟悉组件化编码流程,刚开始学做一个项目最好按照以下三个步骤来
1.实现静态组件
先把一个项目抽取组件,使用组件实现静态页面
比如这个案例App的子组件就可以拆分为三个上面输入框,中间列表展示,下面总结栏,其实组件的划分就是按照他的功能点来划分的,
比如子组件按照功能划分了三个组件,list里每一个item是不是有自己的功能可以勾选,可以删除,所以又可以进一步细分组件(如果你拆完一个组件发现很难起名字,说明你拆的不是很合理)
既然已经拆分好组件了,就可以去vue项目里面写我们的组件了,创建、导入、注册三步曲完成
接下来应该有我们的静态模板了,是这样的,一般情况下我们的一个项目大多数已经完成了一些了,所以不会从零开始,这个时候老板派给你个任务叫你把这个实现组件化开发,你就直接把html先一股脑的塞到 App.vue里面,可以启动服务器看到整体的一个效果,然后再去一步一步把代码拆分进我们的组件里面去
注意:有很多问题是语法报错,将那个lintonsave关闭即可
然后就可以开始拆分了,其他不说这个list里面每一条数据看出了拆分组件的重要性,我直接在list组件复用item就可以了
css拆分时要注意:base等公共样式放在App.vue,其他各自的样式各回各家但是要注意添加scoped
2.展示动态数据
将我们项目中需要动态真实的数据存起来 一般是数组加对象的的形式,一个对象一条数据里面有id、name等等
那么数据一般保存在哪里? 回顾一下之前props的案例,我们的数据是不是写在父组件里面的,通过子组件标签传给了他,子组件才能用props来接受外部传来的数据,所以我们的数据要定义在每条数据这个组件的父组件
在我们定义数据这里几个注意点:
id为什么用字符串,因为数值型会有上限,字符串没有
既然数据都有了,所以这里就不用一个一个去写子组件标签了直接v-for列表渲染
最关键的:我们要将数据传到子组件里面去吧,这里不再是像以前那样,一个一个传,这里直接是传的一个对象,而且还是遍历出来的每一条对象,还必须要动态绑定,不动态绑定这里就是一个字符串
子组件这边,注意一下props接受参数要用引号包裹,然后就是怎么来让我们的复选框动态的获取到有没有勾选,让其动态绑定值为我们数据里面的值即可
3.添加
首先我们实现回车添加数据的逻辑,肯定是要生成一个对象然后添加进那个数组里面,这里的id由于灭有数据库支持,就采用了一个包,uuid可以生成全球唯一id,但是他体积表较大,这里用的是另一个体积小一点的 nanoid
接下来问题就来了,我们这个数据是在header里面添加的,而我们的数据是在list,我们学过父组件给子组件传数据(props),但是没有学过兄弟关系来传数据吧,这里才去最基础的方法来实现
我们吧list里面定义的数据data放到app组件里面去,然后app通过动态绑定将数据传到list的组件标签,这个时候list用props来接受传过来的值
最主要的是怎么把子组件header传到父组件app里面去:我们在app定义一个函数然后接受形参,将这个函数动态绑定给到header,header通过props就能够得到这个函数,然后重要的一步 我将这个函数写在键盘事件里面,同时参数是我们的创建的数据,就相当于调用了这个函数,调用不要紧,关键是这个函数式app送给你用的,你调用(送给你用的所以拿过来是存在于vc实例对象上)拿我app不就拿到了这个参数吗所以,app现在又有参数,又定义了数据,那么添加的逻辑就开始了
4.勾选
我们要在item里面来勾选,从而影响到数据里面的completed这个选项,我们的数据是定义在App里面的,有一句话叫做 数据在哪里,那么处理数据的方法就写在哪里,所以这里好像又要用到子组件给父组件东西了,给什么?我勾选的状态实在item里进行的,我必须拿到勾选的这一个id,才能在处理数据的方法里面以id为参数对数据记性遍历找到对应的那一个将他的completed的值改为非值
这里有一个注意点,把我们之前这个勾选的所有逻辑推翻,直接在item的input标签里面写一个v-model,我们说复选框v-model默认收集的是checked的值,如果我把v-model设置为todo.completed是不是就让我们的checked动态绑定了,他为true,checked就为true,第一步初始化数据的勾选完成了,这里还有一个更重要的,你该数据也同样可以改到data里面的数据,因为v-model本身就是双向绑定,但是我们前面也说过,props接收到的数据不能改,这里很明显是通过props传过来的数据改到的,为什么这里没报错呢,因为vue对于对象改动的检测有点类似于 const,一般数据确实数据变了就是改动了,但是数组和对象通过属性名或者下标去改某一个值并不叫改动,要变动整个数组和对象才叫改动,所以这里没有报错,这个方法是简单但是,官方定义的props传过来的数据不能改,最好还是不要改,万一哪天这个数据不是对象里的值了,就麻烦了,最好还是按照语法规则来
5.删除
主题逻辑刚上面差不多,点击删除返回id,app传过来一个函数接受这个id,然后数组的筛选方法filter让我们的数据等于筛选出来的新数组,这里就不考虑性能问题了,假装是个标记删除吧,删除了虽然还在但是也永远不会给你显示出来了,所以可以直接把他赋值给这个原数据,还有一个点confirm确认框,会弹出一个对话框内容为你传进去的参数,配合if来使用可以达到只有你点击确定了才会执行后面的逻辑
6.底部统计
既然是统计,那肯定要用计算节点来做,这里用到了数组的reduce方法,要注意的是,prev每次返回要等于他自己
7.底部交互
先完成我们点击了所有的勾选框,下面全选会勾上,但凡少勾选一个都不会钩上的逻辑,其实很简单,将我们全部的这个数量也弄成一个计算属性,然后将我们全选动态绑定,且返回值也由计算属性来决定,直接去比较已完成和全部是否相等
探后就是我们的全选功能,逻辑是这样,点击一下,通过e获取他的checked的值,然后又要动到数据了,需要app里面对数组做一个循环对所有的数据的completed的值都等于这个checked的值
但是这样有一个bug,当我们删完后,会是勾选状态,应该为不勾选并且隐藏掉
在我们刚才完成点击点击上面,下面全选也会对应去勾选上那里的逻辑完善一下,因为原来的写法,就是当已完成和总数一样的时候就会勾选上,那么最后删完了,也是一样的所以不行
通过v-if添加在footer即可
好了,可以忘掉这一章节实现的功能了,简便方法他来了
我们这里的全选框有些啥子东西,一个管初始化读取数据的,一个改数据的,又是input,读写,想到他没有v-model
我们用v-model去绑定isAll的值也就是判断有没有全选的值,即可完成读的操作,仔细想想是不是
但是这里改的话会报错,为什么?
因为我们的isAll是计算属性,你改动他的值,你setter都没有怎么改,所以这里要这么做,定义一个setter,并且把这个值给到我们刚才定义的循环让所有值都等于这个checked的App组件上的函数
为什么这里可以使用v-model前面是因为那个值时props传过来的值肯定不能改,而这里是我们写在这个组件的计算属性属于自己的
8.清除已完成的任务
最后一个功能,很简单直接一个点击事件,在app这边做一个数组筛选,筛选的是completed没被选中的
9.总结
组件化编码流程
拆分静态组件,按照功能拆分
实现动态组件,考虑好数据的位置,如果数据是一个组件在用就放到这个组件,如果数据是一些组件在用,就放到他们的共同的父组件(这种方法也叫做状态提升)
实现交互(从绑定事件开始)
props不仅适合父给子传数据,还可以子给父传数据(父会给子一个函数)
v-model注意修改的值是不是props过来的,不是他过来的还是可以用的还是很方便的
修改对象里面的值跟const一样改单个值不会被发现,要修改整个对象。
七.浏览器本地存储
1.localStorage
关闭浏览器数据不会丢失
通过它上面的一个api可以存储数据 .setitem()两个参数,前面是键,后面是值,要注意的是都要以加引号以字符串形式进行存储,而且就算你不加引号,最终呈现效果也会强制给你调用toString这个方法
可以看到就算是字符串也变成了字符串类型,那么问题就来了,那如果我传入的是一个对象,也被强制调用了toString那我对象就没了,什么也看不到了
所以如果是要存储对象数据的时候需要将对象用转为json数据在进行存储,我们都知道json本质上还是一个字符串
剩下还有三个api:读取getitem()、删除removeitem()、清空clear()这个不用传数据
注意:读取没有的属性,将会显示null
2.sessionStorage
浏览器一关就没有数据了
他的api跟local一样
3.TodoList案例完善
我们刚才做的案例数据在一刷新,就会回到初始案例,显然这样是不行的,每个人都应该有属于自己的数据,就可以配合localstorage来,通过监视属性来做,监视我们的data数据,当一发生变动就让最新的值setitem到我们的本地存储
我在这里卡了半天啊,我一直在纠结,为什么这个local里面的属性名会给我变成个数组,最终查到了,原来watch监视属性里面的参数本身就是个数组,放的对象的形式,做到这一步当我们敲击回车,已经可以看到localstorage将我们的数据存储下来了,但是呢我们的页面还没有,这个时候需要将我们原来的数据,注意datas本身是一个数组这里就不用再用数组包裹了
这个时候我们我们刷新就能看到我们之前已经添加过的数据了
bug:当我们把local清空准备重新试一下,就会报错
不能够读取null的长度差不多是这个意思,哪里来的null?还记得前面说过当我们本地存储如果读取的是一个不存在的属性那他读取出来就是null,所以问题出现在这里,这个时候localstorage里面还没有这个属性的,主需要采用短路运算,让原始数据,存在就用它否则就为一个空数组
bug:虽然完成了刷新添加的数据不会丢失,但是我们的选择刷新了会丢失,为什么,问题出现在watch这里,我们对watch的监视只是看dataArr有没有整体改动,用了unshift,vue都能检测到,很明显这是一个能够改变自身的方法,但是我们去勾选前面的选择,却是深层次里面的了,所以监视的deep属性就来,只有监测到深层次的改动才又会重新setitem
八.自定义事件
方法一 : @或者v-on方法完成一个案例,当我们点击一个子组件,会把子组件的名字传到app里面来并打印出来,用到props的子传父方法,怎么用自定义事件来完成这件事情,首先在app的组件标签写上我们的自定义事件名,用v-on来绑定,
那么这个事件怎么来触发呢,这样来理解,当我们通过组件标签给她绑定了一个自定义事件,那么此时这个组件实例对象vc身上肯定已经有这个事件了,至于怎么来触发就需要回到我们的组件里面去定义
这里先把我们的触发后的事件处理函数定义好,然后关键逻辑 主要是在我们要触发的这个组件里面,想要这个自定义事件要怎么触发其实是听你自己的,同样还是需要在这边生命一个内置的事件,然后在这个事件函数里面用到一个api $emit,他的第一个参数就是你的自定义的事件的名字,第二个参数可以传参给你自定义事件的处理函数
props和自定义事件异同点:
共同:都可以实现子给父传数据,而且都是通过父组件里面的回调来实现的
不同点:props需要接收,而这种方法,直接拿来用都不用调用这个函数,props还需要自己去调用这个函数把参数传进去
方法二: 针对于上面的自定义事件的形式,我们还有第二种方法也叫做 ref法,通过在app给子组件添加一个ref,前面就说过我们用ref获取来的组件是这个组建的实例对象,有了实例对象,直接通过mounted这个生命周期钩子,为什么要在这里做,因为只有挂载完毕了我们才能拿到这个实例对象,vue才会new 组件构造函数,继续通过$on这个方法给这个实例对象在他身上添加一个自定义事件
做到这一步,我们组件里面的代码不变,还是click同时还是通过$emit 这个api来触发自定义事件,做到这一步意思就是,一切准备就绪,一旦在这个组件触发了这个自定义事件就会执行自定义事件的回调函数,那么回到函数呢?直接在后面以参数的形式添加
如果说我只想执行一次用v-on方法就是直接用事件修饰符,用ref方法,就调用$once这个api
注意如果是子组件多个参数传进来,可以使用这种方式将其以一个数组方式接受
8.1解绑自定义事件
解绑单个事件,写在子组件里面,全新api $off
解绑多个,用字符串包裹
解绑所有,this.$off()不传参数
回顾前面所说的一个生命周期的问题,说过当执行了destroy之后,身上的事件、监听器等都会被销毁,但是说的事件是自定义事件,和vue事件不包括原生js事件,比如你点击一个按钮n++,这个时候n肯定不加了,但是如果你写的有console.log那么这个log肯定还是你点一次输出一次的,自定义事件就更不用说了,也是vue实现的,所以也会被销毁实现不了了,还有一个点就是,vm被销毁了他下面的子组件的这些自定义事件等也会被销毁
8.2注意
是一种组件间的通信方式,适用于 子组件给父组件传
我们的组件标签上也可以绑定内置事件,但是需要 .native这个修饰符,绑定后比如一个click那就是这个子组件的最大的div可以触发也就是子组件的最外层
如果用下面这钟方式绑定自定义事件的时候,需要注意回调这里要么写在mtehods里面,要么写成一个箭头函数,不然this指向会变
8.3TodoList自定义事件
将之前这个案例子传父数据的地方都改成自定义事件,我就直接传几个,比如敲回车放入数组这里直接将原来的动态绑定改为自定义事件,简写形式
然后我们header这边的 props就可以删除了,同时在我们的键盘事件添加上调用api去触发自定义事件的命令
然后我们在用ref打标识的方法再做一次全选的方式,首先需要在app里面找到footer的子组件,给她打一个标识,然后在我们app这个组建的mounted函数里面来通过ref得到这个组件实例对象通过on这个api将自定义事件绑定上去,同时第二个参数为我们要调用这个事件的回调函数
然后后面基本是一样的,在我们子组件里面这个自定义事件该怎么触发,就写内置事件,写一个事件处理函数,然后在这个处理函数里面,emit这个api来触发自定义事件,同时将我们需要的参数传过来
九.全局事件总线
9.1安装全局事件总线
可实现任意组件间的通信
其实原理是这样的,我们左边这么多组件,要实现任意互相通信,可以由一个中间者实现,比如我们在B里面定义这个x给她通过 o n 绑 定 一 个 自 定 义 事 件 , 同 时 回 调 在 我 们 B 里 面 , 注 意 是 在 B 里 面 , 所 以 当 执 行 这 个 自 定 义 事 件 的 时 候 , 是 在 B 里 面 执 行 , 完 成 了 这 一 步 , 比 如 说 我 们 要 把 A 的 数 据 传 到 B 里 面 来 , 那 么 A 就 可 以 通 过 x 这 个 对 象 用 他 身 上 的 on绑定一个自定义事件,同时回调在我们B里面,注意是在B里面,所以当执行这个自定义事件的时候,是在B里面执行,完成了这一步,比如说我们要把A的数据传到B里面来,那么A就可以通过x这个对象用他身上的 on绑定一个自定义事件,同时回调在我们B里面,注意是在B里面,所以当执行这个自定义事件的时候,是在B里面执行,完成了这一步,比如说我们要把A的数据传到B里面来,那么A就可以通过x这个对象用他身上的emit这个api来触发我们的自定义事件同时把A身上的数据,传过来,这个时候我们B的回调里面就能收到这个数据了
其实原理跟我们前面的自定义事件很像,所以这么一看,这个x是不是要满足两个特性:一个是它能够被所有组件访问到,一个是他身上要有 o n 、 on、 on、emit等api,第一个问题它能够被所有组件访问到,放在VueComponent上实现不了,因为我们说过每个VueComponent都是一个全新的构造函数,放在自己vc上更不可能,那就只有你能访问了,那么顺着那条线,是不是答案已经出来了,没错,要让所有组件都访问得到,那就只有Vue的原型对象了
第二个问题,怎么让他身上有这些api,这些api其实都是在vue原型对象上的,所以我们vm、vc都可访问得到,但是将它等于一个vc不太现实,因为我们是将它定义在入口文件的,那就只能为一个vm了,并且还要在vm的beforecreate这个生命周期函数来赋值,为什么要在生命周期函数里来赋值,因为这里讲究一个时间效应,太慢了不行的,前面也已经看过了ref打标识这种方法调用on这个api就是在mounted生命周期函数里面调用的,为什么因为讲mounted的时候就说过这里面是万物的开始,呱呱坠地的时候,什么定义定时器、自定义事件等等都是在这里,而且也只能在这里,不然时间晚了,我触发了你还没绑定好那怎么可以,所以说我们讲究一个时间效应,如果等到vm都定义完了,来一个x=vm,这个时候已经整个都挂载到页面上去了,我们组件里面的mounted也早已经执行完了,你的x都还没有这些api那就会报错,然后还只能写在beforecreate这个生命周期钩子,为什么,也不是说只能嘛,最好写在这里,created感觉也是可以的,因为这里数据挂载这些都还没做,但是也说过vue内置的一些事件、api之类的定义完了,我要这些就够了,我不需要数据
所以最终定义成这样就是最标准的了,而且我们一般x叫做$bus,因为这个东西的作用一是本身有点公交车的感觉,谁都能用,还有一个就是他的中文意思还有总线的意思
有一点必须要清楚,我想把A发送到B,那调用emit发射这个api的就是前者并且参数是数据,而后者就调用on并且参数为回调,你就拿到这个数据了,想干嘛干嘛了
然后就是,定义自定义事件也就是on肯定一挂载就要定义,所以写在mounted里面,而发送数据这边决定触发事件的方式
既然用到了出生mounted,最好也在临别beforeDestroy解绑我们的事件,一定要写事件名
9.2TODOList全局事件总线
又可以继续完善之前的案例了,其实父给子传数据,props是最好的方法,子给父传,用我们原始方法也行(props),自定义事件也好,都差不多的,这里最需要用到全局事件总线的,是孙给爷传,之前一直靠着list这个中间量props,他自己也没用只是给item带过去函数
定义好api
我们是item给app传,那就在item先emit,都是传过去id进行更新我们的数据里面的completed是否勾选和筛选进行删除操作
然后再mounted里面声明事件
十.消息订阅与发布
一种组件间的通信方式,适用于任意组件间通信
如果A需要C的数据,那么A就订阅消息,C就发布消息即可
原生JS无法轻松实现消息订阅与发布,需要第三方库(这里推荐 pubsub-js)
先安装这个库
哪里需要就在那里导入,我要把student的学生姓名传给school那他们两个都需要
,导入时注意 直接pubsub没有js
学生这边发布信息,参数为要传过去的数据,用到的api pubsub.publish,第一个参数为消息名,发布与订阅都需要的
学校这边订阅消息用到的是 pubsub.subscribe接受两个参数,第一个是我们的消息名字,所以一般取名为msgName,第二个参数才是我们传过来的数据,一般取名data,注意消息订阅同自定义事件、全局事件接收数据这边都是放在mounted函数里面的
注意一,同样需要在beforeDestory函数里面取消订阅,用到的api .unsubscribe,但是我们这里的消息订阅有点类似于定时器,需要一个变量去接收,这边取消订阅为这个变量名,注意不是消息名
像这样是拿不到的,都是两个作用域了,把它放到实例对象上去,作为一个属性即可
注意二:直接在订阅消息里面写这个函数同样要写为箭头函数,不然this会乱,或者也可以在methods里面写,这里直接调用
十一.TODOList编辑
新增一个编辑功能,要完成的逻辑就是,当我们一点击编辑按钮,对象会新增一个属性edit为true,然后页面上两个标签一个span一个input通过edit的值去条件渲染是否展示
很明显我们确实能给一个对象添加一个属性,但是这样添加的属性并没有setter所以也无法被vue检测到而重新解析模板,应该用vue.set的方法,这里还只能用我们的第二种$set的方法因为这里拿不到Vue
最好用v-show毕竟这里会频繁切换
这里应该完善一下,不是每一次点击编辑都会去创建一个属性,有这个属性了直接改值就可以了
我们失去焦点后要把值改到数据里面去的逻辑,注意还记得得到这里吗,事件处理函数不传参数默认为e,传多个参数的时候要使用e,需要传参$event
利用全局事件总线把我们的id和要改的数据传过去,这里是发射数据应该是 emit
1.nextTick
bug
可以输入空值并保存为新的值
有一个很重要的点,我们需要一点编辑,就让input框获取焦点吧,这样才符合常理,我们可以通过打标识,来获取这个input框,然后在我们点击编辑的事件中,最后一步通过$refs来让他获取焦点
想法是好的,但是很遗憾这样做并不行,分析一下,我们vue的工作原理是当一个函数的内容执行完了才会去重新解析模板,如果完成一行数据就去,那一直都在来回就很耗费资源了,所以这里当我们点击编辑的时候刚好把edit改为了true,页面接收到true后文字消失,input出现,但是关键就是这个时候就处于这个节点,拿到了true还没给到页面上,这个时候继续往下执行focus这一行代码,我们的input都没出现在页面上怎么来获取焦点?
又是因为获取焦点的问题,前面因为为这个栽过一次,但是现在不用怕了,vue针对于这个情况专门出了一个api,而且这个api还挺常用,.$nextTick,他后面跟的是一个回调函数,他的意思就是当我们完成下一次DOM更新操作后才会去执行里面的回调函数,也就是这一次编辑改为true更新到DOM上面后才会回来执行这里面的回调
十二.过渡与动画
1.动画
先完成一个点击显示隐藏的案例
定义好我们的动画效果,在vue里面虽然可以简便一点,但是效果还是要自己写写的
我们要的效果就是点击显示就给我显示同时添加一个来的效果,点击隐藏同理,如果原生js写就需要去判断逻辑等等
vue能做的就是可以让我们轻松实现显示隐藏的动画,就目前来看jq好像是直接调用哈,jQuery的动画直接调用就能做到,回到正题,需要添加一个标签 transition这个标签里面放我们的要显示隐藏的元素
同时我们的动画的类名有特定的类名,显示是 v-enter-active,隐藏是 v-leave-active,配置好这些后,vue就能在合适的时机给你添加合适的动画
注意:
每一个 transition标签可以自己取名字,但是取了
以上是关于vue - Vue介绍的主要内容,如果未能解决你的问题,请参考以下文章