Vue一文学会?
Vue大家都知道就是一个国内非常流行的框架,最近因为过了许久没用Vue对于Vue的许多早已淡忘,所以目前正在复习Vue顺便记录一下笔记,以后忘了也可以进行查证,因为这是根据自己的性格所写的笔记,可能大家会看不懂,如果看不懂请尽量不要试着看,可以去看看其他的博主写的文章!
起步
如果需要知道怎么使用webpack手动搭建vue环境的麻烦传送
那么我们还是使用Vue的官方cli进行构建Vue程序 npm i -g @vue/cli
然后我们 vue create -n suiyue_m
-n选项你随意加不加,是用来表示不初始化git的
然后就是一个选项栏
我之前已经保存过一次选项了所以大家可以看看,我这里在选择一次
选择最后一项按回车键进入二次选择
空格键选择
大家先跟着我的选择选吧,一般就是这样,最多就是多一个typescript什么的之类,然后我们直接敲回车
之后这里又有一个选项
意思是要不要开启历史模式,什么区别呢?
就是路由的时候
默认是启用的(因为Y是大写,n是小写),启用此历史模式就是
example url: http://www.xxx.com/user/xiaoming/info
不启用就是熟悉的
http://www.xxx.com/#/user/xiaoming/info (应该没记错)
(启用此模式需要配置服务器因为,这样发送http请求的话会请求对应服务器对应的文件夹下的index.html所以需要进行配置,具体配置请移步Vue官方文档,不放链接了,因为我忘了那个链接了)
所以我们选择N,主要是懒得配置服务器了
下面就是配置css预处理了,我喜欢用less大家随意按照自己喜欢的擅长的那种进行选择,下一个选项就是
语法检测eslint然后我默认就选择第一个了,代表eslint用来检测语法没有错误,其他的不了解也不使用
下一个默认也选择第一个代表在保存时进行语法检查
这个的意思大意就是Babel,PostCss,ESLint这些配置的配置文件(个人理解,错误勿怪)存放在一个单独的文件还是跟package.json文件放在一起
那么就选择第一项了,放在一个独立的文件中
最后一个就是是否保存这次的选择,然后因为我保存了所以有三个选项大家随意保存不保存,如果敲y的话会让你输入这个preset的名字,默认是不保存的,然后就开始下载依赖什么的了
最后想说的就是建议大家使用yarn或者pnpm这等之类的npm包管理工具,因为速度快楼主使用的是yarn
大家可以使用
npm i -g yarn
进行安装
然后我们直接运行Vue服务
默认是不会打开浏览器自动运行的需要大家手动打开浏览器查看页面,好了关于vue-cli的用法就结束了
接下来就是Hello Vue的实现了,我们先更改一些配置文件
在文件夹的根目录新建一个vue.config.js文件,插入一下这些内容将vue服务的端口改为3000,让它自动打开浏览器,至于热更新本身就热更新了
然后我们重新
yarn serve
然后就会看到我们熟悉的一幕了
因为3000端口跑了react的项目所以缓存了图标
然后接下来就是Hello Vue了,直接打开App.vue
将template下面改成这样
就是一个Hello Vue了
那么因为我是复习我就想到什么写什么了
进阶
-
计算属性与监听
计算属性,类似于一个Vue属性但是计算属性是实时进行计算出来的,计算属性可以依赖Vue的属性,当Vue的属性改变时,计算属性会同步的改变,类似于
然后其实下面就是一个计算属性永远不会更新的死节
因为下面的这个计算属性并没有依赖任何Vue的属性导致此计算属性永远也不会更新,其实此计算属性的效果也可以同样使用methods进行替代,类似于
然后就是此方法与使用计算属性的不同之处在于,当页面被触发渲染时计算属性所依赖的属性改变时才会重新计算求值,但是函数每一次页面重新渲染时都会进行重新的一次计算求值
监听
使用属性名作为函数名,每一次当对应的属性值发生改变时会进行调用对应的函数(不进行详细的截图了)
class与style的绑定
绑定class
使用v-bind指令绑定class传入一个对象,属性名决定类名,是否指定此类名决定值的真或者是假,同样的我们也可以将class后面的属性提出为一个对象指定变量的方式
同样的class后面也可以指定为一个函数或者一个计算属性要求是返回对象形式的
class绑定数组语法
渲染为
同时也可以在数组中使用三元运算符来指定对应的类名
渲染为
最后就是还可以在数组之中使用对象来进行混入
(对组件传递class类名会默认绑定到此组件的根元素身上)
style绑定
(在强调一遍,vue中指令后面的引号中的字符串会被当做js代码进行执行)
同样的因为style是一个对象我们可以将这个对象取出直接指定变量的名字进行绑定也可以类class的绑定方法
style数组绑定法类对象方法
指令
v-if
使用v-if后面的表达式为true时才会渲染对应的html元素,否则不会渲染(使用的是上dom树和下dom树)
我这里用了一下v-if
Hello World
通过isShow控制h1标签的上树与下树,这里使用的v-if是直接从dom树上面删除的,如果需要频繁的操作dom需要使用另外一个指令(暂时忘了)
vue还提供了一个指令与此指令配套,就是v-else,我们稍微修改代码
Hello World
h2 ---> Hello World
你会发现使用vue能够让你用极少的代码来操作dom
vue2.1新增了一个v-else-if指令
v-else 必须添加到v-if或者v-else-if后面否则无法被识别
我们继续修改代码
Hello World
h2 ---> Hello World
h3 ---> Hello World
我们直接将isShow改变为数字通过每一个区间的不同渲染不同的元素
v-show --> v-show指令只是单纯的切换标签的display属性,所以并不是真正的销毁一个dom元素
v-if初始化加载开销低,每次切换开销高 v-show初始化开销高,但是切换开销低
用法一般是: 只需要渲染一两次的dom元素可以使用v-if,需要频繁显示隐藏的一些效果需要v-show
v-for
-
{{ item }}
可以使用of替换in,这样更像迭代器
v-for="item of items"
遍历数组有两个参数
(item,index)遍历对象有三个参数 (value,name,index)
数组更新检测
data中数组的某一些方法也会触发vue的视图更新
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
当data中的数组通过上面的方法数据发生改变时同样会出发虚拟dom的更新进而刷新视图
(上述方法统称为变异方法,就是会改变调用这些方法的数组)
由于JavaScript的某些限制,vue无法监控两类数组的变化
- items[0] = "Xiao Ming" 直接修改某一位置的值
- items.length = 99 修改数组的长度
为了解决第一类问题,可以使用下面的两种方法
- Vue.set(items,0,"XiaoMing")
- items.splice(0,1,"XiaoMing")
解决第二类问题的方法
items.splice(newLength)
(我这里直接写的items,大家一定要使用vue的实例打点调用)
由于JavaScript的限制vue无法检测对象属性的添加和删除,例如当Vue对象实例化之后可以为这个实例化对象vm(viewModel)继续添加属性但是这时候添加的属性vue是无法动态监控到的(此属性没有与vm进行绑定)
解决方案:
Vue.set(obj,newProp,newPropValue))
(这代表是Vue这个对象的静态方法,不是实例化vm的方法,实例化vm也有一个此方法为$set()这个方法是全局set方法的别名)
v-on
v-on:事件名.事件修饰符 --> 一个简单的使用
{{counter}}
我们除了直接在v-on后面书写语句外我们还可以书写方法(methods中定义的)
{{counter}}
一样可以实现点击按钮+1的操作,然后我们除了可以使用方法外我们还可以给这个方法进行传参,类似于
{{counter}}
有时候我们可能需要访问原声事件对象的一些属性,我们也可以将$event这个属性传递给方法
{{counter}}
事件修饰符
按照vue官方的说法就是事件中就是纯粹的逻辑而不去处理dom事件的细节所以我们可以使用事件修饰符做一些操作事件细节的事情如:阻止默认事件,阻止事件冒泡等等
比如说我这里有一个a标签我这个a标签点击之后就会跳转到baidu去
那我想干啥呢?我想要这个a标签点击之后counter+1,所以我就这样写
那么你就会发现点击了这个a标签之后counter+1后又跳转到baidu去了,这就是所谓的默认事件,顾名思义就是a标签本来就是表示一个链接的点击之后自然是要跳转到对应的地址去,所以我们可以通过
prevent
事件修饰符阻止默认事件,我们可以试试
这样之后不管你怎么点击a标签也只会响应click事件不会跳转页面了
常用的修饰符
- stop 阻止冒泡
- prevent 阻止默认事件
- capture 捕获阶段执行事件
- self 大致理解为捕获或者冒泡到这个元素的事件不会执行,只有直接出发此元素的事件才会被执行
- once 代表只执行一次
- passive 这个东西代表立即触发默认事件,同时会使prevent无效
按键修饰符 --> 可以通过按键修饰符绑定keyboard事件时监听某一个键
- enter
- tab
- delete (捕获“删除”和“退格”键)
- esc
- space
- up
- down
- left
- right
这是一个使用按键修饰符的小例子
就轻松实现了按下特定的键做某些特定的事情了
同时我们也可以自定义按键修饰符
我们可以使用
Vue.config.keyCodes.w= 87
定义一个w的按键修饰符键盘码为87
效果显而易见,同时vue2.1新增了系统修饰键(个人觉得就是几个特殊的键)
- .ctrl
- .alt
- .shift
- .meta 键盘上的有win图标的键,mac就是花键
所以我们可以这样玩
这样的话就是不按住ctrl键不会响应点击事件的,还是一个非常亲名的功能
我这样就可以制作一个按住alt+c清楚输入的内容的一个输入框
时候我们就可以骄傲的说我们的输入框有快捷键了
这里说一下上面绑定keyup时使用的是.alt.67
后面的67是键盘上的c键的键盘码我们绑定事件时也可以直接将键盘码点上去,然后就是
v-on有一个缩写 比如v-on:click.prevent.ctrl
--->@:click.prevent.ctrl
可以直接缩写为@
vue2.5新增了一个用于键盘事件的修饰符
- exact
我这里直接就将官方的说明粘过来了,一看就懂
vue2.2新增了鼠标的按键修饰符
- .left
- .right
- .middle
那么我们就可以实现一个右键点击+1的操作了
那么这时候就发现只有右键点击才能够+1了(而左键点击又坑爹的跳转了),并且当我们按住ctrl之类的系统修饰键是无效的
v-model --> 数据的双向绑定
我们快速实现一个表单认证
同时此指令还有一些修饰符就如v-on一样
- .lazy 默认使用input中的input事件进行双向绑定,使用此修饰符可将双向绑定的事件改为change(当输入框失去焦点时更新)
- .number 默认输入的任何字符都是字符串,如果你需要让用户输入的数字转换成number类型可加
- .trim 可以自动去除用户输入字符串中的首尾空格
其他指令介绍
(v-if,v-model,v-for,v-on)
v-text --> 指令用于绑定后面值到元素的innerText中
这样就完成了绑定,这个指令会替换掉原本元素中的内容(元素中的所有内容都会被替换包括子元素)
你会发现这个指令解析出来就是一个单纯的字符串
v-html
这个指令可以解决上面的问题,v-text中的内容无论是什么都会被解析为字符串
v-html与v-text类似,但是会将类似于html的代码解析为html嵌入元素中
lfjlsfsd
上述两个指令都会替换掉元素中的所有内容,但是很灵活可以通过函数或者一些简单的表达式动态的求值,同时替换元素中的所有内容也算是一个缺点,我们可以使用vue插值表达式就是双大括号{{}}进行动态解析某些值,插值表达式不会替换原宿所有内容,解析后的值就会替换在插值表达式所在的位置,插值表达式计算出的值为纯字符串
{{msg}}
有一种情况我们可以预见
Hello {{msg}}
这时候渲染是没有任何问题的
但是当我们进入调试模式调低网速时
这个地方更改为slow 3G
无语了,我这里是vue cli服务的情况
模拟不了那种情况,我就直接说了吧,大家应该能够明白是什么情况吧
当网速慢的时候我们写的插值表达式可能就会原样输出(就是该咋样咋样的输出,因为这个时候网速慢vue.js这个文件可能还没有请求过来,因为肯定是优先载入html文件再从html文件中的script标签中载入vuejs文件)这个时候就暴露了,等到vuejs请求下来才会更新这些插值表达式,但是这样就有点坑了,不是很美观,所以vue提供了一个指令用来控制此等情况
v-cloak
这个指令就非常简单,就是插值表达式暴露到屏幕的时候可以为对应的元素暴露一个v-cloak属性
(我这个真的不行,模拟不了
从图片中可以看出,这是服务端渲染html结束然后返回给客户端的,这应该是服务端渲染的(个人猜测,但是8,9了))
就是当有了这个v-cloak属性时我们就可以写类似的样式
因为这个属性在插值表达式解析完毕之后会自动去除(removeAttr..)
v-once
顾名思义不说了
(就是当这个元素第一次渲染之后,之后的数据变化触发render方法更新视图时这个元素不会在被刷新了永远也不会了)
Hello {{msg}}
你就会发现无论你怎么点击按钮,试图也不会刷新因为初始化生命周期已经执行过一次render了,所以以后不会刷新视图了,哪怕数据怎么发生变化
除非你直接人肉修改此选项
Hello {{msg}}
哈哈,一般是不会这么做的,因为这是不被vue提倡的
v-pre
跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
例子就是
Hello {{msg}}
你看到Vue算我输
就像于Vue不会管这个元素了,这个元素的所有都跟普通html一样了,这些在vue中认识的指令也无用了,浏览器不能认识的一切都不会起作用了
v-slot
这个东西后期完善更新,需要先了解组件
(date:2019-06-23 13:21:54)
组件基础
声明一个组件的最简单的方法就是通过Vue.component方法,然后就是我想说的就是因为vue-cli声明组件用的是另外一种方法所以我们只有新建一个文件夹不用打包工具来写了,我这里直接去node_modules文件夹下的vue中将dist目录下的vuejs复制过来的,然后直接新建一个index.html文件夹如下
大家像我这样写完这个index.html之后使用file协议在浏览器中打开这个文件就会发现我之前所说的这种情况了,现在我们将网络改为slow 3G然后刷新,反正你就是会看到插值表达式会一闪而过就这个情况
算了其他的不多说了,我们首先看一下最基础的定义组件
{{msg}}
然后我们就可以在浏览器中看见hello组件了,这样便意味着我们已经自己制作了一个组件了,大家可能在制作组件的时候有一点不爽的就是为什么template写html代码没有代码提示什么都要手写就是不爽对吧,所以我们可以使用这种方法定义template
{{msg}}
hello组件
我们可以直接将组件的模板写在template标签中,这样就又有了我们熟悉的代码提示了(是不是非常棒),同时我们自定义的组件就跟新建Vue的实例一样大多数关于组件的方法都会有比如说data啊methods啊都有
这样就继承了Vue的大多数属性
{{msg}}
组件的生命周期
我觉得关于Vue组件的生命周期只需要一张图就可以明白了
直接就将Vue官方的一张图fetch过来了
- beforeCreate() 在组件创建之前此时无法访问vue实例(this)
- created() 创建完成之后已经可以访问this实例和数据
- beforeMount() 在组件挂载到视图之前
- mounted() 组件已经挂载到视图上以后
- beforeUpdate() 改变数据触发视图更新之前
- updated() 视图已经更新后
- beforeDestroy() 组件将要被销毁之前(下树,display:none不算,是销毁)
- destroyed() 组件销毁之后
这就是Vue组件的生命周期了
{{msg}}
关于组件的生命周期就到这里了
组件的传参
那么我们使用一个自定义组件肯定是需要动态的显示某些内容的,这时候我们就需要传递一些参数过去了,那么组件之间是怎么传参的呢?
通过props就可以实现组件之间的参数传递
我们看一下
{{count}}
那么vue是不建议也不可以在子组件中直接操作props的,因为此props为父组件传递过来的,子组件无论怎么改变此props的值,当父组件触发虚拟DOM刷新页面时都会重新传递props意味着子组件改变的props并不会长久的储存下去,所以Vue提供了一个类似于自定义事件的这种机制
{{count}}
兄弟们看注释吧,代码结合注释这还不懂
(废话一大堆:说明不适合自学啊,这里说一下我是自学的前端开发的,不是不愿意去培训机构,相反其实还是挺想去的,只是因为家庭的原因(最主要是没钱啊)所以只能苦逼的自学了,其实我想说的是不管是去培训机构还是自学还是在学校我想说的就一点,你永远也不可能会一直有老师带着你,技术是在不断的迭代的,谁也不知道明天又有哪种框架哪种解决方案火了,就比如webassembly一样,谁知道那天会火说不定到时候的前端真的可以说又是一场革命了,你想到时候的前端有接近原生的代码执行效率,无论是开发网站还是配合electron或者nw开发跨平台的桌面应用或者搭配react native或uni-app或weex等等开发移动端的软件,毫无疑问的一点就是以后的前端谁也说不准,所以我觉得自学反而是好的,自学的过程中虽然很难但反而是最容易学通学透的因为我们没有人为我们解答问题,每一个问题都是需要自己去研究解决的,可以说每一个人都在学习,不过有的人是在学校学习有的人在工作的时候学习,或者说每个人一直都在学习,比如你刚出生你不学走路,不学说话,等等...)
咳咳扯远了,总而言之大家可以想象一下以后的前端是一个怎么样的情况,现在webassembly已经支持c/c++/rust语言编译为asm.js这种编译的JavaScript代码进行在浏览器端执行了
我们接着说一下,子组件通过自定义事件将自己的需求暴露给父组件,由父组件负责数据的更新(值是由父组件传递下来的,不父组件维护谁维护)
那么我想要求子组件点击按钮不跟父组件的按钮一样了,我要点击子组件的按钮我想+多少就多少应该怎么办呢?
那么我们继续完善代码
{{count}}
这时候我们就可以通过自定义事件传参的方式,来实现这个需求了,如果传递了多个参数请在父组件中@自定义事件后传入一个函数接收多个参数
这里我又想实现一个自定义的输入框,但是当我输入v-model的时候我发现这个指令失效了?
{{msg}}
使用v-on绑定input事件在代码中emit一个input事件到自定义组件身上,这样就可以被v-model接收到了,从而完成双向数据绑定,懂了吗?
Vue提供了一个自定义组件用于动态显示我们的自定义组件的
{{msg}}
component标签用于控制渲染我们的组件通过is属性动态渲染不同的组件已达到更好的交互效果,这里组件的切换是上树下树级别的
因为组件执行了生命周期中的destroyed方法
(那么关于Vue的基础就已经说完了,接下来就是Vue深入组件的一个部分了)
深入了解组件
组件注册
首先关于组件命名的要求,按照Vue官方所说的那样组件命名有两种方式
第一种:custom-input 就是字母之间或者组件名之中必须出现一个横线用以区分原生标签
第二种:首字母大写 CustomInput 驼峰命名法,大家随意喜欢那种都是可以的
然后就是到目前为止我们注册组件还是使用的是Vue.component这种注册组件的方式是全局注册的,全局注册的组件无论在哪一种层级还是哪一个Vue实例都是可以使用的,接下来给大家说说如何局部注册组件,局部注册的组件只能在当前注册的组件中使用
{{msg}}
然后我们在这里一共定义了两个组件其中一个组件注册为另一个组件的子组件,且这个组件注册到Vue实例上,那么我们接下来直接在html中访问这个CustomInput组件看看会是什么情况,你会发现Vue不出意外的报错了
{{msg}}
那么我们接下来将这个组件放到customdiv组件中试试
{{msg}}
那么我们发现不出意外组件已经正常渲染了,因为Vue实例的template已经挂在到div#app上了,所以我们的子组件一定要写在template上而不是那个标签中的内部
Prop
HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:
Vue.component('blog-post', {
// 在 JavaScript 中是 camelCase 的
props: ['postTitle'],
template: '{{ postTitle }}
'
}
那么这个限制在字符串模板是没有限制的,前面也说了template属性可以给一个选择器用来定位html template标签中的内容,这就是所谓的DOM模板,字符串模板就是我下面这样template之后直接手写这个模板,但是你也知道的没有代码提示纯手写贼难受
{{msg}}
那么关于props首先要了解的就是组件中props属性的类型,前面我们写的props都是数组的形式出现的就像我上面贴的代码一样,其实props属性还可以是一个对象,且看下方代码
我接受的username是{{username}} 我接受的password是{{password}}
我接受的age是{{age}}
那么我这里故意将age设置为字符串不出所料的是果真是报错了,出乎意料的是值还是显示出来了
那么我将age重新改为number类型的时候报错就消失了
就不贴代码了,这是应该知道怎么改的
那么我们可以直接这样传递对象
然后可能我们需要传递对象的属性进去,那么vue就提供了一个非常简便的方法,那么可能我们正常需要这样写
那么Vue就提供了一个简单的方法快速通过props传递一个对象的所有属性
大家记住,这种方法一定要在元素中props中写对象的属性,不要傻乎乎的写对象的名字在哪里啊
单向数据流
大家应该也知道我之前有说过从父组件传递下来的props是不能进行修改的,因为哪怕你接收的props如何修改,当父组件触发虚拟DOM时props又会进行重新传递导致子组件重新渲染新的props值,这就是所谓的数据的单向流动,即数据总是自顶向下一层一层传递的(可能这时候大家就会想了,如果层级非常多的话岂不是从顶级组件传递下来会有那么几个组件只负责props传递数据到目标组件上,那么这个问题我们需要使用vuex进行解决,后面说),这样我们就非常清楚数据的一个流动,并且如果子组件修改了props那么数据的流向也不是很明确了,那么如果确实需要修改props呢?这里有两种解决方案,要么就是直接将传递过来的props绑定到自己的data上
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
另一种方法呢就是直接通过计算属性依赖这个props的值计算我们需要的值
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
两种方法各有各的应用场景,这里就不深入了解了
注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态。
props验证
这个验证跟react的prop-types
库非常相似
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
// username:String,
// 多个可能的类型
// age:[String,Number],
age: {
type: Number,
// 指定默认值
default: 18
},
password: {
// 指定类型
type: String,
// 必须传递
required: true
},
// 自定义验证函数
username: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
// 也可以是一个带有默认值的对象
/* obj:{
type:Object,
// 对象或者数组的默认值必须从一个factory function(工厂函数)中取
default(){
return ["a",18,"c"]
}
} */
},
那么这个时候定义之后我们回到浏览器刷新就会发现
报错了,但是值也取到了,那么我们修改一下这个函数
// 自定义验证函数
username: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['小钢炮', 'warning', 'danger'].indexOf(value) !== -1
}
}
这样就ok了
注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的属性 (如 data、computed 等) 在 default 或 validator 函数中是不可用的。
类型检查
type 可以是下列原生构造函数中的一个:
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
额外的,type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认。例如,给定下列现成的构造函数:
function Person (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
//你可以使用:
Vue.component('blog-post', {
props: {
author: Person
}
})
//来验证 author prop 的值是否是通过 new Person 创建的。
如果有这么一种情况,我们的组件是用来发布出去的,那么不知道用户会怎么样的去传递属性,那么如果假如说我使用我这个组件,我传递了一个我根本就没有在props中定义过的属性会怎么样呢?
Hello my
那么你会发现,上面我的这个自定义组件的根元素有一个已有的类名,我在使用的时候传递了两个没有定义的属性过去,我们看看html架构是个什么情况
你会发现没有被props定义的属性都会直接继承到组件的唯一根元素身上,如果你不想组件的根元素继承这些属性的话,你可以在定义组件的时候加上
inheritAttrs: false
那么我这里加一下,刷新的时候发现
我们没有被props接收的属性都被忽略了,class合并了后面有说原因,那么我们使用了这个选项之后就没办法使用传递过来的属性了吗?其实Vue将没有被props接收的自定义属性都封装到了一个组件实例的$attrs属性上,我们修改打印一下
mounted() {
console.log(this.$attrs)
},
Vue官方说过的一句话还是非常哲学的,对哲学:
这个模式允许你在使用基础组件的时候更像是使用原始的 HTML 元素,而不会担心哪个元素是真正的根元素,没错你会发现上面的baseInput这个自定义的组件我完全当成input再用,因为属性什么的都是用的input的属性
注意 inheritAttrs: false 选项不会影响 style 和 class 的绑定。意思就是说加了这个属性,class和style还是会被合并,不会被这个属性影响,我上面就是一个活生生的例子
自定义事件
不同于组件和 prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称.
(事件名不存在组件名那样的自动转换大写字母的名称加横线,事件名必须$emit()什么事件名就必须@什么事件名称)
借用Vue官方的一句话
(不同于组件和 prop,事件名不会被用作一个 JavaScript 变量名或属性名,所以就没有理由使用 camelCase 或 PascalCase 了。并且 v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 v-on:myEvent 将会变成 v-on:myevent——导致 myEvent 不可能被监听到。因此,我们推荐你始终使用 kebab-case 的事件名。)
意思就是在template中@的事件名如果有大写字母会被自动转换成小写导致事件永远不会被监听到,所以可以说是自定义事件必须使用短横线命名法类似于 CustomEvent ---> custom-event ,除非是字符串模板否则可以说是必须使用短横线命名法
自定义组件的v-model --> vue2.2新增特性
比如说我们自定义一个文本输入框
{{msg}}
这样我们就自定义了一个input输入框,但是个人感觉好像没什么用处似的,有的时候我们可能很想监听我们的自定义组件的原声事件,那么v-model提供了一个修饰符
- .native --> 用于绑定原生事件
可以这么认为,native就是一个把组件变回原生DOM的一种方法,给vue组件绑定事件的时候,一定要加上native,如果是普通元素就不需要,默认vue会将原生事件绑定到组件的根元素上,如果根元素不支持此事件就会静默的失败,例如
{{msg}}
像这个例子
Vue毫不客气的报错并且不会获得任何数据
具名插槽
听名字就知道就是有具体名字的插槽了,什么意思呢?具名插槽有什么用?
有时我们需要向一个组件中传递多个插槽(一个slot就是一个插槽),那么肯定这样是不对的
我
这样的话就相当于重复了几次插槽的内容而已,完全无法分隔开各插槽之间的内容,这个时候具名插槽的作用就来到了,我们可以这样书写代码实现不同插槽之间的分隔
header
nav
section
footer
header
nav
section
footer
这样我们就分隔开了每一个插槽,这就是具名插槽了,那么其实默认的
也是有名字的叫做default,我们也可以指令v-slot:default或者不指定名字的标签当会传入到默认的插槽中,如果没有提供默认插槽那么就会放弃对应默认插槽中的内容
关于具名插槽就介绍到此了,接下来说一下作用于插槽
作用域插槽
简单来说就是让插槽中的内容访问对应组件中的内容
{{username}}
{{username}}
这就代表着默认插槽的作用域与其所在的组件同级(不是父子是同级)所以无法访问其所在组件的一些数据
那么我们就需要这么玩了
{{my_props.username}}
{{username}}
这样我们就成功的将数据fetch到了,以上就是作用于插槽的使用讲解了
上述作用于插槽在提供组件中如果没有具名插槽时可以简化书写为
还可以进一步简化
上述简写方法只能在组件中没有具名插槽中使用,如果组件中有具名插槽还请不要使用简写,否则语法会无效并且Vue会发出警告,切记
解构插槽prop
作用域插槽的内部工作原理是将你的插槽内容包括在一个传入单个参数的函数里
function (slotProps) {
// 插槽内容
}
所以我们可以直接对插槽进行解构,像这样
浏览器正常渲染输出,同时我们可以在解构时重命名插槽
我们设置可以直接给插槽赋默认值
vue2.6+ 新增动态插槽名
...
就是可以通过一个变量或者计算属性函数等等动态计算插槽名字
具名插槽的缩写,跟v-on和v-bind一样具名插槽也是有缩写的,具名插槽的缩写 v-slot:header ---> #header v-slot:缩写为#,跟其他指令的缩写一样该缩写只有当插槽有参数才有用,这意味着一下语法是无效的
{{ user.firstName }}
我们必须明确制定他的参数才行
{{ user.firstName }}
异步组件
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染.
这一个简单的例子演示了如何异步加载组件,你可以在此函数中执行任何异步的请求最后通过resolve传递给vue
断断续续才发现居然写了这么多,所以我决定拆分开来写了,因为vue还有差不多这么一篇文章的知识还没有接触,所以我决定将另外的一些知识什么的都写在下一篇文章中,同时发现自己写得有那么一点点的乱,我决定最后来一个总结吧
最后来一个总结
- 计算属性 -->obj
需要依赖于组件的data才能够进行数据的更新,如果data不更新,计算属性永远不更新
- 监听 --->obj
监听的属性为函数名,每一次这个属性的改变都会当做参数传给对应的函数,然后自定义逻辑
- class与style的绑定
对象法 class: key --> 类名 value-->bool(决定是否绑定此类名)
style: key --->样式名(驼峰) value---> 样式的值
数组法 class: 每一个变量都表示类名,值为bool
style -->每一个变量必须是一个对象,key-value代表样式名和样式值
同时也可以使用三元运算符,或者直接引用data中的对象或者数组等等
- 指令
- v-if
- v-else-if (必须在v-if后,否则无效)
- v-else (必须在上面两个指令后,否则无效)
- v-show
- v-for
- v-on --> @
-->事件修饰符
- stop
- prevent
- capture
- self
- once
- passive
-->按键修饰符 - enter
- tab
- delete (捕获“删除”和“退格”键)
- esc
- space
- up
- down
- left
- right
-->系统修饰键 - .ctrl
- .alt
- .shift
- .meta
--->2.5新增键盘事件修饰符 - .exact
--->2.2新增鼠标按键修饰符 - .left
- .right
- .middle
--->组件的修饰符 - .native
- v-bind --> (:)
-->修饰符
- .sync
{{msg}}