vue.js是什么
是一套构建用户界面的渐进式框架
vue应用组成
一个 Vue 应用由一个通过new Vue创建的根 Vue 实例,以及可选的嵌套的、可复用的组件树组成。
vue数据的响应
当一个 Vue 实例被创建时,它向 Vue 的响应式系统中加入了其data对象中能找到的所有的属性。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
实例生命周期
beforeCreat ----> 创建vue实例前
created ---> 创建vue实例完成后
beforeMount -----> DOM渲染前
mounted -----> DOM渲染后
beforeUpdate -----> 数据更新前
updated ------> 数据更新后
beforeDestroy -----> vue实例销毁前
destroyed ------> vue实例销毁后
模板语法
vue模板为什么可以被浏览器解析?
Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。
底层是如何实现的?
Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,在应用状态改变时,Vue 能够智能地计算出重新渲染组件的最小代价并应用到 DOM 操作上。
计算属性和观察者
什么时候使用计算属性?
1.对于需要任何复杂逻辑显示的变量,就应该使用计算属性(computed);
2.当有一些数据需要随着其它数据变动而变动时,使用计算属性比watch监听更方便;
计算属性基本写法
实例:
var vm =newVue({
el:'#example',
data: {
message:'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage:function(){
// `this` 指向 vm 实例
returnthis.message.split('').reverse().join('')
}
}
})
计算属性与方法的区别
相同点:使用结果都是一样的;
不同点:计算属性只有在它的相关依赖发生改变时才会重新求值,否则会返回已缓存的值;
方法每当触发重新渲染时,调用方法将总会再次执行函数。
计算属性的 setter
计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter;
注意:当写了setter后,运行computed中的方法时,setter 会被调用;
侦听器
当需要在数据变化时执行异步或开销较大的操作时,使用watch是最合适的;
watch中可以处理一些异步的操作,计算属性不可以;
Class 与 Style 绑定
*通过v-bind来绑定class和style;
class绑定的语法:
1.对象语法:v-bind:class="{ active: isActive, 'text-danger': hasError }"
2.数组语法:v-bind:class="[activeClass, errorClass]"
3.以上两个语法都可以使用在组件中,动态绑定的class名不会覆盖已存在的名;
style绑定的语法:
1.对象语法:v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"
2.数组语法:v-bind:style="[baseStyles, overridingStyles]"
style自动添加前缀
当v-bind:style使用需要添加浏览器引擎前缀的 CSS 属性时,如transform,Vue.js 会自动侦测并添加相应的前缀。
多重值
2.3.0起,新增了style可以写多个值,如下:
:style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }
在渲染页面时,只会显示数组中,浏览器支持的值,前两种都不支持的情况下,会显示flex。
条件渲染
v-if、v-else、v-else-if(2.1.0新增)
基本使用方法如下:
<h1 v-if="ok">Yes</h1>
<h1 v-else-if="yesNo">noYes</h1>
<h1 v-else="no">No</h1>
以上案例只可以判断有条件指令的元素身上;
条件渲染分组(template元素)
判断多个元素需要使用<template>元素,将需要判断的元素包起来,方法如下:
<template v-if="ok">
<h1>h1</h1>
<p>p</p>
</template>
<template v-else="no">
<h2>h2</h2>
<span>span</span>
</template>
用管理可重用的元素key
案例说明:如果你允许用户在不同的登录方式之间切换;
不写key属性如下:
以上这样的切换,input值中的值会相互影响;
通过key属性处理上面问题:
给不同的key值,就可以做到相互不影响,从而切换时,input中的值会单独出来;
v-show条件渲染
v-show使用方法与v-if相同;
v-show与v-if的区别:
1.v-show的元素始终会被渲染在DOM中,v-show,只是简单的使用display属性,并且,v-show不支持v-else和<template>元素;
2. v-if,只有在符合条件时,才会渲染元素,否则不渲染;
3.v-if,是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
如何选择使用v-if和v-show
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
列表渲染
v-for语法:v-for="items in list" 或者:v-for="items of list"
可以遍历数组,也可以遍历对象
对象遍历:
v-for的第二个参数:key ---- v-for="(value, key) in object"
key表示数据中的键名;
v-for中key参数说明
尽量在v-for中加入key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。因为它是 Vue 识别节点的一个通用机制。
数组更新检测
变异方法:会改变原有数组;如下:
push()、pop()、shift()、unshift()、splice()、sort()、reverse()
非变异方法:不会改变原有数组,会返回一个新数组;如下:
filter()、concat()、slice()
对象更改检测注意事项
还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:
可以使用:Vue.set(object, key, value) 方法来添加或删除;也可以使用vue全局的Vue.$set
参数说明:
1.object:要修改的对象;
2.key:要修改的key名;
3.value:要修改的value值;
说明:set方法不可以同时添加多个key,value;
同时添加多个key,value的方法,使用Object.assign();
//this.userProfile 是要添加的对象
this.userProfile =Object.assign({},this.userProfile, {
age:27,
favoriteColor:'Vue Green'
})
显示过滤/排序结果
当需要对数组进行过滤或排序,但不需要改变原有数组,这时需要使用计算属性(computed);
实例如下:
data: {
numbers: [1,2,3,4,5]
},
computed: {
evenNumbers:function(){
returnthis.numbers.filter(function(number){
returnnumber %2===0
})
}
}
说明:当数组是嵌套在v-for中,计算属性就不适合了,需要使用method方法。
一段取值范围的 v-for
v-for比v-if的优先级高,也就是,先循环后判断。
如下(v-for与v-if是在同一个元素上):
如果需要先判断后循环,这种情况可以把判断指令写到循环指令外或者是template元素上;
组件中的v-for
*vue 2.2.0以上在组件中使用v-for必须要加key;
案例:
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>
for中的item,传入组件中,使用porps原因是为了for与组件之前的解藕,并能明确数据的来源,从而重复使用;
事件处理
监听事件
使用v-on指令监听事件
<div v-on:click="eventFn">点击按钮</div>
v-on冒号后面跟着的是事件,如click,mouseout等;
事件处理方法
事件的处理方法,可以写到methods中,将方法名写入v-on="方法名",调用事件;
内联处理器中的方法
<div v-on:click="eventFn('vue')">点击</div>
可以将事件写在内联中进行调用,并传参;
当遇到需要使用原生DOM事件,可以通过$event,传入到事件中;
Vue.js 中提供的修饰符
事件修饰符
.stop:阻止单击事件继续传播
.prevent:提交事件不再重载页面
.capture:添加事件监听器时使用事件捕获模式
.self:即事件不是从内部元素触发的
.once:点击事件将只会触发一次(2.1.4 新增)
按键修饰符
.enter、.tab、.delete(捕获“删除”和“退格”键)、.esc、.space、.up、.down、.left、.right
自动匹配按键修饰符
<input @keyup.page-down="onPageDown"/>
在上面的例子中,处理函数仅在$event.key === 'PageDown'时被调用。
系统修饰键
.ctrl、.alt、.shift、.meta
以上按下相应按键时才触发鼠标或键盘事件的监听器;
为什么在 HTML 中监听事件?
1.易读,一眼就可以看到对应的方法;
2.与 DOM 完全解耦,更易于测试;
3.当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除;不需要自己删除;
表单输入绑定
使用v-model指令绑定表单控件标签,可以实现监听效果,输入框的标签可以实现双向数据绑定;
摘抄API
表单修饰符
.lazy:转变input输入框同步数据的事件;
<input v-model.lazy="msg" /> //这里表示,添加了lazy,change事件中才会同步数据;
.number:转变input输入框值的类型,改变为number类型(如果原值的转换结果为 NaN 则返回原值)
.trim:去掉input值的首尾空格;
组件
什么是组件
组件是vue的功能之一,可以看成是自定义元素。可以扩展HTML元素,封装可重用的代码。组件也可以使用is,扩展原生HTML元素;
注册组件
1.全局注册
使用Vue.component('组件标签名',{组件的配置代码})方法注册;
组件标签名,官网推荐使用烤串命名方法为最佳;
// 注册
Vue.component('my-component', {
template:'<div>A custom component!</div>'
})
// 创建根实例
newVue({
el:'#example'
})
2.局部注册
可以在vue实例下,components 中注册组件;
varChild = {
template:'<div>A custom component!</div>'
}
newVue({
// ...将只在父组件模板中可用
components: {
// 将只在父组件模板中可用
'my-component': Child
}
})
DOM 模板解析注意事项
组件标签,会受到 HTML 本身的一些限制,因为 Vue 只有在浏览器解析、规范化模板之后才能获取其内容;
例如:ul,select等,这些内部包含的元素有限制,组件标签会被视为无效;
解决方法
1.使用is来解决这个问题,如下:
<table>
<tr is="my-component"></tr>
</table>
运行后:
<table><my-component></my-component></table>
2.也可以使用字符串模版来处理,因为字符串模版没有限制
<script type="text/x-template">
JavaScript 内联模板字符串
data 必须是函数
Vue.component('simple-counter', {
template:'<div></div>',
// 技术上 data 的确是一个函数了,因此 Vue 不会警告,
// 但是我们却给每个组件实例返回了同一个对象的引用
data:function(){
return { //在data中的函数,必须返回return一个对象,这样就就不会相互影响。否则数据会同时影响到;
list:[1,2,3]
}
}
})
组件组合
组件的组合,批组件的嵌套配合使用,常见父子组件之间的配合,会遇到相互通信传递的问题;
父向子传递使用props,向下传递;
子向父传递使用自定义事件,向上传递;
props
使用props传递数据
props是专门绑定组件中自定义属性的,也可以通过props传递数据;
声明方法
Vue.component('child', {
// 声明 props
props: ['message']
})
<child message="data"></child>
camelCase(驼峰命名) vs. kebab-case(俗称烤串命名)
在props中,命名要使用camelCase命名,在html中就可以使用kebab-case命名;
动态prop
prop的值可以是动态的数据,这时就可以使用v-bind来动态绑定数据;
如下:
Vue.component('child', {
// 声明 props
props: ['message']
})
<child :message="data"></child>
prop可以传递一个对象;
如下:
todo: {
text:'Learn Vue',
isComplete:false
}
<todo-item v-bind="todo"></todo-item>
**prop声明的属性不可以直接输入字面量的值,
如:<child message="1"></child>
这里的1是字符串1,不是一个数值,如果需要是一个数值,则要通过v-bind动态绑定,这样才是javascript的表达式;
单向数据流
prop是单向绑定的,父组件通过prop向子组件传值后,子组件是不可以直接修改父传过来的值;这是为了防止子组件随意修改父的数据,导致数据不准确;
实际运用中,会遇到子组件需要修改父组件的数据,解决办法如下:
***如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。
Prop 验证
例:props:{
自定义属性名:{
type:Number,//设置类型 ---->>type:[String,Number]//类型也可以是多种
default:10,//设置默认值[可填]
required:true,//设置是否必填[可填]
}
}
自定义验证:
props:{
test(自定义属性名):{
validator:function(value){
retrun value>10;
//value,是test绑定对应的数据的值;
//return 验证规则,直接写retrun true验证直接通过;如果写规则逻辑就按逻辑走;
}
}
}
非 prop 特性
指可以直接传入组件,而不需要定义相应的 prop。
如需要有个数据直接传入组件,比如使用某个插件的某个属性,可以直接可以直接将这个属性写入到组件元素上,赋值为'true'
替换/合并现有的特性
合并:遇到class、style时,会合并值,不会替换;
替换:遇到只能有一个值的数据,会被替换;
自定义事件
当子组件向父组件传递数据,就可以通过自定义事件来传;
使用绑定自定义事件v-on
事件接口:
使用 $on(eventName) 监听事件
使用 $emit(eventName) 触发事件
父组件用$on监听自定义事件,$emit触发父组件所关心的自定义事件。
子组件向父组件传递方法步骤:
1>创建一个变量val在父组件中,用于接收子组件的值;val='';
2>将val绑定到父组件要显示的input中
<input :value="val"/>
3>子组件的自定义标签中,添加自定义事件;
<list-cus @receive='selectValue'></ist-cus>
4>子组件中的元素(li)加点击事件,并通过vue自带监听事件,监听并回调要传的值;
methods:{
changeValue(item){
this.$emit('receive',item);
}
}
5>在父组件中的methods事件中写selectValue方法,方法中会传入value的值
methods:{
selectValue(value){
this.val=value;
//将最终得到的选项值赋给val显示到页面中
}
}
备注:$emit(str1,[str2])
str1:自定义事件名
str2:要传入的参数,可以是多个
触发当前实例上的事件,附加参数都会传给监听器回调;
这里的监听器可以理解为,子组件标签身上的自定义事件;
给组件绑定原生事件
使用v-on事件名 .native,这样绑定的就是原生事件了;
<my-component v-on:click.native="doTheThing"></my-component>
.sync 修饰符
这个修饰符在2.3.0时,重新被启用;
当一个子组件改变了一个带 .sync 的 prop 的值时,这个变化也会同步到父组件中所绑定的值。这就是.sync的作用;
使用自定义事件的表单输入组件
**自定义事件可以用来创建自定义的表单输入组件,使用v-model来进行数据双向绑定**
vue双向数据绑定的实现原理
vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的,vue数据劫持是通过Object.defineProperty()来实现的;
Object.defineProperty()是什么:可以控制一个对象属性的一些特有操作,比如读写权、是否可以枚举;
其中使用get和set两个方法,用来控制视图-->数据,数据<--视图之间的修改更新,实现双向数据绑定;
get是在读取属性值(数据)时,触发的函数;set是在设置属性值(数据)时,触发的函数;
双向数据绑定实现思路
实现mvvm主要包含两个方面,数据变化更新视图,视图变化更新数据;
视图变化更新数据:可以通过监听事件;
数据变化更新视图:这个可以通过Object.defineProperty()对属性设置一个set函数,当数据改变了就会来触发这个函数