ZhangYang's Blog

JavaScript实现MVC

VC设计模式封装前

看完《javascript设计模式》,将自己之前写的插件,用MV及MVC设计模式重新封装了一遍

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// sticky-topbar.js
!function () {
window.addEventListener("scroll", function () {
if (window.scrollY > 0) {
topNavBar.classList.add('sticky')
} else {
topNavBar.classList.remove('sticky')
}
})
}.call()
// smoothly-navigation.js
!function () {
let aTags = document.querySelectorAll('nav.menu > ul > li > a')
function animate(time) {
requestAnimationFrame(animate);
TWEEN.update(time);
}
requestAnimationFrame(animate);
for (let i = 0; i < aTags.length; i++) {
aTags[i].onclick = function (x) {
x.preventDefault()
let a = x.currentTarget
let href = a.getAttribute('href') //'#siteAbout'
let element = document.querySelector(href)
let top = element.offsetTop
let currentTop = window.scrollY
let targetTop = top - 80
let s = targetTop - currentTop // 路程
var coords = { y: currentTop }; // 起始位置
var t = Math.abs((s / 100) * 300) // 时间
if (t > 500) { t = 500 }
var tween = new TWEEN.Tween(coords) // 起始位置
.to({ y: targetTop }, t) // 结束位置 和 时间
.easing(TWEEN.Easing.Cubic.InOut) // 缓动类型
.onUpdate(function () {
// coords.y 已经变了
window.scrollTo(0, coords.y) // 如何更新界面
})
.start(); // 开始缓动
}
}
}.call()
//message.js
!function () {
var APP_ID = 'baTF3mT0Ybt7NcGffQphNKDW-gzGzoHsz';
var APP_KEY = '02G0rMK0z1bMwV1mvUhOIRpi';
AV.init({
appId: APP_ID,
appKey: APP_KEY
});
myForm.addEventListener("submit", function (e) {
e.preventDefault()
var remark = document.querySelector("input[name='remark']").value
var name = document.querySelector("input[name='name']").value
var TestObject = AV.Object.extend('message')
var testObject = new TestObject()
testObject.save({
remark: remark,
name: name
}).then(function (testObject) {
var li = document.createElement("li")
li.innerText = `${testObject.attributes.name}:${testObject.attributes.remark}`
var ul = document.querySelector("#content")
ul.appendChild(li)
document.querySelector("input[name='remark']").value = ""
document.querySelector("input[name='name']").value = ""
})
})
var query = new AV.Query('message');
query.find().then(function (remarks) {
var aRemark = remarks.map(function (v) { return v.attributes })
aRemark.forEach(function (v) {
var li = document.createElement("li")
li.innerText = `${v.name}:${v.remark}`
var ul = document.querySelector("#content")
ul.appendChild(li)
});
});
}.call()

