成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

參與知乎 live — 編寫(xiě)優(yōu)雅的前端業(yè)務(wù)代碼總結(jié)

CNZPH / 2461人閱讀

摘要:知乎原地址編寫(xiě)優(yōu)雅的前端業(yè)務(wù)代碼前言當(dāng)我們?cè)趯?xiě)業(yè)務(wù)代碼的時(shí)候,我們到底在寫(xiě)什么其實(shí)是對(duì)交互的一些處理。遍歷,通過(guò)事件委派,將事件綁定在上。事件綁定濫用使用進(jìn)行統(tǒng)一管理。寫(xiě)代碼要說(shuō)人話。

知乎 live 原地址:編寫(xiě)優(yōu)雅的前端業(yè)務(wù)代碼

前言

當(dāng)我們?cè)趯?xiě)業(yè)務(wù)代碼的時(shí)候,我們到底在寫(xiě)什么?

其實(shí)是對(duì)交互的一些處理。所有的交互都是基于用戶或者瀏覽器的一些行為來(lái)觸發(fā)的,比如渲染頁(yè)面,在頁(yè)面onload方法觸發(fā)之后,我們的js代碼才會(huì)執(zhí)行,比如說(shuō)懶加載,根據(jù)用戶滾動(dòng)或者可視區(qū)域的變化來(lái)觸發(fā),比如按鈕的點(diǎn)擊之后頁(yè)面的局部刷新,比如input框輸入、表單提交、上傳文件等等,以上所說(shuō)的這些行為組成起來(lái)的就是我們前端要寫(xiě)的業(yè)務(wù)邏輯。

我們所寫(xiě)的業(yè)務(wù)都是基于事件來(lái)對(duì)產(chǎn)品功能和場(chǎng)景進(jìn)行描述。

頁(yè)面的執(zhí)行順序是怎樣的?

頁(yè)面在初始化的時(shí)候,先加載css,然后加載html的節(jié)點(diǎn),最后將js放在頁(yè)尾按順序執(zhí)行,然后css加載,模板輸出之后css生效,js再加載,js再對(duì)頁(yè)面的模板進(jìn)行交互處理,比如編譯模板,最后再把交互功能比如事件進(jìn)行綁定。無(wú)論寫(xiě)什么業(yè)務(wù),都會(huì)是這個(gè)生命周期。

一個(gè)頁(yè)面的輸出是有它的生命周期的,同時(shí),一個(gè)js程序,比如vue或者react也是有自己的生命周期的,所以每一個(gè)類(lèi),每一個(gè)業(yè)務(wù)邏輯都是有自己的生命周期的。

下面是react的組件的生命周期:最開(kāi)始的時(shí)候先拿到默認(rèn)的參數(shù)屬性,然后初始化狀態(tài),在render之前有一個(gè)事件的廣播,在render之后有一個(gè)事件的廣播,這時(shí)候這個(gè)組件就render到頁(yè)面上了。組件在運(yùn)行的時(shí)候有兩個(gè)方式,一個(gè)是狀態(tài)的改變,它會(huì)觸發(fā)update,再去觸發(fā)state的改變,然后再對(duì)應(yīng)地重新render,在render之前會(huì)先觸發(fā)事件廣播,render之后也會(huì)觸發(fā)一個(gè)事件廣播。另一個(gè)方式是卸載,卸載之前會(huì)觸發(fā)一個(gè)廣播。

vue的生命周期和react的其實(shí)是很像的,它只不過(guò)比react多了一步對(duì)template和el進(jìn)行一個(gè)判斷的掃描,對(duì)應(yīng)的也是render渲染,在渲染之后會(huì)有一個(gè)屬性的update,有一個(gè)銷(xiāo)毀的過(guò)程。

總結(jié)一下,vue和react的生命周期其實(shí)就是完成它這個(gè)前端框架的業(yè)務(wù)邏輯。

實(shí)例

下面這段代碼是將一個(gè)面向過(guò)程的js程序改為面向?qū)ο蠓绞街蟮膉s程序。

