Vue核心
快速入门
入门
不写了,参考文档
引入vue.js开发版的时候,控制台会提示,这个提示可以关掉。
Vue.config.productionTip = false
el
也可以通过`.$mount(‘#root’)挂载
后面用到了es6的简写,如果不了解es6语法的可以适当补充一下
注意事项
- vue不能挂在到html和body上。
- vue作用范围包括子元素
- 建议使用id选择器
- 一个vue实例对应一个容器,一对一
- 插值里可以写js表达式,一个表达式可以生成一个值(变量,运算,三元,函数…)
- data里面写多个同名属性,会覆盖,只有最后一个有用。
- methods里面的最好不要写箭头函数,否则会导致this从vue变成了window。
数据代理
大概是vue的MVVM的原理
Object.defineProperty
可以用来给一个对象添加属性,此时添加的属性是具有封装性质的属性,这个属性是否可枚举,可改,可删除都是可以设置的,默认都是false。该函数的参数有三个,分别是对象,属性名,和配置对象。配置对象里可以设置get
和set
函数,来决定该属性的值从哪里获取。而vue
将data
对象里的东西保存在自己的_data
里,然后当访问_data
或者修改时,便会调用get
和set
函数,从而达到数据更新的目的。且只有data
里面的才会数据代理
我的感觉时重载了.
运算符,用户访问vm.name便会调用vm._data.name,但是_data
里进行了数据劫持,并不直接提供,而是再度进行封装。总之js的基于对象不是基于类的思路,而是走了原型这条路。具体关于js的面向对象可以参考这里。
认识指令
vue主要的一些指令,后面详细解读其原理和更多用法
<h2 v-text="message"></h2>
替换所有
支持字符串拼接
v-html
会按照html渲染
v-on:
、@
,可以传参,可以简写@click = "isHot = !isHot"
v-show``v-if
前者只改变display属性
v-bind:src = "xxx"
、:src = "{active:isActive}"
可以使用对象形式或者三元表达式
v-model
双向绑定,只能用于输入型元素,需要有value属性,另外,v-model:value
可以简写为v-model
v-for = "(item, index) in arr"
v-message
和某个变量双向绑定
v-cloak
一个特殊的属性,没有值,vue在接管以后会删掉这个属性。因此,可以利用css来防止因为网速慢而显示出{{}}
这样的插值表达式。cloak意思为斗篷。利用css属性选择器[cloak]:{display: none}
就行了。
v-once
动态渲染之后,即为静态数据。
v-pre
跳过该元素的渲染,如果确定该元素不需要vue,那么加v-pre
效率更高
事件修饰符
事件修饰符是在事件名称后直接
.
一些属性,属于一些简便的写法。下边举几个例子
可以使用事件修饰符
@keyup.enter="myFun"
表示回车键,类似的有delete,esc,space,up,down,left等等。特殊的例如CapsLock要用caps-lock。另外tab本身再keydown的时候会切换焦点,所以要想绑定需要用keydown。还有几个比较特殊的键,ctrl,alt,win,shift,当他们与keyup绑定的时候,需要组合键(alt+1)才能出发,keydown正常。如果想用自己的别名,需要再js配置一下,例如给回车键起别名:Vue.config.keyCodes.huiche = 13
。想传参就加括号,不想传参爱写不写!但是写了如果传参,记得多传一个$event,别搞丢了事件。
再有,
event
有一个preventDefault()
的方法,也可以通过@click.prevent
实现。e.target
是触发事件的对象同理,为了阻止事件冒泡,
e.stopPropagation()
,也可以用@click.stop
代替。一共有六个事件修饰符。还有
.once
表示一次性。还可以连着写!
@click.stop.prevent
,@click.ctrl.y
计算属性
计算属性,在Vue的机制里,会通过getter计算出新的属性,最后成为vm的一个属性值,最终的计算属性只是一个属性值,不是对象!具体用法参见下边的代码。通过自动调用getter和setter来达到目的。
需要注意的是,当第一次加载fullName和所依赖的数据如firstName发生改变的时候,fullName会重新调用。如果依赖的数据没有发生变化,得益于vue的缓存机制,fullName的get只会在最开始调用一次,所以性能由于methods。
当修改fullName的值时,set函数调用。
computed:{ |
计算属性的简写
下面再来说一下计算属性的简写形式。
当你的计算属性不涉及setter的时候才可以简写,简写代码见下方。
你会发现简写之后的形式,就相当于methods里面的一个函数。但是不同的是,computed里面的函数是Vue调用执行的,最后计算完后成为了vm的一个属性。所以插值引用时不能加括号,这点和直接调用methods里的方法是不同的,且methods里的没有缓存机制和计算属性的一些独有的优化特点。
computed:{ |
监视(侦听)属性
监视属性,顾名思义就是当某些属性发生改变的时候,会触发handler。这里说的属性包括上边提到的计算属性。如果写了不存在的属性,那么新旧值都是undefined,不报错。写法如下:
watch:{ |
为了灵活,也可以通过vm的$watch来调用,但是必须在Vue对象实例化之后才能调用
vm.$watch('isHot',{ |
深度监视
我们常常遇到这样的问题:当我们要监视的数据不是一个简单的数据类型时(例如一个对象),那么当我们改变了对象的一个属性,对象是否变了呢?本质来说,对象的地址没有变,那么可以认为对象是没有变化的。于是如果我们想监视对象的某个属性就需要用到把上边提到的
isHot
换成'对象名.属性'
这里的引号时必不可少的,具体参见es语法,此处不多赘述。但是当我们想要监视这个对象的任一属性时,我们直接写该对象时不行的,因为
watch
默认不会深度监视,所以需要我们打开这个配置,如下
watch:{ |
监视属性的简写
简写模式和计算属性类似,都需要只有一个函数配置项,这里对于watch和$watch的简写举例说明
watch:{ |
监视与计算的对比
两者某些功能都可以实现,计算属性相对于监视来说不需要再data里面提前定义好属性,所以更加简洁。但是计算属性完全依赖于return的值,所以对于类似定时器等功能无法正常实现,但是监视就方便了。不过需要注意的时,定时函数为什么不写function呢,这就需要了解一下js高级里面的this了,对于function,谁调用的function,this就是谁。但是箭头函数时没有this的,这时this指的就是外层的this,很显然,外层的this就是vm。所以这里不写fuction。
总结:vm管理的函数需要用function,除非不需要用到this,而如果不是vm管理的函数(例如定时器,ajax回调,promise回调),用箭头函数。总之,目的就是让this指向vm。
wahch:{ |
样式绑定
一个标签如果写多个class属性
class='xxx' class='yyy'
,默认只解析第一个。在vue中,我们可以写class = 'xxx' :class='yyy'
,两者并不冲突,此时,前者时正常的属性,后者时通过v-bind
绑定js表达式,最终由vue一起绑定到class。这里的表达式可以是字符串变量,数组变量和对象,具体格式如下:
//字符串就不写了 |
style绑定
在上边讲过了class的绑定,这里再说一下style的绑定(虽然用的很少),但是还是介绍一下
:style = "{fontSize: 20px}" //这里需要些样式对象,或者对象数组,注意font-size要写成fontSize |
条件渲染
v-show = "js表达式"
v-if
v-else-if
如果上边的v-if满足,那么后面的v-else-if不判断。
v-else
用法我就不用说了吧,猜也能猜到👵不过需要注意的是,通过v-if控制的几条不能被打断。
v-if
与<template>
当我们需要个一些元素添加样式,又不想一个一个添加,又不想增加父元素,可以用如下的方法,效果实现了,且在dom里面没有template元素,template不能和v-show使用。
<template v-if = "isShow"> |
列表渲染
- 可以有两个形参,虽然不加括号也行,但是建议加上
- key值Vue用来对比前后的虚拟dom的,如果变更以后的虚拟dom和旧的一样,那么就不再重新渲染,而是直接复用,节省效率。所以当你的列表需要变化,例如排序,增删,那么key就非常重要,默认key是index,你需要加一个:key = p.id之类的专用key,防止列表出现问题,尤其是包含input输入框的时候,容易出岔子。
- 遍历的对象不一定是数组,也可以是对象,也可以是字符串,具体不多解释,试试就知道了。
<li v-for="(p, index) in persons" :key = "index"> |
数据监测
这是一块复杂的知识,但是如果不搞懂底层的逻辑,可能会在数据监测中遇到很多问题。首先,我们在
data
里面写的数据会被加载到vm的_data
上,同时,这些属性也会在vm的根节点上,也就是说我们可以直接访问vm.property
,然后通过调用get来访问_data
里面的属性,_data
里的属性同样需要getter,共有两层的getter。为什么要这样呢,前者是为了调用方便,不然每次多要写_data
也太不爽了,后者是为了监测数据,你想,当你修改data里的某个数据时,vm如果不知道,那还怎么监测并重新解析数据呢。因此,需要用到_data
里面的getter和setter,当你修改数据时,调用了set
,从而实现检测的效果。
上边大概说明白了监测实质就是vue将你写在data里面的东西加工了。但是当加工以后,我们还想再往里面添加属性怎么办呢,这就需要深入探讨一下了。
大概分为两种情况,一个是往一个对象里添加属性,一个是往数组里添加数据。
前者,很容易想到obj.name = 'jack'
这样的例子,以为我们拿到对象节点就万事大吉,但是不然,这样添加的属性是没有监测效果的,也就是说没有对应的getter和setter,那么怎么办呢,vue提供了解决办法,你可以通过Vue.set(obj, property, value)
来添加属性。
后者,我们可以借鉴对象的方式,因为数组毕竟也是个对象,万物皆对象嘛,我们可以将property换成index即可。Vue.set(arr, index, value)
。但同时,vue也对数组进行了专门的优化,首先数组里面的每个数据是没有对应的getter和setter的,那么当我们修改数组的数据时,vue怎么判断呢?其实,vue专门对数组的几个函数进行了修改,push pop shift unshift splice sort reverse
这几个函数是可以修改原数组的值的,当我们通过这几个函数来修改数组的时候,vue就可以检测到了。切记不要直接通过索引值来修改。
最后说一下细节问题,数组里面如果是对象,那么这个对象的属性是有getter、setter的。
表单收集
我们知道,一想到表单收集,肯定就是
v-model
了,但是需要注意些特殊的坑,毕竟表单有单选,复选,单行,多行等。
<input type = 'text' v-model='account'/>
收集到的是输入的数据<input type = 'radio' v-model='account' value='sex'/>
单选框,收集到的是value,由于没有输入,默认是null,所以需要配置value属性。<input type = 'checkbox' v-model='account'/>
- 如果不配置input,默认手机checked属性,即布尔值
- 如果配置
- 当v-model初始值不是数组,收集的还是checked
- 否则收集的是value组成的数组。
- 修饰符
- lazy:失去焦点再收集
- number:收集类型转成数字
- trim:去除前后空格
自定义指令
简写
其实vue指令本质不就是底层在操作dom嘛,所以你只需要自己写一个指令名,例如
v-hello
,当你在配置项里配置好hello,那么就可以用了。代码如下
new Vue({ |
完整
但是有一些特殊的需求,例如
el.focus()
,有些命令只能在元素插入到页面以后才能执行。这时候我们就要考虑到自定义指令的调用时机了。上一个简写模式,只有在最开始绑定以及随后重新解析模板的时候才会调用,也就是没有inserted。并没有所谓的“元素插入页面以后调用”,那么就来看看完全体吧,上代码
new Vue({ |
细节
- vue默认会转成小写,所以命名不要驼峰命名,而是要用v-user-name这样的命名,具体叫啥,我没记住。
- 如果想写全局firective,就用
Vue.directive('hello', function(){...})
,和全局的过滤器是一样的,但是什么是全局过滤器呢,我听了,但是不想写了。反正就是filters filter
之类的,好像vue3被弃用了,听听算了。 - this是window
生命周期
来了!重点来了。
引入
new Vue({ |
介绍
细节
- 重点关注mounted和beforeDestroy。
- 在后者里修改数据不会再触发更新
一些片段
跟着教程敲的一些片段
|
|
axios
axios回调函数里面的this已经改变,无法在会点函数内部通过this访问data,可以在回调之前拿一个变量保存一下this
axios.get(url).then |
组件化
在常规编写中,为了复用,有了模块的概念,也就是分成多个js。而这里的组件化,是撒子呢。看下去
非单文件组件
虽然开发中不太常用,但这里还是写一些基本的用法
用法
const s = Vue.extend( |
细节
命名
- 一个单词可以首字母大写也可以不大写
- 多个单词可以(kebab-case)也可以大驼峰(CamelCase),但是不在脚手架里,大驼峰是不支持的。
标签可以写双标签
<school></school>
,也可以但标签<school/>
,但是如果不在脚手架,但标签会导致后续组件无法渲染简写
const school = Vue.extend(options) 可以简写为 const school = options
原理就是,如果你在传入的是一般对象,那么vue会自动调用extend
嵌套组件
把一个组件当成html,同时把子组件挂载到父组件上。顺序要注意,子组件要在前面。其实每个组件就是一个VueComponent实例,简称vc实例,vc和vm类似,this指向vc,vc是在vm的$children属性里。两个构造函数Vue和VueComponent类似,但是不一样,例如vc里面不能传el,再例如,data在vc里必须是函数,vm里可以是对象。而且正是由于vc是可以复用的,所以data不能写对象。
const b = Vue.extend( |
关于原型
在Vue中做了一件事,那就是把VueComponent的原型的原型指向了Vue的原型,而不是Object。具体关于原型的理解,我是这么想的,一个构造函数,本身就是一个对象,他有一个属性是
prototype
,称为显示原型属性,这个属性里存放的东西可以理解为一个类的静态属性。在这个属性里的东西,所有由该构造函数new的对象通过.__proto__
(隐式原型属性)共享。而Vue将VueComponent构造函数的prototype
的__proto__
的指向从Object修改成了Vue的原型对象,以至于组件可以访问Vue中的显示属性。如果还是不太理解,可以去补充一下js高级。js的面向对象和c++和java还是有还很大区别的。
脚手架
终于来了,后缀是.vue,简单说一下组件化的运行逻辑,首先入口是一个html和一个main.js,这个main.js不需要你手动引入,只需要在main.js引入Vue和app组件,然后里面配置好Vue实例,配置好需要的组件(其实只有一个app组件),挂载到对应的html文件上(render)即可。下面是一个组件(.vue)的模板,分为三块,template script style。另外public里面的html文件用到了jsp语法,自己学吧。html里面的
<noscript>
标签,表示不支持js的时候才解析里面的内容。
<template> |
render
由于运行时vue缺少模板渲染,所以用render来替代
render: h => h(App); //vue将会向h传递一个creatElement的函数,来创建元素,且不需要配置component。另外,h的形参传递组件例如App,则如上。如果传html代码,则h('h1','Heloo')。 |
修改默认配置
想查看Vue-cli的默认配置,只需要控制台
vue inspect > output.js
,就可以导出所有的配置项目,生成一个js。该文件修改是无效的。如何修改呢?
对于main.js src public index.html favicon.ico就别修改了,能够修改的可以去这里参考一下。具体过程就是在根目录(和package.json同级)创建一个vue.config.js
,参照官网的配置项修改。该文件暴露采用common.js,最后和webpack的配置整合。
ref
为了获取元素和组件,vue自定义的一个属性ref,如下当我们给一个元素或者组件加上ref属性以后,就可以通过
this.$refs.title
拿到这个元素或者组件。和id类似,但是对于组件,通过id拿到的组件是渲染之后的组件而不是组件本体。
<h1 ref = 'title'> |
prop
功能:让组件接收外部传过来的数据(组件传参)
传递数据:
<Demo name="xxx" sex="hhh"/>
,这里如果是:name="xxx"
那么xxx会按照js表达式解析接收数据:
- 第一种方式(只接收):
props:['name']
- 第二种方式(限制类型):
props:{name:String}
- 第三种方式(限制类型、限制必要性、指定默认值):
props:{
name:{
type:String, //类型
required:true, //必要性
default:'老王' //默认值
}
}- 第一种方式(只接收):
props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。