VC设计模式封装后

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// sticky-topbar.js
!function () {
var view = document.querySelector("#topNavBar")
var controller = {
view: null,
init: function (view) {
this.view = view
this.bindEvents() // this.bindEvents.call(this)
},
bindEvents: function(){
window.addEventListener("scroll", function () {
if (window.scrollY > 0) {
this.active()
} else {
this.deactive()
}
}.bind(this))
},
active: function(){
this.view.classList.add('sticky')
},
deactive:function(){
this.view.classList.remove('sticky')
}
}
controller.init(view) // controller.init.call(controller,view)
}.call()
// smoothly-navigation.js
!function () {
var view = document.querySelector("nav.menu")
var controller = {
view: null,
init: function (view) {
this.view = view
this.bindEvents()
this.initAnimation()
},
bindEvents: function () {
let aTags = view.querySelectorAll('ul > li > a')
for (let i = 0; i < aTags.length; i++) {
aTags[i].onclick = function (x) {
x.preventDefault()
let a = x.currentTarget
let href = a.getAttribute('href') //'#siteAbout'
let element = document.querySelector(href)
this.scrollToElement(element)
}
}
},
initAnimation: function () {
function animate(time) {
requestAnimationFrame(animate);
TWEEN.update(time);
}
requestAnimationFrame(animate);
},
scrollToElement: function (element) {
let top = element.offsetTop
let currentTop = window.scrollY
let targetTop = top - 80
let s = targetTop - currentTop // 路程
var coords = { y: currentTop }; // 起始位置
var t = Math.abs((s / 100) * 300) // 时间
if (t > 500) { t = 500 }
var tween = new TWEEN.Tween(coords) // 起始位置
.to({ y: targetTop }, t) // 结束位置 和 时间
.easing(TWEEN.Easing.Cubic.InOut) // 缓动类型
.onUpdate(function () {
// coords.y 已经变了
window.scrollTo(0, coords.y) // 如何更新界面
})
.start(); // 开始缓动
}
}
controller.init(view)
}.call()
// message.js
!function () {
var view = document.querySelector("#message")
var controller = {
view: null,
messageList: null,
form: null,
initAv: function () {
var APP_ID = 'baTF3mT0Ybt7NcGffQphNKDW-gzGzoHsz';
var APP_KEY = '02G0rMK0z1bMwV1mvUhOIRpi';
AV.init({
appId: APP_ID,
appKey: APP_KEY
});
},
init: function (view) {
this.view = view
this.form = view.querySelector("form")
this.messageList = view.querySelector("#content")
this.initAv()
this.loadMessages()
this.bindEvents()
},
bindEvents: function () {
this.form.addEventListener("submit", (e) =>{
e.preventDefault()
console.log(this)
this.saveMessage()
})
},
saveMessage: function () {
var remark = this.form.querySelector("input[name='remark']").value
var name = this.form.querySelector("input[name='name']").value
var TestObject = AV.Object.extend('message')
var testObject = new TestObject()
testObject.save({
remark: remark,
name: name
}).then((testObject) => {
var li = document.createElement("li")
li.innerText = `${testObject.attributes.name}:${testObject.attributes.remark}`
this.messageList.appendChild(li)
this.form.querySelector("input[name='remark']").value = ""
this.form.querySelector("input[name='name']").value = ""
})
},
loadMessages: function () {
var query = new AV.Query('message');
query.find().then((remarks) => {
var aRemark = remarks.map(function (v) { return v.attributes })
aRemark.forEach((v) => {
var li = document.createElement("li")
li.innerText = `${v.name}:${v.remark}`
this.messageList.appendChild(li)
});
});
}
}
controller.init(view)
}.call()

MVC设计模式封装例子

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// index.html
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<!-- 存储服务 -->
<script src="//cdn.jsdelivr.net/npm/leancloud-storage@3.15.0/dist/av-min.js"></script>
<!-- 即时通讯服务 -->
<script src="//cdn.jsdelivr.net/npm/leancloud-realtime@4.3.1/dist/realtime.browser.min.js"></script>
</head>
<body>
<section id="message">
<ul id="content"></ul>
<form id="myForm">
<label>姓名:<input type="text" name="name"></label>
<label>留言:<input type="text" name="remark"></label>
<input type="submit" value="提交">
</form>
</section>
<script src="message.js"></script>
</body>
</html>
// message.js
!function(){
var model = {
// 获取数据
init: function(){
var APP_ID = 'TsDnap9SEXjSvGSowP7gXXJC-gzGzoHsz'
var APP_KEY = 'rGye31p12mM3wFpNRn9RADu9'
AV.init({ appId: APP_ID, appKey: APP_KEY })
},
fetch: function(){
var query = new AV.Query('Message');
return query.find() // Promise 对象
},
// 创建数据
save: function(name, content){
var Message = AV.Object.extend('Message');
var message = new Message();
return message.save({ // Promise 对象
'name': name,
'content': content
})
}
}
var view = document.querySelector('section.message')
var controller = {
view: null,
model: null,
messageList: null,
init: function(view, model){
this.view = view
this.model = model
this.messageList = view.querySelector('#messageList')
this.form = view.querySelector('form')
this.model.init()
this.loadMessages()
this.bindEvents()
},
loadMessages: function(){
this.model.fetch().then(
(messages) => {
let array = messages.map((item)=> item.attributes )
array.forEach((item)=>{
let li = document.createElement('li')
li.innerText = `${item.name}: ${item.content}`
this.messageList.appendChild(li)
})
}
)
},
bindEvents: function(){
this.form.addEventListener('submit', (e) => {
e.preventDefault()
this.saveMessage()
})
},
saveMessage: function(){
let myForm = this.form
let content = myForm.querySelector('input[name=content]').value
let name = myForm.querySelector('input[name=name]').value
this.model.save(name, content).then(function(object) {
let li = document.createElement('li')
li.innerText = `${object.attributes.name}: ${object.attributes.content}`
let messageList = document.querySelector('#messageList')
messageList.appendChild(li)
myForm.querySelector('input[name=content]').value = ''
console.log(object)
})
}
}
controller.init(view, model)
}.call()