(function (global, $, _, doc) {
    "use strict";

    // 定義一個(gè)構(gòu)造器,是這個(gè)文件的入口
    var app = function (options) { 
        options = options || {};
        this.a = options.a;
        // ...
        this.eventMap = {
            "click .title": "titleClick",
            "dbclick .input": "inputDbclick",
        };

        // 初始化所有節(jié)點(diǎn)屬性
        this.initEles();
        this.init();
    };

    // 定義構(gòu)造函數(shù)靜態(tài)屬性,掛載所有選擇器的屬性
    app.Eles = {
        pap: $(".paper"),
        centryY: $(".centry-y")
    };

    // 工具方法
    var utils = {
        has: function(arr, name) {
            return arr.indexOf(name) > -1;
        },
        // ...  
    };

    app.prototype = {
        constructor: app,
        initEles: function () {
            var eles = app.Eles;
            for (var name in eles) {
                if (eles.hasOwnProperty(name)) {
                    this[name] = $(eles[name]);
                }
            }
        },
        init: function () {
            this.bindEvent(this.eventMap);
        },
        initDrag: function () {
            // ...
        },
        uninitDrag: function () {
            // ...
        },
        bindEvent: function (maps) {
            this.initDrag();
            this.initOrdinaryEvents(maps);
        },
        unbindEvent: function (maps) {
            this.uninitDrag();
            this.unInitOrdinaryEvents(maps);
        },
        initOrdinaryEvents: function (maps) {
            this._scanEventsMap(maps, true);
        },
        unInitOrdinaryEvents: function (maps) {
            this._scanEventsMap(maps, false);
        },
        _scanEventsMap: function (maps, isOn) {
            var delegateEventSplitter = /^(S+)s*(.*)$/,
                bind = isOn ? this._delegate : this._undelegate;

            for (var keys in maps) {
                if (maps.hasOwnProperty(keys)) {
                    var matchs = keys.match(delegateEventSplitter);
                    bind(matchs[1], matchs[2], this[maps[keys]].bind(this));
                }
            }
        },
        _delegate: function (name, selector, func) {
            // 事件委派,將事件綁定在$(documet)上
            doc.on(name, selector, func);
        },
        _undelegate: function (name, selector, func) {
            doc.off(name, selector, func);
        },
        destroy: function() {
            this.unbindEvent();
        }
    };

    // 將構(gòu)造函數(shù)掛在window上,那么在外部也能訪問(wèn)閉包內(nèi)的屬性,相當(dāng)于對(duì)外暴露了一個(gè)接口
    global.app = app;

    $(function () {
        // 實(shí)例化構(gòu)造函數(shù),相當(dāng)于這個(gè)構(gòu)造函數(shù)就開(kāi)始執(zhí)行了
        new app();
    });
})(this, this.jQuery, this._, this.jQuery(document));

上述代碼做的事情:

進(jìn)行了生命周期的定義,把文件的入口移到了一個(gè)構(gòu)造器里面,通過(guò)new這個(gè)構(gòu)造器來(lái)進(jìn)行這個(gè)js程序的入口的初始化。

定義eventMap,定義bindEvent、initOrdinaryEvents_scanEventsMap、_delegate方法。遍歷eventMap,通過(guò)事件委派,將事件綁定在$(documet)上。之前的使用的是onclick或者on方法來(lái)進(jìn)行事件的綁定,維護(hù)的時(shí)候要到各個(gè)地方去找,現(xiàn)在只需要關(guān)注eventMap就很方便,能夠清楚知道事件、選擇器和事件處理函數(shù)名。

給構(gòu)造器綁定了一個(gè)靜態(tài)屬性Eles,那就不需要用$(".paper"),而是用this.pap(initEles方法實(shí)現(xiàn)的)即可,好處是在壓縮的時(shí)候,字符串是不能被壓縮的,而this.pap會(huì)被壓縮,壓縮率會(huì)更高。

代碼優(yōu)化的技巧

if (e.target.id === "titleDrag" || e.target.id == "subtitleDrag") {}

// 改為
if (["titleDrag", "subtitleDrag"].indexOf(e.target.id) > -1) {}

$(".center-box").removeClass("hidden").css({
    width: ui.helper.width(),
    left: parseInt(centerY.css("left")) - Math.floor(ui.helper.width() / 2)
});

// 改為
var width = ui.helper.width();
var left = parseInt(centerY.css("left"), 10);
this.centerBox.removeClass("hidden").css({
    width: width,
    left: left - Math.floor(width / 2)
});

posObj[event.target.id] = {
    id: event.target.id,
    outerHTML: this.delStyle(event.target.outerHTML),
    style: "#" + event.target.id + "{position: absolute;left:" + (ui.offset.left - 260) / mmToPx + "mm;top:" + (ui.offset.top - 40) / mmToPx + "mm;}"
};

// 改為
posObj[id] = {
    id: id,
    outerHTML: this.delStyle(target.outerHTML),
    style: "#" + id + "{" + this._getPositionLT(top, left, mmToPx) + "}"
};

$(target).next().removeClass("hidden");
$(target).next().find(".line-left").css({
    top: 40,
    left: ui.offset.left,
    height: pap.css("height"),
    width: parseInt(pap.css("width")) - ui.offset.left + 260 + "px"
});
$(target).next().find(".line-top").css({
    left: 260,
    top: ui.offset.top,
    width: pap.css("width"),
    height: parseInt(pap.css("height")) - ui.offset.top + 40 + "px"
});

