需求到模块
- 需求
- 可输入数值的左右移动div,可以撤销和前进;
- 做一个画廊效果,图片数量由后端数据决定,排列顺序不一定,每个图片有这个图片的下标;
- 模块
- 负责移动div的模块;
- 输入指令模块;
- 状态管理模块;
- 模块设计
数据驱动思想
- 从views驱动到data驱动
- 视图驱动
命令模式
- 定义:把具体的指令与实现隔离,对调用与执行解耦;
- 做法:将方法、数据封装到单一的对象中,对调用方与执行方进行解耦,达到职责分离的目的;
- 解决问题:降低调用部分与执行分布的解耦,让使用的时候只需要关心指令,而不需要关心具体的api;
如何更好的做一个功能
需求一实现
<template>
<div class="moduleThink">
<div>
<button id="left" @click="toLeft">左移动</button>
<input type="text" name="" id="num"/>
<button id="right" @click="toRight">右移动</button>
</div>
<div class="wrapper">
<div id="content">这是个移动的div</div>
</div>
<div>
<button id="back" @click="goBack">后退</button>
<button id="font" @click="goFont">前进</button>
</div>
</div>
</template>
<script>
class DataManager {
constructor() {
this.stateArr = [{
property: 'left',
num: 0
}];
this.stateIndex = 0;
}
pushState(obj) {
this.stateArr.push(obj);
this.stateIndex = this.stateArr.length - 1;
}
getBack() {
if (this.stateIndex > 0) {
this.stateIndex--;
}
}
getFont() {
if (this.stateIndex < this.stateArr.length - 1) {
this.stateIndex++;
}
}
getData() {
return this.stateArr[this.stateIndex];
}
}
export default {
name: 'ModuleThink',
data() {
return {
dataManager: new DataManager()
}
},
methods: {
changeDiv: function() {
var _data = this.dataManager.getData();
var element = document.getElementById('content');
element.style[_data.property] = _data.num;
},
toLeft: function() {
var value = document.getElementById('num').value || 0;
var left = document.getElementById('content').style.left || 0;
this.handleDiv.excute({
property: 'left',
num: (parseInt(left) - parseInt(value)) + 'px'
});
},
toRight: function() {
var value = document.getElementById('num').value || 0;
var left = document.getElementById('content').style.left || 0;
this.handleDiv.excute({
property: 'left',
num: parseInt(value) + parseInt(left) + 'px'
});
},
goBack: function() {
this.handleDiv.excute('back');
},
goFont: function() {
this.handleDiv.excute('font');
}
},
mounted() {
var vm = this;
vm.handleDiv = (function() {
return {
//命令模式
excute: function(commander) {
var commanderArr = ['back', 'font', 'left', 'right'];
if (typeof commander === 'object') {
vm.dataManager.pushState(commander);
vm.changeDiv();
} else {
var has = false;
if (commanderArr.indexOf(commander) != -1) {
has = true;
//策略模式
var state = {
font: function() {
vm.dataManager.getFont();
vm.changeDiv();
},
back: function() {
vm.dataManager.getBack();
vm.changeDiv();
}
};
state[commander]();
} else {
throw new Error('命令不合法');
}
}
}
}
})();
}
}
</script>
<style scoped>
.wrapper {
position: relative;
}
#content {
position: absolute;
}
</style>
效果图:
需求二实现
<template>
<div id="imgContent">
</div>
</template>
<script>
/**
* 命令解析模块---生成dom节点--具体的渲染.
*
*
* */
class Picture {
constructor(options) {
this.html = '';
this.options = options;
this.render();
}
initData() {
//各大框架里面都有使用的东西--与默认属性合并
//1.有些属性不需要用户提供
//2.防止用户漏传入
var final = {};
var defaultOptions = {
data: [],
id: document,
sort: 'normal',
size: [100, 100]
};
//适配器模式
for (let item in defaultOptions) {
if (this.options[item]) {
final[item] = this.options[item];
if (item === 'id') {
final[item] = document.getElementById(this.options[item]);
}
} else {
final[item] = defaultOptions[item];
}
}
return final;
}
initDOM(finalOptions) {
//需要样式
var styleArr = [{
//包裹图片div样式
float: 'left',
width: finalOptions.size[0] + 'px',
height: finalOptions.size[1] + 'px',
position: 'relative'
}, {
//下标顺序的样式
position: 'absolute',
bottom: '0px',
right: '0px',
background: 'black',
color: 'white',
padding: '10px',
width: '10px',
height: '10px'
}, {
//图片样式
width: '100%',
height: '100%'
}];
var wraper = document.createElement('div');
//排序图片
//用策略模式
var commanderHandle = {
normal: function(arr) {
return arr;
},
reverse: function(arr) {
return arr.reverse();
}
}
var data = commanderHandle[finalOptions.sort](finalOptions.data);
data.forEach((url, index) => {
var div = document.createElement('div');
var img = document.createElement('img');
var span = document.createElement('span');
var styleObj = null;
var handleDom = null;
styleArr.forEach((style, index) => {
//享元模式
switch (index) {
case 0:
handleDom = div;
break;
case 1:
handleDom = span;
break;
case 2:
handleDom = img;
break;
}
for (var styleName in style) {
handleDom.style[styleName] = style[styleName];
}
});
img.setAttribute('src', url);
div.appendChild(img);
span.innerHTML = index + 1;
div.appendChild(span);
wraper.appendChild(div);
});
this.html = wraper;
}
renderDOM(element) {
element.appendChild(this.html);
}
render() {
var order = this.initData();
this.initDOM(order);
this.renderDOM(order.id);
}
}
export default {
name: 'Gallery',
mounted() {
var options = {
id: 'imgContent',
data: ['./static/img/1.jpg', './static/img/2.jpg', './static/img/3.jpg', './static/img/4.jpg', './static/img/5.jpg', './static/img/6.jpg']
}
var pic = new Picture(options);
}
}
</script>