分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 网页技术

记一次数据、逻辑、视图分离的原生JS项目实践

发布时间:2023-09-06 02:10责任编辑:郭大石关键词:暂无标签

一切的开始源于这篇文章:一句话理解Vue核心内容。

在文章中,作者给出了这样一个思考:

假设现在有一个这样的需求,有一张图片,在被点击时,可以记录下被点击的次数。
这看起来很简单吧, 按照上面提到到开发方式,应该很快就可以搞定。
那么接下来,需求稍微发生了点变动, 要求有两张图片,分别被点击时,可以记录下各自的点击次数。这次似乎也很简单,只需把原先的代码复制粘贴一份就可以了。
那么当这个需求变成五张图片时,你会怎么做? 还是简单复制粘贴吧,这样完全可以完成这个需求,但是你会觉得很别扭,因为你的代码此时变得很臃肿,存在很多重复的过程,但是似乎还在你的忍受范围内。
这时候需求又发生了微小的变动,还是五张照片分别记录被点击次数,不过这样单独罗列五张图片似乎太占空间,现在只需要存在一个图片的位置,通过选择按钮来切换被点击的图片。 这时候你可能会奔溃掉,因为要完成这个看似微小的改动,你原先写的大部分代码可能都需要被删掉,甚至是完全清空掉,从零开始写起。

也许你应该像我一样,从一张图片到五张图片完成上面的需求。相信我,这个过程很有趣。因为每增加一次需求,你或多或少都会需要重构你的代码。特别是如果你直接从一张跳到五张的话,那么你就需要完全重构你的代码。

二话不说,先看整个项目的效果。这里我直接放了五张图片实现的效果。

说实话,这其实是一个非常简单的demo,只要对JS的知识稍微熟悉一点,并且在写代码时注意一下闭包的问题,就可以轻松的实现效果。在没学vue之前,我们一定是这样写代码的。

<ul> ???????<li>one</li> ???????<li>two</li> ???????<li>three</li> ???????<li>fore</li> ???????<li>five</li> ???</ul> ???<div class="container"> ???????<img class="pic" src=‘http://www.jqhtml.com/wp-content/themes/sc/images/logo.png‘> ???????<img class="pic" src=‘http://www.jqhtml.com/wp-content/themes/sc/images/logo.png‘> ???????<img class="pic" src=‘http://www.jqhtml.com/wp-content/themes/sc/images/logo.png‘> ???????<img class="pic" src=‘http://www.jqhtml.com/wp-content/themes/sc/images/logo.png‘> ???????<img class="pic" src=‘http://www.jqhtml.com/wp-content/themes/sc/images/logo.png‘> ???????<p class=‘num‘></p> ???????<p class=‘num‘></p> ???????<p class=‘num‘></p> ???????<p class=‘num‘></p> ???????<p class=‘num‘></p> ???</div> ???<script> ???????var img = document.getElementsByTagName(‘img‘); ???????var num = document.getElementsByTagName(‘p‘); ???????var li = document.getElementsByTagName(‘li‘); ???????for (let i = 0; i < 5; i++) { ???????????li[i].onclick = (function(index) {//形成闭包 ???????????????return (function(e) { ???????????????????for (let j = 0; j < 5; j++) { ???????????????????????//console.log(num); ???????????????????????num[j].removeAttribute(‘class‘); ???????????????????????img[j].removeAttribute(‘class‘); ???????????????????} ???????????????????num[index].setAttribute(‘class‘,‘show‘); ???????????????????img[index].setAttribute(‘class‘,‘show‘); ???????????????}) ???????????})(i) ???????????img[i].onclick = counter(num[i]); ???????} ???????????????//计数器函数 ???????function counter(ele) { ???????????var num = 0,//点击的次数 ???????????????node = ele; ???????????return function(e) {//形成闭包让每个元素都有自己私有num变量 ???????????????node.innerHTML = ++num; ???????????????????????????} ???????} ???</script>

这种直接操作DOM来改变视图的开发方式似乎并不能hold住复杂的逻辑和代码量,况且在这个例子中逻辑并非很复杂。这也证明了由JS来直接操作DOM以改变视图的开发方式并不适合如今的前端开发。这也是前端开发为什么需要类似vue这样的框架。

如果你学过vue,你会发现完成这个需求,只需要改一下data对象里的图片数就轻松的实现了需求。(用vue实现上面的需求更加简单,只需要几行代码就可以实现,并且可扩展性也好,感兴趣的同学可以用vue实现一下上面的需求)