// 改為
this._drawNextLine(nextEle, left, top);

this.centerBox.addClass("hidden");

// 改為
utils.hide(centerBox);

var ul = this.widgetUl;
var ht; 
switch (e.target.id) {
    case "thin":
        ht = "
  • "; ul.append(ht); break; case "middle": ht = "
  • "; ul.append(ht); break; case "thick": ht = "
  • "; ul.append(ht); break; } // 改為 this.widgetUl.append("
  • ");

    var txt = this.txt;
    var cus = this.cus;
    var mmToPx = this.mmToPx;
    var pap = this.pap;
    var target = $(e.target);
    txt.text(target.text());
    switch (e.target.id) {
        case "a4":
            pap.css({
                width: 210 * mmToPx + "px",
                height: 297 * mmToPx + "px"
            });
            cus.addClass("hidden");
            break;
        case "b5":
            pap.css({
                width: 176 * mmToPx + "px",
                height: 250 * mmToPx + "px"
            });
            cus.addClass("hidden");
            break;
        case "16k":
            pap.css({
                width: 184 * mmToPx + "px",
                height: 260 * mmToPx + "px"
            });
            cus.addClass("hidden");
            break;
        case "cus":
            cus.removeClass("hidden");
            break;
    }
    
    // 改為
    var txt = this.txt;
    var cus = this.cus;
    var id = e.target.id;
    var target = $(e.target);
    var setpapCss = {
        "a4": [210, 297],
        "b5": [176, 250],
        "16k": [184, 260]
    };
    txt.text(target.text());
    if (setpapCss[id]) {
        var wh = setpapCss[id];
        this.setPapWH(wh[0], wh[1]);
        utils.hide(cus);
    }
    if (id === "cur") {
        utils.show(cus);
    }

    總結(jié)

    常見(jiàn)的 js 業(yè)務(wù)場(chǎng)景分析以及解決思路:

    選擇器濫用

    把所有的選擇器的屬性掛載構(gòu)造函數(shù)靜態(tài)屬性上,統(tǒng)一進(jìn)行管理,并通過(guò)initEles方法將其掛載在this上。

    事件綁定濫用

    使用eventMap進(jìn)行統(tǒng)一管理。

    生命周期混亂,沒(méi)概念

    app在實(shí)例化的時(shí)候會(huì)往頁(yè)面里加這個(gè)組件,調(diào)用this.destory時(shí)會(huì)解綁所有事件(還可以補(bǔ)充把html刪掉)。

    復(fù)用性和沙盒安全

    模板渲染技巧

    參考artTemplate.js。

    解耦你的業(yè)務(wù) js 代碼,如何在業(yè)務(wù)中使用設(shè)計(jì)模式?

    模塊化和繼承到底怎么用。

    模塊化就是把文件拆分成小文件。

    拆分維度問(wèn)題和作用域傳遞。

    找到utils,拒絕ctrl+c/v。

    常見(jiàn)的一些業(yè)務(wù)優(yōu)化方法總結(jié):

    判斷太多怎么辦。

    參照上述優(yōu)化代碼中的switch...case例子。

    dom操作到底怎么做才是最好的,找到最優(yōu)解。

    建議用沒(méi)有樣式意義的自定義屬性data-*來(lái)作為選擇器,而不是用具有樣式意義的class和id,因?yàn)槿绻幸惶靋ss類(lèi)名變了,那么js也得改變。

    樣式該怎么加。

    jQuery的css方法,或者對(duì)jQuery的css方法的進(jìn)一步封裝。

    增加你的項(xiàng)目可維護(hù)性和代碼可讀性:

    注釋真的好嗎?

    先寫(xiě)偽代碼,所有的方法不考慮它的實(shí)現(xiàn),把它拆成粒度比較細(xì)的顆粒,用方法名來(lái)描述業(yè)務(wù)邏輯,把方法名都寫(xiě)好了之后,互相調(diào)用,最后再添加最細(xì)粒度的方法的實(shí)現(xiàn)。用這種方法來(lái)寫(xiě)的話,不寫(xiě)注釋也可以,因?yàn)榉椒桶褬I(yè)務(wù)邏輯解釋了。

    格式化的問(wèn)題。

    單詞難拼,句子好讀,代碼50行好讀,300行難讀。

    寫(xiě)代碼要說(shuō)人話。

    文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

    轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/95117.html

    相關(guān)文章

    • python

      Python裝飾器為什么難理解? 無(wú)論項(xiàng)目中還是面試都離不開(kāi)裝飾器話題,裝飾器的強(qiáng)大在于它能夠在不修改原有業(yè)務(wù)邏輯的情況下對(duì)代碼進(jìn)行擴(kuò)展,權(quán)限校驗(yàn)、用戶認(rèn)證、日志記錄、性能測(cè)試、事務(wù)處理、緩存等都是裝飾器的絕佳應(yīng)用場(chǎng)景,它能夠最大程度地對(duì)代碼進(jìn)行復(fù)用。 但為什么初學(xué)者對(duì)裝飾器的理解如此困難,我認(rèn)為本質(zhì)上是對(duì)Py… Python 實(shí)現(xiàn)車(chē)牌定位及分割 作者用 Python 實(shí)現(xiàn)車(chē)牌定位及分割的實(shí)踐。 ...

      chenatu 評(píng)論0 收藏0
    • 前端開(kāi)發(fā)負(fù)責(zé)人修煉指北

      摘要:大家好,我叫,江湖人稱(chēng)吃土小叉,目前擔(dān)任公司的前端負(fù)責(zé)人半年多了,一路上摸爬滾打,歷經(jīng)團(tuán)隊(duì)人員變動(dòng),近日頗有感觸,于是結(jié)合自己近半年的前端負(fù)責(zé)人實(shí)踐經(jīng)驗(yàn),權(quán)當(dāng)作一個(gè)學(xué)習(xí)記錄,整理歸納一下小作坊團(tuán)隊(duì)前端負(fù)責(zé)人的修煉要點(diǎn)大部分只是記錄了關(guān)鍵詞, 大家好,我叫XX,江湖人稱(chēng)吃土小2叉,目前擔(dān)任公司的前端負(fù)責(zé)人半年多了,一路上摸爬滾打,歷經(jīng)團(tuán)隊(duì)人員變動(dòng),近日頗有感觸,于是結(jié)合自己近半年的前端負(fù)...

      Drummor 評(píng)論0 收藏0
    • 學(xué)習(xí)實(shí)踐 - 收藏集 - 掘金

      摘要:官網(wǎng)地址聊天機(jī)器人插件開(kāi)發(fā)實(shí)例教程一創(chuàng)建插件在系統(tǒng)技巧使你的更加專(zhuān)業(yè)前端掘金一個(gè)幫你提升技巧的收藏集。我會(huì)簡(jiǎn)單基于的簡(jiǎn)潔視頻播放器組件前端掘金使用和實(shí)現(xiàn)購(gòu)物車(chē)場(chǎng)景前端掘金本文是上篇文章的序章,一直想有機(jī)會(huì)再次實(shí)踐下。 2道面試題:輸入U(xiǎn)RL按回車(chē)&HTTP2 - 掘金通過(guò)幾輪面試,我發(fā)現(xiàn)真正那種問(wèn)答的技術(shù)面,寫(xiě)一堆項(xiàng)目真不如去刷技術(shù)文章作用大,因此刷了一段時(shí)間的博客和掘金,整理下曾經(jīng)被...

      mikyou 評(píng)論0 收藏0
    • Python

      摘要:最近看前端都展開(kāi)了幾場(chǎng)而我大知乎最熱語(yǔ)言還沒(méi)有相關(guān)。有關(guān)書(shū)籍的介紹,大部分截取自是官方介紹。但從開(kāi)始,標(biāo)準(zhǔn)庫(kù)為我們提供了模塊,它提供了和兩個(gè)類(lèi),實(shí)現(xiàn)了對(duì)和的進(jìn)一步抽象,對(duì)編寫(xiě)線程池進(jìn)程池提供了直接的支持。 《流暢的python》閱讀筆記 《流暢的python》是一本適合python進(jìn)階的書(shū), 里面介紹的基本都是高級(jí)的python用法. 對(duì)于初學(xué)python的人來(lái)說(shuō), 基礎(chǔ)大概也就夠用了...

      dailybird 評(píng)論0 收藏0
    • JavaScript 函數(shù)式編程到底是個(gè)啥

      摘要:函數(shù)是一等公民。其實(shí)閉包本身也是函數(shù)式編程的一個(gè)應(yīng)用。劣勢(shì)不能算是嚴(yán)格意義上的函數(shù)式語(yǔ)言,很多函數(shù)式編程的特性并沒(méi)有。 隨著大前端時(shí)代的到來(lái),在產(chǎn)品開(kāi)發(fā)過(guò)程中,前端所占業(yè)務(wù)比重越來(lái)越大、交互越來(lái)越重。傳統(tǒng)的老夫拿起JQuery就是一把梭應(yīng)付當(dāng)下重交互頁(yè)面已經(jīng)十分乏力。于是乎有了Angular,React,Vue這些現(xiàn)代框架。 但隨之而來(lái)的還有大量的新知識(shí)新名詞,如MVC,MVVM,F(xiàn)l...

      denson 評(píng)論0 收藏0

    發(fā)表評(píng)論

    0條評(píng)論

    閱讀需要支付1元查看
    <