面向 SPA 编程 - 从 MVC 到 MVVM
随着时代的进步和技术的演进,前端开发也发生了翻天覆地的变化。从过去简单的页面渲染到现在的复杂单页面应用(SPA),前端开发的工作已经不再仅仅是 HTML、CSS 和 JavaScript 的简单组合,而是需要使用各种前端框架和工具来完成复杂的业务逻辑。
在面向 SPA 编程的过程中,模式的选择起着至关重要的作用。在最开始的时候,Model-View-Controller (MVC)是一个很好的选择,它把应用程序分为三个部分:模型、视图和控制器。模型负责应用程序数据和业务逻辑,视图负责呈现数据,并且控制器负责处理用户输入和更新模型和视图。
然而,随着单页面应用的流行,MVC 模式逐渐显示出它的缺点。MVC 模式在面向 SPA 编程时有相当多的局限性,它需要使用手动掌控的 DOM 操作,这使得开发人员陷入不堪重负的传统模式的陷阱中。
此时,前端开发人员可以考虑使用 Model-View-ViewModel(MVVM)模式来替代MVC。MVVM 模式的优点是,由于它会基于可观察对象建立视图/数据绑定,因此可以解决这种问题,View 可以自动更新,而不需要进行手动的 DOM 操作。MVVM 模式将应用程序分为三个部分:模型、视图和视图模型。 MVVM 通过数据绑定技术,让 View 自动获取到 Model 中任何更改内容,并进行实时更新。
MVVM 模式也可以确保前端开发人员更好的分离关注点。MVVM 将业务逻辑和 DOM 操作分离开,并使用 ViewModel 来连接这两方面。开发人员可以更专注于业务逻辑,而无需担心 DOM 操作。
现在让我们看一个关于 MVVM 模式的实际例子。假设我们有一个简单的应用程序,它包含以下两个功能:
- 显示一张图片和一些文字描述
- 用户可以点击按钮,以便更改图像和描述
如果我们使用 MVC 模型来实现这个应用程序,那么代码可能如下所示:
// www.javascriptcn.com code example
const model = {
data: {
imageSrc: '',
description: ''
},
update(data) {
this.data = data
this.emit('dataChange', data)
},
fetch() {
return fetch('xxx').then((res) => {
return res.json()
}).then((data) => {
this.update(data)
})
}
}
const view = {
el: '#app',
template: `
<div>
<img src="{{imageSrc}}">
<p>{{description}}</p>
</div>
`,
render(data) {
const html = this.template
.replace('{{imageSrc}}', data.imageSrc)
.replace('{{description}}', data.description)
$(this.el).html(html)
}
}
const controller = {
init() {
view.render(model.data)
model.fetch()
this.bindEvent()
this.subscribeModel()
},
bindEvent() {
$('#update').on('click', () => {
model.fetch()
})
},
subscribeModel() {
model.on('dataChange', (data) => {
view.render(data)
})
}
}虽然这段代码能够完成需求,但是它需要太多的 DOM 操作和手动更新。如果使用 MVVM 模式,代码可能如下所示:
<div id="app"> <img data-bind="src:imageSrc"> <p data-bind="text:description"></p> <button id="update">Update</button> </div>
// www.javascriptcn.com code example
class ViewModel {
constructor(options) {
this.el = options.el
this.data = options.data
this.template = options.template
this.render()
}
render() {
const html = this.template
.replace(/{{(.*?)}}/g, (matched, key) => {
return this.data[key].value
})
$(this.el).html(html)
this.bindData()
}
bindData() {
const selectors = Object.keys(this.data)
selectors.forEach((selector) => {
const value = this.data[selector]
$(this.el).find(`[${selector}]`).each((index, ele) => {
const attrName = $(ele).attr(selector)
$(ele).attr(attrName, value.value)
})
})
}
}
const viewModel = new ViewModel({
el: '#app',
data: {
imageSrc: {
value: ''
},
description: {
value: ''
}
},
template: `
<div>
<img data-bind="src:imageSrc">
<p data-bind="text:description"></p>
</div>
`
})
$('#update').on('click', () => {
fetch('xxx').then((res) => {
return res.json()
}).then((data) => {
viewModel.data.imageSrc.value = data.imageSrc
viewModel.data.description.value = data.description
viewModel.render()
})
})在 MVVM 的示例中,我们通过 ViewModel 来处理 DOM操作,确保我们能够专注于业务逻辑。通过视图模型,我们可以轻松实现更改DOM 操作,而不需要手动更新它们,我们只需要更新模型,并且模型会自动更新视图。
通过对 MVC 和 MVVM 模式的对比,并使用一个实际例子来演示它们之间的区别和优劣,让我们可以更好地理解和掌握 SPA 编程的知识,学习如何通过 MVVM 模式来提高开发效率和代码可维护性。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d80812a941bf7134e570ec