VueJs
Vue.js:渐进式的、MVVM模式的JavaScript框架,所谓渐进式,其实就是Vue核心库+插件;
1. 编码简洁,体积小,运行效率高,适合移动端/PC端开发;
2. Vue本身只关注UI,可以轻松引入Vue插件或其他第三方库;
3. 借鉴Angular.js的模板和数据绑定技术,借鉴React的组件化和虚拟DOM技术;
4. 不兼容<=IE8,因为IE8无法模拟的ES5特性,但它支持所有兼容ES5的浏览器。
1. Vue扩展插件:
1. vue-cli(vue脚手架)、vue-resource(即axios,ajax请求)、vue-router(路由)
2. vuex(状态管理)、vue-lazyload(图片懒加载)、vue-scroller(页面滑动相关)
3. 基于vue的UI组件库:mint-ui(移动端)、element-ui(PC端)
2. MVVM:
1. Model:模型,数据对象
2. View:视图,模板页面,动态的HTML页面,包含一些JS语法代码,如{{xx}}、v-xx
3. ViewModel:视图模型,对应Vue实例,new Vue({})
4. ViewModel通过Vue[DOM监听、数据绑定]关联Mode与View
3. Vue是声明式开发方式,遵循对应的语法即可,而命令式开发需要关心整个实现的流程。
Vue语法
1. 创建实例:
const vm = new Vue({
el: '#app', --> 管理的一块区域,通过CSS选择器查找管理的区域
data: { --> 所管理区域内需要的数据Model
msg: '<a href="https://www.baidu.com/">go</a>',
name: 'A',
imgUrl: 'https://www.abc.cn/a.jpg',
},
methods: { --> 管理区域内的方法(ES6)
test1(){ alert("hehe!") },
test2(a){ alert(a) }
},
computed: { --> 属性计算,this指向data
full1() { return "Hello " + this.msg; }
},
watch: { --> 监视属性的变化,this指向data
name: function(newVal, oldVal){ --> name发生改变的回调函数
this.msg = "Hello " + newVal; --> 动态修改属性msg
}
}
})
2. 双大括号表达式:<div>{{变量/JS表达式}}</div>
<div id="app">
<p>{{msg}}</p> ===> 不管msg是不是一个标签,都会当成一个普通的字符串
<p>{{msg.toUpperCase()}}</p> ===> 把msg转为大写字母
</div>
3. v-xxx:自定义标签
1. <p v-text="msg"></p>:更新标签内的字符串文本textContent;
2. <p v-html="msg"></p>:如果msg是一个标签,则以标签显示,类似于innerHTML;
3. <img v-bind:src="imgUrl" />:强制数据绑定,把imgUrl作为一个表达式解析;
等效于:<img :src="imgUrl" />
4. <button v-on:click="test1">:无参的绑定事件监听,等效于 @click="test"
5. <button v-on:click="test2('test')">:有参的绑定事件;也可以直接使用data中
的属性:<button @click="test2(msg)">
6. v-model:双向绑定,<input type="text" v-model="msg"/>
msg变化,输入框中的内容也会变化,同理,输入框中的内容发生变化,msg也随之变化;
4. 计算属性:computed
<input type="text" v-model="full1"/>,输入框中的值就是full1的返回值,
任何地方的msg变化,full1()会重新计算,返回值变化,进而输入框中的值随之变化。
5. 监视属性:watch,监视的属性name发生变化,回调对应的函数;
1. 深度监视:如果监听的属性是一个数组,普通监听无法监听到数组内的变化
watch: {
属性名: { --> 启用深度监听,数组内的任何变化,都会被监听到
deep: true,
handler: function(newVal, oldVal) { ... }
}
}
2. 监视属性的方法不能使用箭头函数,因为箭头函数仍然沿用上一级作用域的this,已经不再
指向Vue组件对象.
6. Vue实例的方法都以"$"开头:
vm.$watch('监视的属性名', function(newVal, oldVal){ -->动态添加属性监听
this.msg = "Hello " + newVal;
});
7. 计算属性-高级:getter/setter、缓存
1. 通过getter/setter实现对属性数据的显示和监视,计算属性的方法只会调用一次,
多次读取也只执行一次getter,是为了提高性能,计算之后做了缓存处理;
2. 双向绑定v-model:
computed: { --> 属性计算,this指向data
full2: {
get(){ --> 根据相关的属性,计算并返回当前属性值
return this.msg
},
set(value){ --> 当属性值发生变化时,更新相关的属性
this.msg=value
}
}
}
<input type="text" v-model="msg"/>
<input type="text" v-model="full2"/> --> full2的getter/setter是根据msg
计算的:msg的变化会引起getter的回调,手动输入内容又会回调setter,进而改变msg
1. class与style的绑定
.con1{ color: red; } .con2{ color: blue; } .con3{ font-size: 20px; }
data: {
cl: 'con1',
isOne: true,
isTwo: false,
activeColor: 'red',
activeSize: 30
},
methods: {
update1(){
this.cl = 'con2' --> 动态改变cl的值,即改变样式
},
update2(){
this.isOne = !this.isOne --> 改变true/false,也就改变了应用
this.isTwo = !this.isTwo --> 的样式
}
}
1. class绑定::class="'样式名'",:class='xxx'
<p :class="'con1'">PPP</p> ==> 等效于:class="con1"
<p :class="cl">PPP</p> ==> 绑定cl变量,动态控制样式
<p :class="cl" class="con3">PPP</p> ==> :class和原生class配合使用
<p :class="{con1: isOne, con2: isTwo}">PPP</p> ==>对象的方式
<p :class="[con1, con3]">PPP</p> ==> 数组的方式
2. style绑定::style="{ }"
<p :class="{color: activeColor, fontSize: activeSize+'px'}">PPP</p>
==> 属性名就是样式名,带"-"的属性名,后面的首字母大写,属性值是data的属性;
2. 条件渲染指令:v-if、v-else、v-show
var vm = new Vue({
el: '#app',
data: { isOk: true, }
});
<p v-if="isOk">vif</p> <p v-else>velse</p>
<p v-show="isOk">vshow1</p> <p v-show="!isOk">vshow2</p>
<button @click="isOk=!isOk">Change</button>
1. v-if、v-else是真正的条件渲染,作用的标签会被销毁与创建,且v-if是惰性的,
如果初始条件为false,则什么也不错;只有在条件第一次为true时,才会在DOM中局部渲染;
2. v-show只是设置内联样式display:none; 实现隐藏,标签并没有被销毁;
3. 如果切换频繁,v-show的效率会更高一些;而如果不希望标签存在于DOM中,则使用v-if。
3. 列表渲染:v-for
1. 遍历数组
data: {
persons: [
{name: 'Tom', age: 18}, {name: 'Jack', age: 16},
{name: 'Bob', age: 19}, {name: 'Rose', age: 17},
],
searchVal: '', --> 用于保存搜索框中的内容
orderBy: 0 --> 排序的标识
},
methods: {
deleteP(index){ --> 删除当前索引的元素
this.persons.splice(index, 1);
},
changeP(index) { --> 更新失败
this.persons[index] = {name: 'Any', age: 11};
}
}
<ul>
<li v-for="(p, index) in persons" :key="index"> ==>遍历persons
{{index}}---{{p.name}}---{{p.age}}
<button @click="deleteP(index)">Delete</button>
<button @click="changeP(index)">Change</button>
</li> ==>:key表示<li>的唯一标识,让Vue减少DOM更新,提高性能
</ul>
2. 由于JavaScript的限制,Vue不能检测以下变动的数组:
a. 利用索引直接修改元素,如:vm.items[i] = val,delete vm.items[i];
b. 修改数组的长度,如:vm.items.length = len; --> splice(len)可以解决
所以changeP()执行后,虽然persons内部元素已经改变了,但界面没有任何变化;
3. deleteP()能删除成功,是因为Vue重写了数组的部分方法,这些变异方法先执行了
数组的原生方法,然后去更新UI,如push()、splice()、unshift()...;
4. 而对于filter()、concat()、slice(),不会改变原数组,而是返回一个新数组;
this.persons = this.persons.filter(function); --> 新数组替换旧数组
5. 但如果更新的是数组中的对象,则可以被监听到,this.persons[index].age=20
6. 遍历对象:v-for
<li v-for="(value, key) in persons[0]" :key="key">
{{value}}---{{key}}
</li> ==> key表示对象中的属性名,value表示属性值
7. 搜索与排序:搜索框中的内容变化,被遍历的数组随之改变
methods:
resetOrder(order){ this.orderBy = order; }
computed:
searchPerson(){
let that=this; --> 保存this的指向
let filterPerson = this.persons.filter(function(p){
return p.name.indexOf(that.searchVal) !== -1;
}); ---> 筛选
if(this.orderBy !== 0) { --> 排序
filterPerson.sort(function(p1, p2){
if(that.orderBy===1) { --> 升序排列
return p1.age - p2.age
} else { --> 降序排列
return p2.age - p1.age
}
});
}
return filterPerson;
}
--------------------------------------------------------------
<input type="text" v-model="searchVal" /> ==> 输入框绑定searchVal
<ul>
<li v-for="(p, index) in searchPerson" :key="index">
{{index}}---{{p.name}}---{{p.age}}
</li> ==> 被遍历的数组是动态计算的
</ul>
<button @click="resetOrder(1)">升序排列</button> --> 重置orderBy的值,
<button @click="resetOrder(2)">降序排列</button> --> 将重新计算遍历的数组
<button @click="resetOrder(0)">原本顺序</button>
8. 还是由于JS的限制,Vue不能检测对象属性的添加或删除。
4. 事件处理
1. 事件绑定:v-on在绑定事件时,对于无参的方法,会隐式传递默认参数event;
对于有参的方法,希望获取参数event,则需要手动传递"$event"
methods:
test1(event){ console.log(event.target.innerHTML) },
test2(num, event){ console.log(event.target.innerHTML) }
---------------------------------------------
<button @click="test1">TEST1</button>
<button @click="test2(45, $event)">TEST2</button>
2. 阻止事件冒泡
<div @click="test3">
<div @click.stop="test4"> --> 阻止事件冒泡
</div>
3. 阻止默认行为
<a href="http://www.baidu.com/" @click.prevent="test5">
4. 按键事件,如按键松开:@keyup
<input type="text" @keyup="test6"> --> 监听任何按键的松开事件
<input type="text" @keyup.13="test6"> --> 监听keyCode为13的按键松开事件
<input type="text" @keyup.enter="test6"> --> 少数按键可以直接使用名字
5. 表单:<form action="#" @submit="handleSubmit">
1. 输入框直接使用"v-model"绑定即可;
2. 单选框:v-model使用同一个data中的属性,其属性值是被选中的value属性值;
3. 复选框:v-model也是使用同一个data中的属性,但该属性是一个数组,元素是复选框
的value属性值,数组中的初始值,就是复选框的默认值;
4. 如果只有一个复选框,只是判断是否被选中,则用v-model绑定一个boolean型的属性,
或绑定一个带有getter/setter的计算方法:<input type="checkbox" v-model="b"/>
b为true,则被选中,同理,如果手动取消选中,则b也会变为false;
5. <select>下拉框:
data: {
city: [{id:1, name:'BJ'}, {id:2, name:'SH'}, {id:3, name:'XY'}],
cityId: 0
},
<select v-model="cityId"> ==> v-model最终接收选择的值
<option value="">未选择</option>
<option :value="c.id" v-for="(c, index) in city" :key="index">
{{c.name}}</option>
</select>
1. <option>的原生属性value会把属性值当作一个普通的文本,而不是一个表达式,
所以用vue的":value",其实是"v-bind:value",v-bind可以省略;
2. <option>上使用":key"也是为了唯一的标识。
6. 生命周期:又叫勾子函数
1. 初始化显示:beforeCreate()、created()、beforeMount()、mounted()
2. 更新显示:this.xxx = value --> beforeUpdate()、updated()
3. 销毁Vue实例:vm.$destroy() --> beforeDestroy()、desroyed()
1. mounted():挂载,初始化显示之后立即调用,页面已经渲染完成;
2. beforeDestroy():调用vm.$destroy(),销毁Vue实例之前回调;
data: {
show: true
},
mounted() { --> 初始化Vue实例时调用
let that = this;
this.intervalId = setInterval(function(){
that.show = !that.show;
}, 1000); --> 初始化时开启一个定时器
},
beforeDestroy() { -->销毁时清除定时器,否则定时器一直存在,导致内存泄露
clearInterval(this.intervalId);
},
7. 过滤器
1. 定义过滤器
Vue.filter('filterName', function(value, arg, ...){
//数据处理 ...
return newValue
});
2. 使用过滤器:
<div>{{myData | filterName}}</div> ==> 无参数
<div>{{myData | filterName(arg)}}</div> ==> 有参数
8. Vue指令
1. 常用内置指令:v-text、v-html、v-model(双向数据绑定)、v-if、v-else、v-show、
2. v-for、v-on(简写为'@')、v-bind(强制绑定解析表达式,可以省略)
3. ref:指定唯一标识,vue对象通过"$refs"属性访问这个元素对象;
<p ref="content">PPP</p>
methods:
hint(){
const p = this.$refs.content --> 根据ref获取指定标签
p.textContent --> 获取标签内容
}
4. v-cloak:防止闪现,与CSS配合,[v-cloak]{display:none}
<p>{{msg}}</p> --> 如果数据加载过慢,页面可能显示的是"{{msg}}"
1. 指令属性在解析之前是存在的,但是解析之后就会从标签移除;
<p v-cloak>{{msg}}</p>
<style>
[v-cloak] { --> 属性选择器
display: none; --> 隐藏标签
}
</style>
2. 页面解析之前,<p>上的属性选择器v-cloak是存在的,所以<p>被隐藏了;在页面解析
之后,{{msg}}也已经被替换成真实数据了,指令属性会被移除,所以<p>会显示出来。
8. 自定义指令
1. 注册全局指令
Vue.directive('my-directive', function(el, binding){
el.innerHTML = binding.value.toupperCase();
}) --> el:标签元素对象,binding:包含指令相关信息数据的对象
2. 注册局部指令:只在当前Vue实例的el范围内有效
directives: {
'my-directive': { ---> 简写为:'my-directive'(el, binding){ ... }
bind(el, binding) {
el.innerHTML = binding.value.toupperCase()
}
}
}
3. 使用指令:v-自定义指令名,<p v-my-directive="msg"></p>
9. Vue插件:按照Vue文档开发的一个js文件
1. 创建MyPlugin.js:
(function(){
const MyPlugin = {}; --> 需要向外暴露的插件对象
//--> 插件对象必须有一个install()
MyPlugin.install() = function(Vue, options) { ... }
window.MyPlugin = MyPlugin; --> 挂在到window对象上,向外暴露
})()
2. 声明使用插件:Vue.use(MyPlugin) --->即执行MyPlugin.install()