资讯专栏INFORMATION COLUMN

MV* 框架 与 DOM操作为主 JS库 的案例对比

springDevBird / 1229人阅读

摘要:中定义的处理业务逻辑与提供数据源,中的绑定负责渲染与响应用户点击拖拽等行为,这样就最大保证了视图逻辑相分离。远离的世界,围绕层控制器路由从后端放到前端,更加适合开发。

最近分别使用 Zepto 和 Avalon框架写了个 SPA项目,贴出来讨论下 JS DOM操作为主 JS库 与 MV* 框架的对比

案例(MV* 框架 与 DOM操作 JS库 实例对比) 购物车页面 JS业务逻辑(忽略 Ajax请求--Ajax请求时机根据产品具体情况而定)

以列表方式展示购物车商品

每件商品有"+"、"-" 按钮,点击该按钮则:

检测是否达到购买极限(如:最小购买数量不能小于 1件)

达到购买极限则给该按钮添加相应的 class 以便提示用户该按钮不能再点击

反之则去掉该按钮上的该 class(如:现在商品数量为 1,"-" 为不可用状态,现在点击 "+" 则 "-"变为可用状态)

改变该件商品数量

计算 并 更新该商品总价金额

重新计算 并 更新 购物车所有商品金额

移除单种商品

从视图上找到该 DOM

然后移除该 DOM

重新计算 并 更新 购物车所有商品金额

移除购物车所有商品

显示购物车无商品 div,引导用户到商品列表等其它页面

实现: 实现一:Zepto 版
  

以 DOM操作 JS库实现:jQuery、Zepto、MooTools)

通过后端控制器渲染页面

view:

<{css src="page/cart.css"}>

购物车
style="display: none;"<{/if}> >

购物车空空如也

">去添加

<{if !empty($cart.cartList)}>
商品总价(不含运费) <{$cart.totalAmount|cur}> " class="topBtn">去结算
<{foreach from=$cart.cartList item=item}>

<{$item.cashcoupon.name}>

<{$item.cashcoupon.price|cur}> <{$item.cashcoupon.mktprice|cur}>
<{/foreach}>
商品总价(不含运费)<{$cart.totalAmount|cur}>
<{script src="page/cart.js"}> <{/if}>

JS 逻辑

javascript
// 全局常量 var UA = navigator.userAgent; var ipad = !!(UA.match(/(iPad).*OSs([d_]+)/)), isIphone = !!(!ipad && UA.match(/(iPhonesOS)s([d_]+)/)), isAndroid = !!(UA.match(/(Android)s+([d.]+)/)), isMobile = !!(isIphone || isAndroid); var CLICK = isMobile ? "tap" : "click"; // 移动端触摸、PC单击 事件 // 购物车 var Cart = { // 更新 info update: function ($id, $number, fun) { var data = { id: $id || "", number: $number || 0 }; CGI.POST("wecart-update.html", data, function (data) { // 回调方法 fun && fun(data); }); }, // 计算总价 figurePrice: function () { var goodsList = $(".goodslist"); console.log(goodsList); if (0 === goodsList.length) { this.removeAll(); return false; } // 当前商品金额 var price; // 当前商品数量 var number; // 总金额 var allPrice = 0; $.each(goodsList, function (index, item) { item = $(item); price = parseFloat(item.attr("data-price")); number = parseInt(item.find("input").val()); console.log({"数量": number, "单价": price}); allPrice += price * number; }); console.log("总价:" + allPrice); // DOM 操作 $(".total").text("¥" + allPrice.toFixed(2)); }, // 移除所有 removeAll: function () { // DOM 操作 $("#emptyBox").show(); $(".box").hide(); } }; // 递增、递减 $(".numBox").on(CLICK, function (e) { // numBox var _t = $(this); var dom = $(e.target); // 商品数量 DOM var numDom = _t.find("input"); //console.log(numDom); // 数量 var _v = parseInt(numDom.val()), now_v; // 最大购买数 var max = parseInt(numDom.attr("data-max-count")); if (dom.hasClass("plus")) { // 递增 // 最大购买数量限制 if (_v === max) { return false; } now_v = (_v < 1) ? 1 : (_v >= max ? max : _v + 1); } else if (dom.hasClass("minus")) { // 递减 // 最小购买数量限制 if (_v === 1) { return false; } now_v = (_v < 1) ? 1 : (_v > max ? max : _v - 1); } else { return false; } var cartId = dom.parents(".goodslist").attr("data-cashcoupon-id"); // ajax Cart.update(cartId, now_v, function (data) { // 更改数量 numDom.val(now_v); // 递减数量按钮 var minus = _t.find(".minus"); // 递增数量按钮 var plus = _t.find(".plus"); now_v > 1 && minus.hasClass("bg_gray") && minus.removeClass("bg_gray"); now_v === 1 && !minus.hasClass("bg_gray") && minus.addClass("bg_gray"); now_v < max && plus.hasClass("bg_gray") && plus.removeClass("bg_gray"); now_v >= max && !plus.hasClass("bg_gray") && plus.addClass("bg_gray"); // 计算总价 Cart.figurePrice(); }); event.preventDefault(); }); // 删掉商品 $(".del").on(CLICK, function () { var dom = $(this).parents(".goodslist"); var cartId = dom.attr("data-cashcoupon-id"); cartId && Cart.update(cartId, 0, function (data) { // 提示 SD.Toast({"text": "删除成功!"}); // 移除当先列 dom.remove(); // 计算总价 Cart.figurePrice(); }); }); // 删掉所有商品 $(".delAll").on(CLICK, function (event) { SD.Confirm({ content: "你确定要清空购物车吗?", //lock: false, ok: { text: "残忍清空", fun: function () { Cart.update("", 0, function (data) { // 提示 SD.Toast({"text": "删除成功!"}); // DOM 操作 Cart.removeAll(); }); } }, cancel: { text: "再忍忍" } }); });
实现二:Avalon版
  

以 MV* 框架实现:Angular、Avalon)
通过后端接口获取购物车数据,JS动态渲染页面

view:

html

商品总价(不含运费){{price|currency}} 去结算

{{el.cashcoupon.name}}

{{el.cashcoupon.price|currency}} {{el.cashcoupon.mktprice|currency}}
商品总价(不含运费){{price|currency}}
清空全部

JS 业务代码

javascriptdefine("cart", ["avalon", "request"], function (avalon) {

    var avalonAjax = avalon.ajax;

    var model = avalon.define({
        $id: "cart",
        toggle: true,
        price: 0, // 总金额
        goodsList: [],
        // 递加数量
        plus: function (index) {
            model.goodsList[index].quantity = parseInt(model.goodsList[index].quantity) + 1;

            // 计算总数量 和 总金额
            count();
        },
        // 递减数量
        minus: function (index) {
            if (model.goodsList[index].quantity <= 1) {
                return false;
            }
            model.goodsList[index].quantity = parseInt(model.goodsList[index].quantity) - 1;

            // 计算总数量 和 总金额
            count();
        },
        // 移除当前
        remove: function (index, perish) {
            perish();   // 移除
        },
        // 移除所有
        removeAll: function () {
            avalon.vmodels.cart.goodsList.clear();

            // 计算总数量 和 总金额
            count();
        }
    });

    // 获取数据
    var getData = function () {
        if (avalonAjax) {
            avalon.getJSON("", {method: "ecoupon.cart.list"}, function (data) {
                model.price = data.totalAmount;
                model.goodsList = data.cartList;
            })
        }
    }();

    // 计算总数量 和 总金额
    function count() {
        var _count = 0;
        var _price = 0;
        model.goodsList.forEach(function (goods, index) {
            _count += parseInt(goods.quantity);
            _price += parseFloat(goods.cashcoupon.price) * parseInt(goods.quantity);
        });
        avalon.vmodels.page.cartNum = _count;
        model.price = _price.toFixed(2);
    };

    // 购物车数量监听(目前只能监听商品种类变化, 不能监听商品数量变化)
    model.goodsList.$watch("length", function () {
        count();
    });

    return model;

});
  

zepto 版本中,js 业务代码大量使用了 选择器 来 操作DOM,导致 js 与 view 极度耦合。

  