我们可以明显的感觉到vue这种数据和视图分离的代码组织方式更加的容易实现扩展,并且代码可读性更强。而我们上面的原生JS 的实现方式将数据和视图都混在一起了,当项目需求越来越复杂的时候会让代码越臃肿,且越不易于扩展。

其实数据和视图分离并不是框架的专利,要知道框架也是由原生的JS实现的。因此原生JS也可以写出数据和视图分离的代码,让项目变得更加易于扩展。

下面我们就按照数据、视图、逻辑分离的思路来重构一下我们这个项目的代码。

首先,我们把数据给抽离,可以看到视图的样子大概是这样的一个形式。

<body> ???<ul id="cat-list">  //列表 ???</ul> ???<section id="cat">//猫图片的显示区域 ???????<h2 id="cat-name"></h2> ???????<div id="cat-count"></div> ???????<img src="" alt="" id="cat-img"> ???</section></body>

我们将数据存储在一个名为model的对象中。

var model = { ???currentCat: null, ???cats: [ //猫的图片数据 ???????{ ???????????clickCount : 0, ???????????name : ‘Tabby‘, ???????????imgSrc : ‘img/434164568_fea0ad4013_z.jpg‘, ???????}, ???????//省略余下的图片数据 ???]}

在初始化页面的时候,我们要加载数据,渲染页面。

var catView = { //图片区域的视图 ???init: function() { ???????//储存DOM元素,方便后续操作 ???????this.cat = document.getElementById(‘cat‘); ???????this.catName = document.getElementById(‘cat-name‘); ???????this.catCount = document.getElementById(‘cat-count‘); ???????this.catImg = document.getElementById(‘cat-img‘); ???????this.cat.addEventListener(‘click‘,function() {//给每张图片添加点击事件 ???????????controler.addCount(); ???????},false); ???????this.render(); ???}, ???render: function() { ???????let currentCat = controler.getCurrentCat(); ???????this.catName.textContent = currentCat.name; ???????this.catCount.textContent = currentCat.clickCount; ???????this.catImg.src = ‘../‘ + currentCat.imgSrc; ???}}var listView = { ???//列表区域的视图 ???init: function() { ???????this.catList = document.getElementById(‘cat-list‘); ???????this.render(); ???}, ???render: function() { ???????let cats = controler.getCats(); ???????let fragment = document.createDocumentFragment(‘ul‘); ???????cats.forEach((item,index) => { ???????????let li = document.createElement(‘li‘); ???????????li.textContent = item.name; ???????????li.setAttribute(‘class‘,‘item‘); ???????????li.addEventListener(‘click‘,function() {//给li添加点击事件 ???????????????controler.setCurrentCat(item); ???????????????catView.render(); ???????????}) ???????????fragment.appendChild(li); ???????}) ???????this.catList.appendChild(fragment); ???????fragment = null; ???}}

从上面的视图对象可以知道,视图并不直接从model中获取数据,而是通过一个中间对象controler来间接访问model,也就是说controler对象实现了所有的视图和数据间的逻辑操作。

var controler = { ???init: function() { ???????model.currentCat = model.cats[0]; ???????catView.init(); ???????listView.init(); ???}, ???//获取全部的猫 ???getCats: function() { ???????return model.cats; ???}, ???//获取当前显示的猫 ???getCurrentCat: function() { ???????return model.currentCat; ???}, ???//设置当前被点击的猫 ???setCurrentCat: function(cat) { ???????return model.currentCat = cat; ???}, ???addCount: function() { ???????model.currentCat.clickCount++; ???????catView.render(); ???} }

到这里,我们用数据、视图、逻辑分离的代码组织方式重构了一个小型的项目,从该项目中可以清楚的看到:数据model只负责存储数据,而视图view只负责页面的渲染,而controler负责view和model之间的交互逻辑的实现。

等一下,既然说交互逻辑是放在controler中实现的,而视图只负责渲染页面,那为什么click点击事件会放在视图层呢?

这里要明确一下的就是(仅个人理解):视图并不是侠义上的静态页面,视图指的是静态页面和动态入口(用户交互,如点击事件),所以事件的绑定放在view层是完全可以理解的,view层实现了一个动态的入口,而用户点击后的所有逻辑操作都是在controler层实现的。

记一次数据、逻辑、视图分离的原生JS项目实践

原文地址:https://www.cnblogs.com/yuliangbin/p/9463114.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved