前言
从今天开始学习课程《Vue2.5开发去哪儿网App 从零基础入门到实战项目》.
正文
设计模式
MVP 设计模式
- M:Model层,数据服务层,负责数据的增删改查。
- V:View层,视图界面层,负责UI的渲染、子视图的组织、UI事件、用户交互等。
- P:Presenter层在View和Model之间起到桥梁的作用,又封装了业务的复杂度,使UI和业务都可以独立的进行变化。
MVP 设计模式制作 TODO 页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<body>
<div>
<!-- V层: 输入框 + 提交按钮 + 展示的无序数列 -->
<input id="input" type="text">
<button id="btn">提交</button>
<ul id="ul"></ul>
</div>
<script>
// P层
// 面向对象思想 : 将整个页面当成对象
function Page(){ }
$.extend(Page.prototype,{
bindEvents : function () {
$('#btn').on('click',$.proxy(this.handleBtnClick,this))
// 将btn的click事件绑定到handleBtnClick方法上.
},
handleBtnClick : function () {
var input = $('#input');
var inputValue = input.val();
var ulElem = $('#ul');
ulElem.append('<li>'+inputValue+'</li>');
input.val('');
}
})
// 实例化页面类
var page = new Page();
// 执行
page.bindEvents();
</script>
</body>
可以看出,如果使用 MVP 设计模式,有大量的代码是在操作DOM的,这必将造成时间上的浪费.
MVVM 设计模式
使用 MVVM 设计模式, 我们可以只关注V端与M端.
中间数据与显示层的连接,可以交给Vue去做,可以省下大量人力物力.
Vue 双向绑定的原理
- ES5中 Object.defineProperty 方法
- 虚拟DOM
组件化思想
全局组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<body>
<div id="app">
<ul>
<todo-item :conten="item"
v-for="(item, index) in listA">
{{item}}
</todo-item>
</ul>
</div>
<script>
// 全局组件
Vue.component('TodoItem',{
props: ['conten'],
template: "<li>{{conten}}</li>"
});
var app = new Vue({
el: '#app',
data() {
return {
newadd: '',
listA: ['a','b','c']
}
}
});
</script>
</body>
局部组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<body>
<div id="app">
<ul>
<show-list :conten="item"
v-for="(item, index) in listA">
{{item}}
</show-list>
</ul>
</div>
<script>
var TodoItem = {
props: ['conten'],
template: "<li>{{conten}}</li>"
}
var app = new Vue({
el: '#app',
// 在这里为组件在全局中注册
components: {
// 给定一个名称,在HTML中使用.
ShowList: TodoItem
},
data() {
return {
newadd: '',
listA: ['a','b','c']
}
});
</script>
</body>
父子组件间相互传值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<body>
<div id="app">
<ul>
<!-- 监听delete事件,如果触发则执行 handleItemDelete 方法,进入new Vue() 中, 其实这里可以直接在handleItemDelete传入参数,不需要再通过子组件一遍-->
<show-list :conten="item" :index="index"
@delete="handleItemDelete(index)"
v-for="(item, index) in listA">
{{item}}
</show-list>
</ul>
</div>
<script>
var TodoItem = {
props: ['conten','index'],//为li标签绑定click事件
template: '<li @click="handleItemClick()">{{conten}}</li>',
methods: {
handleItemClick () {
//当触发click事件后,会向父组件触发delete事件,并且传入参数
this.$emit('delete',this.index);
}
}
}
var app = new Vue({
el: '#app',
components: {
ShowList: TodoItem
},
data() {
return {
newadd: '',
listA: ['a','b','c']
}
},
methods: {
handleItemDelete (index) {
// show-list标签触发delete事件进入这里
this.listA.splice(index,1);
}
}
});
</script>
</body>
生命周期
模板语法
v-text
与 v-html
的区别?
先看一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<div id="app">
<p>1.nameA</p>
<div v-text="nameA"></div>
<div v-html="nameA"></div>
<p>2.字符串拼接</p>
<div>{{nameA + 'Lee'}}</div>
<div v-text="nameA + 'Lee'"></div>
<div v-html="nameA + 'Lee'"></div>
<div v-html="nameB + 'Lee'"></div>
<p>3.nameB</p>
<div v-text="nameB"></div>
<div v-html="nameB"></div>
</div>
<script>
var vm = new Vue({
el: '#app',
data() {
return {
nameA: 'dell',
nameB: '<li>dell</li>'
}
}
})
</script>
- v-html 可以输出的是HTML元素, v-text 是什么输出什么
- 都可以拼接字符串
计算属性与侦听器
计算属性是内置缓存的
当我们使用Chrome的调试模式,将Vue对象中的元素进行重新赋值.
只有计算属性中使用到的变量发生变化时,计算属性才会重新执行,不然元素不会发生变化.
同样的computed也可以同时计算多个变量,而且对Vue对象外的变量还是没法计算,只有当对象内变量发生变化,页面才会连同一起更新 —— 《Vue.js学习笔记(一) · 侦听器与计算属性》
computed
相比watch
代码实现更简洁.
计算属性的setter
与getter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- 页面打印fullName -->
<script>
var vm = new Vue({
el: '#app',
data() {
return {
firstName: 'Zhang',
lastName: 'Yi'
}
},
computed: {
fullName: {
get () {
return this.firstName + ' ' + this.lastName ;
},
set (value) {
var arr = value.split(' ');
this.firstName = arr[0];
this.lastName = arr[1];
}
}
}
})
</script>
Vue内置的函数,当fullName
发生变化时,调用set
方法,当外部引用fullName
时,调用get
方法.
条件渲染、列表渲染
v-if与v-else中Vue会尝试复用已经显示的元素
原因:虚拟DOM中的即时算法.
如果想解决这个问题,给元素加上key
值,这样就不会复用了.
列表渲染中的key值
在每个循环项下添加一个唯一的key
值,用以提高性能.
这个值如果列表中有附带的id属性则用表中属性,如果没有则用index
.
响应式对数组进行修改
1.使用以下的方法,如果只用vm.list[0]= 2
数组值会发生变化,但是页面不会刷新.
- push()
- pop()
- shift() — 删除第一项
- unshift() — 在第一项添加
- splice() — 截取
- sort() — 排序
- reverse() — 取反
2.或直接改变list数组,如vm.list={1,2,3,4}
.
3.使用Vue.set(数组名,索引值,值)
或实例化Vue对象名.$set(数组名,索引值,值)
响应式对对象进行修改
1.直接重新定义对象
2.使用Vue.set(对象名,属性名,值)
或实例化Vue对象名.$set(对象名,属性名,值)
拾遗
JQuery.extend()用法
- 合并多个对象
1
2
3
4
5
6
7
8
//用法: jQuery.extend(obj1,obj2,obj3,..)
var Css1={size: "10px",style: "oblique"}
var Css2={size: "12px",style: "oblique",weight: "bolder"}
$.jQuery.extend(Css1,Css2)
//结果:Css1的size属性被覆盖,而且继承了Css2的weight属性
// Css1 = {size: "12px",style: "oblique",weight: "bolder"}
- 深度嵌套对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$.extend(
{ name: “John”, location: { city: “Boston” } },
{ last: “Resig”, location: { state: “MA” } }
);
// 结果:
// => { name: “John”, last: “Resig”, location: { state: “MA” } }
// 新的更深入的 .extend()
jQuery.extend( true,
{ name: “John”, location: { city: “Boston” } },
{ last: “Resig”, location: { state: “MA” } }
);
// 结果
// => { name: “John”, last: “Resig”,
// location: { city: “Boston”, state: “MA” } }
- 给JQuery添加静态方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<html>
<head>
<title></title>
<script type="text/javascript" src="jquery.2.0.3.js"></script>
</head>
<body>
<script type="text/javascript">
$.extend({
add:function(a,b){return a+b;},
minus:function(a,b){return a-b},
multiply:function(a,b){return a*b;},
divide:function(a,b){return Math.floor(a/b);}
});
var sum = $.add(3,5)+$.minus(3,5)+$.multiply(3,5)+$.divide(5,7);
console.log(sum);
</script>
</body>
</html>
JS中的prototype属性
在 JavaScript 中,每个函数对象都有一个默认的属性 prototype,称为函数对象的原型成员,这个属性指向一个对象,称为函数的原型对象.
当我们每定义了一个函数的时候,JavaScript 就创建了一个对应的原型对象,也就是说,当我们定义一个函数的时候,实际上得到了两个对象,一个函数对象,一个原型对象。
原型对象是一个特殊的对象,函数的 prototype 成员指向它的原型对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script type="text/javascript">
function employee(name,job,born)
{
this.name=name;
this.job=job;
this.born=born;
}
var bill=new employee("Bill Gates","Engineer",1985);
employee.prototype.salary=null;
bill.salary=20000;
document.write(bill.salary); // 输出结果:20000
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function Page(){
}
var page1 = new Page();
var page2 = new Page();
// 1.prototype只能对类使用
page1.prototype.f1 = function () {
alert('f1'); //Uncaught TypeError: Cannot set property 'f1' of undefined
}
// 2.如果类不适用prototype添加方法,则实例化的对象无法使用
Page.f3 = function () {
alert('f3');
}
// Page.f3() --- 打印f3
// page.f3() Uncaught TypeError: page.f3 is not a function
// 3.如果是对象添加的方法,其他同类实例化的对象无法使用该方法
page.f2 = function () {
alert('f2');
};
// page2.f2() Uncaught TypeError: page2.f2 is not a function