avalon版本,利用avalon可以大大加快我们项目的开发速度,可以使我们远离 DOM的世界,我们的编程变成了只围绕 model层而不围绕 DOM,即操作 model就是操作 DOM,同时能让我们开发人员离开 DOM都能轻松进行前端开发。avalon中定义的 VM处理业务逻辑与提供数据源,HTML中的绑定负责渲染与响应用户点击拖拽等行为,这样就最大保证了视图逻辑相分离。

优点

JS 与 view 解耦。远离 DOM的世界,围绕 model层

控制器、路由从后端放到前端,更加适合 Web APP开发。SPA应用可以提供更好的用户体验

业务实现的方式转变(由直接操作 DOM变为 操作 VM,更加适合后端童鞋思维方式)

更容易实现前后端分离

官方讲代码量比 jQuery减少50%

....

缺点

MV* 框架学习成本高,概念多(控制器、路由、指令、过滤器、服务、依赖注入...)[哈哈、后端同学最喜欢这种了,学习起来无压力]

发展时间没有 jQuery这种时间长,组件相比 jQuery相差比较大(大多数需要自己实现)

动画

SEO(貌似有解决方案了)

...

  

具体选择就看场景了吧,动画效果、特效多用 jQuery这种,业务复杂用 MV* 这种

原文发在:http://www.webdevs.cn/article/93.html

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85506.html

相关文章

  • [ 前端框架 ] 前端 MV*框架意义

    摘要:从协作关系上讲,很多前端开发团队每个成员的职责不是很清晰,有了前端的框架,这个状况会大有改观。框架的理念是把前端按照职责分层,每一层都相对比较独立,有自己的价值,也有各自发挥的余地。 简介: MV框架又是为什么兴起的呢?它的出现,伴随着一些 Web 产品逐渐往应用方向发展,遇到了在 C/S 领域相同的问题:由于前端功能的增强、代码的膨胀,导致不得不做前端的架构这个事情了。经常有人质疑...

    fxp 评论0 收藏0
  • 前端每周清单半年盘点之 JavaScript 篇

    摘要:前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点分为新闻热点开发教程工程实践深度阅读开源项目巅峰人生等栏目。背后的故事本文是对于年之间世界发生的大事件的详细介绍,阐述了从提出到角力到流产的前世今生。 前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点;分为新闻热点、开发教程、工程实践、深度阅读、开源项目、巅峰人生等栏目。欢迎...

    Vixb 评论0 收藏0
  • Vue.js新手入门指南[转载]

    摘要:就是一个用于搭建类似于网页版知乎这种表单项繁多,且内容需要根据用户的操作进行修改的网页版应用。单页应用程序顾名思义,单页应用一般指的就是一个页面就是应用,当然也可以是一个子应用,比如说知乎的一个页面就可以视为一个子应用。 最近在逛各大网站,论坛,以及像SegmentFault等编程问答社区,发现Vue.js异常火爆,重复性的提问和内容也很多,楼主自己也趁着这个大前端的热潮,着手学习了一...

    MartinHan 评论0 收藏0
  • javascript框架学习计划

    摘要:前言终于要做这个计划了,前端框架千千万,绝不能一头扎进去盲目开始,本片文章总结一下目前前各种端框架,以及它们的用途主要解决什么问题,然后最后做出学习计划。希望入了前端坑的同学们可以有所帮助。但是库与框架很难严格区分,所以统一称为解决方案。 前言:终于要做这个计划了,前端框架千千万,绝不能一头扎进去盲目开始,本片文章总结一下目前前各种端框架,以及它们的用途主要解决什么问题,然后最后做出学...

    airborne007 评论0 收藏0
  • 让React应用“动”起来

    摘要:因为其组件只是根据提供的及属性,生成动画的数据,业务应用中拿到生成的数据后根据需要添加需要动画的组件样式。除了上述简单的动画应用,在复杂动画的实现方面,表现非常优越。 WEB应用中动画很重要 不管是web应用还是原生应用,也不论是PC端应用还是移动端应用,动画都扮演了一个重要的角色。 尽管动画并不会添加应用的实际动能,但一个好的动画,一个流畅且优雅,选择在恰当时机出现的动画,能为应用增...

    xiyang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<