前提背景:大前端的时代造就了前端的业务逻辑越来越重,原有的MVP设计开发模式(jquery时代)造成了前端界面和数据操作都集中在MVP模式中的P层架构即控制器上,P层承担了大量的逻辑代码和操作视图DOM代码,两者交互在一起耦合性很强并且很重,而V(视图层)、M(数据层)的比重很轻,这对于业务功能越来越复杂的前端应用来说,大型的应用程序使用MVP模式已经不再是很好的选择。MVVM模式的诞生给我们构建复杂应用程序提供了极佳的管理模式和开发模式,VM层替代了原有的P层,它自动的处理dom和数据之间的关系,从而将我们把注意力集中在M层。随着MVVM越来越流行,遵循MVVM模式的Angular、React、Vue三大框架的应运而生,为我们开发大前端应用提供了极大的便利性。下面通过一小段代码对比MVP模式和MVVM之间的区别:
程序目标:实现简单的todolist效果:
MVP设计模式实现代码:
<html>
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<title>jquery todolist</title>
<script src="../js/jquery-3.2.1.js"></script>
</head>
<body>
<div>
<input id="input" type="text">
<button id="btn">提交</button>
<ul id="list"></ul>
</div>
</body>
<script>
/*
* jquery开发遵循MVP模式,M模型 V视图 P控制器*/
// js构造函数
function Page() {
}
// 给Page对象实例增加一个方法init,调用bindEvents()方法,这个方法给button绑定一个点击事件
// $.proxy()方法将this.handleBtnClick()方法绑定到this即page实例
$.extend(Page.prototype, {
init: function () {
this.bindEvents();
},
bindEvents: function () {
var btn = $("#btn");
btn.on('click', $.proxy(this.handleBtnClick, this));
},
handleBtnClick: function () {
var inputElem = $("#input");
var inputVal = inputElem.val();
var ulElem = $("#list");
if(!inputVal){
window.alert('你输入的内容为空,不允许添加!');
return;
}
ulElem.append('<li>' + inputVal + '</li>');
inputElem.val('');
}
});
// 实例化对象调用方法
var page = new Page();
page.init();
</script>
</html>
MVP模式写的代码可以看出大量的逻辑代码和操作dom的代码交织在P控制层里,使用jquery开发遵循MVP模式的项目里,60%-70%的代码都和dom操作有关,造成了前端代码很重并且容易出错。
MVVM模式实现同样效果,使用vue框架实现:
<!DOCTYPE html><html>
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<title>vue 实现todolist</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<input v-model="inputVal" type="text">
<button v-on:click="handleBtnClick">提交</button>
<ul>
<li v-for="(item,index) in list" :key="index">{ {item}}</li>
</ul>
</div>
</body>
<script>
var app = new Vue({
el: "#app",
data: {
inputVal: '',
list: []
},
methods: {
handleBtnClick: function () {
this.list.push(this.inputVal);
this.inputVal = '';
}
}
});
</script></html>
MVVM模式包含视图层(V)、数据层(M)、VM(层),不在包含控制器P层,而VM层是VUE框架内部实现的,我们不需要关心,通过上述实例可以看出我们进行的都是对数据的处理,数据发生改变,dom结构随之发生变化,VM层就是实现这一过程的机制。
再来引入一个思想:前端组件化思想,前端页面的每个可视区域都可以看做是一个个组件构成的,组件化的好处是当我们的前端界面功能复杂时,我们可以拆分成一个个组件,然后在每个组件里写相应的dom结构,js,css等,通过webpack等工程化工具使我们的组件组合成一个大界面,方便我们以后的维护和代码的复用,而我们所要做的上拉刷新下拉加载组件就是基于这一思想和vue的模式来实现的。
先来认识一下better-scrol,该项目的github地址是,点击打开链接
插件作者是黄轶,引用作者的一篇文章当better-scroll遇见vue,里面详细解释了better-scroll的滚动原理和上拉加载,下拉刷新所需的API,
废话不多说,直接贴源码,亲测可以完美正常使用!
scroll.vue
<div class="scroll-wrapper" ref="wrapper">
<div class="scroll-main">
<!-- 顶部提示信息 -->
<div class="top-tip">
<div class="refresh-top"><span v-show="IsRefresh" class="icon-jiazai"></span><span
class="refresh-hook">下拉刷新</span></div>
</div>
<slot></slot>
<div class="bottom-tip">
<span v-show="IsLoading" class="icon-jiazai"></span><span class="loading-hook">查看更多</span>
</div>
</div>
<div class="refresh-success alert-hook">刷新成功</div>
</div>
</template>
<script type="text/ecmascript-6">
import BScroll from 'better-scroll';
export default {
props: {
/**
* 1 滚动的时候会派发scroll事件,会截流。
* 2 滚动的时候实时派发scroll事件,不会截流。
* 3 除了实时派发scroll事件,在swipe的情况下仍然能实时派发scroll事件
*/
probeType: {
type: Number,
default: 1
},
/**
* 点击列表是否派发click事件
*/
click: {
type: Boolean,
default: true
},
/**
* 是否开启横向滚动
*/
scrollX: {
type: Boolean,
default: false
},
/**
* 是否派发滚动事件
*/
listenScroll: {
type: Boolean,
default: false
},
/**
* 列表的数据
*/
data: {
type: Array,
default: null
},
/**
* 标识列表的数据是否为空
*/
flag: {