1. <nobr id="easjo"><address id="easjo"></address></nobr>

      <track id="easjo"><source id="easjo"></source></track>
      1. 
        

      2. <bdo id="easjo"><optgroup id="easjo"></optgroup></bdo>
      3. <track id="easjo"><source id="easjo"><em id="easjo"></em></source></track><option id="easjo"><span id="easjo"><em id="easjo"></em></span></option>
          貴州做網站公司
          貴州做網站公司~專業!靠譜!
          10年網站模板開發經驗,熟悉國內外開源網站程序,包括DEDECMS,WordPress,ZBlog,Discuz! 等網站程序,可為您提供網站建設,網站克隆,仿站,網頁設計,網站制作,網站推廣優化等服務。我們專注高端營銷型網站,企業官網,集團官網,自適應網站,手機網站,網絡營銷,網站優化,網站服務器環境搭建以及托管運維等。為客戶提供一站式網站解決方案?。?!

          6.Page對象詳解

          來源:互聯網轉載 時間:2024-01-29 08:04:30

          就好像用戶看到的都是由dom表現出來的,所有的業務處理都是在Page對象中處理的。如果業務越簡單,創建的Page對象數量就會越少;如果業務越復雜,那么相對而言Page對象數量就越多(或Page實例對象就會越復雜)。 Page對象主要做以下事情:

          1. 渲染頁面,保證dom元素的合理安排,以及事件的處理;
          2. 數據交互,將數據正確的放在dom元素中,并進行合理的前后端數據交互。

          無論是在哪個時候,這兩點確實是前端開發的重中之重,換一句話說這就是前端核心開發內容。

          為了讓Page對象更加專注于上面所提的兩件事情,將處理業務的細節轉移到復雜services的文件中,讓它成為數據樞紐,安排數據的走向,弄清楚數據到底是渲染到頁面上還是保存起來,從而做進一步的前后端數據交互。另一方面,把復雜的渲染部分,封裝成組件,將渲染邏輯以及數據渲染頁面的邏輯交給組件內部處理,減少Page代碼量,讓業務處理更加清晰。

          我們在Page對dom進行原子性的操作,而不是另外抽出一層作為單獨渲染層。從分離上看似更加合理,然而在日常開發中,瀏覽器對于dom的處理已經夠全面了,大部分是可以通過一句代碼來實現的。對于復雜點的,通過簡單的封裝或者組件的處理就能實現(組件對dom也是直接操作)。在Page對象中處理代碼也不會太多,如果為了封裝而失去修改的方便性,其實是得不償失的,而且不同層之間的交互,會讓代碼更加的難以理解(因為dom也算是一層渲染層,額外加一次就顯得比較多余),這也是為什么堅持使用最原始的html的原因之一。

          通過上面的分析,我們更傾向于把Page對象的主要任務作為數據的樞紐,負責數據的運輸,把數據讓給渲染層顯示,或將數據做處理保存,或將數據進行前后端數據交互等事情, 相當于MVC架構中的Controller部分,html渲染出來的dom層代表著View層,Page對象實際上沒有保存長期數據的習慣,如果需要長期保存的數據,可以把它放在App對象中,或者把它放在services的某個文件中。

          需求

          因為頁面和history有很大的關系,并且當前顯示的頁面必須顯示在瀏覽器端的標簽欄中,秉承著異步按需加載的特點,將頁面的配置項固定設置為 { title: “頁面標題”, url: “頁面url”, js: “頁面的定義js文件”, name: “頁面的名稱” }對于Page對象,我希望能滿足以下情況:

          1. 它具有一般模塊的方法,還應該擁有對渲染層事件綁定等處理;
          2. 擁有傳統的方式,將dom緩存起來,下次使用獲取時加快速度,擁有事件管理能力(不然頁面切換無法解綁dom事件);
          3. 只有它擁有與后端交互的能力,僅有Page對象才擁有與后端交互的所有能力。前后端交互是業務的核心之一。

          這里要特別注意,在異步操作中,有時候頁面切換的時候,回調函數中處理dom的時候,會因為dom已被銷毀而出現錯誤;因此我們對頁面切換會對所有該頁面發起的ajax做中斷處理。在別的異步操作中,要確保異步操作完成后,再做頁面切換工作。

          實現思路

          每個Page對象從加載到銷毀, 定義為一個生命周期,過程如下,用圖表示:

          1. 獲取Page實例對象的js,加載js;
          2. 調用render方法,將html獲取到加載到某個dom中,這里處理的方式是放在fragment中;
          3. 接著調用getDomObj方法,目的就是緩存dom,并且綁定事件;
          4. 將fragment加載到瀏覽器的dom中,展示頁面,如果存在beforeInit方法,先執行beforeInit方法;
          5. 調用init方法,初始化該頁面需要引入的插件;
          6. 日常的業務處理,等待用戶切換頁面;
          7. 首先調用dispose方法,這個方法主要是處理引入的插件的銷毀;
          8. 銷毀,主要是移除dom事件的注冊,移除dom的引用,刪除臨時數據, 與后端ajax交互中斷等。

          我們創建一個Page對象

          function Page(name, title, url) {        BaseProto.call(this); // 繼承自定義事件能力    this.domList = {    }; // 緩存dom    this.eventList = {    }; // 緩存事件和dom的關系    this.parent = null; // 現在指App對象    this.parentDom = null; // 指向Page對象放置的dom    this.template = document.createElement("template");    this.http = new Http(this); // 用于AJAX交互,后續介紹    this.data = {    }; // 放置私有對象}Page.prototype = Object.create(BaseProto.prototype, {        // 實例化的Page對象必須要重寫這兩個方法, 對應的步驟2    render: function (next) {            throw new Error("render方法必須繼承重寫")    },    // 使用attachDom和attachEvent用來緩存dom和緩存事件    getDomObj: function (next) {            throw new Error("getDomObj方法必須繼承重寫")    },    // render方法獲取html后,將html放在dom里面,bk代表初始化后的回調調用,對應步驟2, 3, 4    initialize: function (dom, html, bk) {            this.template.innerHTML = html;        var fragment = this.template.content;        this.getDomObj();        dom.appendChild(fragment);        this._beforeInit(bk);    },    _beforeInit: function (next) {            var that = this;        if (typeof this.beforeInit === "function") {                this.beforeInit(function () {                    that._init.apply(that, arguments); // 可以傳參                if (typeof next === "function") next();            })        }        else {                this._init();            if (typeof next === "function") next();        }    },    // 步驟5,6交給用戶處理    _init: function () {            this._addEventListeners(); // 綁定事件        if (typeof this.init === "function") this.init.apply(this, arguments); // 開始處理業務    },    // 代表銷毀對象,對應步驟7, 8    destroy: function () {           // 清除外部引用       if (typeof this.dispose === "function") this.dispose();       this._removeEventListeners(); // 事件移除       this.eventDispatcher.destroy(); // 自定義事件銷毀       this.eventList.length = 0; // 事件緩存清除       this._removeDom(); // 移除dom       this.template = null;       this.parent = null;       this.data = {    };       this.parentDom = null;       this.http.destroy(); // 銷毀對象,阻止未結束的請求。    },    // 緩存dom    attachDom: function (cssQuery, key) {           this.domList[key] = this.template.content.querySelector(cssQuery);       return this;    },    // 緩存事件    attachEvent: function (key, eventStr, fn, passive, doFn) {            passive = passive || false;         var eventList = this.eventList;         doFn = doFn || fn.bind(this);         // 獲取對應key的dom綁定事件數組描述對象         var eventObj = getEvent(eventList, {     key: key });          if (eventObj) {                 var eventArray = eventObj.eventArray;             // 找到該事件的綁定方法數組             var methodEventObj = getEvent(eventArray, {     method: eventStr });              if (methodEventObj) {                     var fnArray = methodEventObj.fnArray;                 // 是否已經綁定,防止重復                 var obj = getEvent(fnArray, {     backFn: fn, passive: passive });                  if (!obj) fnArray.push({     backFn: fn, passive: passive, doFn: doFn });             } else {                     eventArray.push({     method: eventStr,                     fnArray: [{     backFn: fn, passive: passive, doFn: doFn }]                 })             }         } else {                 eventList.push({                     key: key,                 eventArray: [{                         method: eventStr,                     fnArray: [{     backFn: fn, passive: passive, doFn: doFn }]                 }]             })         }         return this;    },    // 剩下的就是_addEventListeners,_removeEventListeners就是解析eventList的數據格式    // 綁定事件和移除事件, 過程略過});

          下面來實現AJAX實現細節,代碼如下

          function Http(target) {        this.target = target;    this.list = [];}Http.prototype = {        constructor: Http,    // ajax方法    ajax: function (option, bk) {            var list = this.list, target = this.target,            useType = false, commonHeader = Http.commonHeader;        var xhr = new XMLHttpRequest();        list.push(xhr);        if (option.username)            xhr.open(option.method, option.url, option.async,                      option.username, option.password);        else            xhr.open(option.method, option.url, option.async);        var header = option.header || {    };        // 作為公共header        for (var key in commonHeader) {                xhr.setRequestHeader(key, commonHeader[key])        }        // 特殊化header        for (var i in header) {                if (header["Content-Type"] !== "multipart/form-data") {                    xhr.setRequestHeader(i, header[i]);            }        }        // 配置二進制流請求        if ("type" in option) {                xhr.responseType = option.type;            useType = true;        }        xhr.onload = function () {                target.dispatchEvent("xhrload", {     xhr: xhr });            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {                    var index = list.indexOf(xhr);                list.splice(index, 1);                var result = useType ?                     xhr.response || xhr.responseText :                     xhr.responseText;                option.success.call(option.target, result);                if (typeof bk === "function") bk(result);            } else {                    if (typeof option.error === "function") option.error.call(target, xhr);            }            if (typeof option.complete === "function") option.complete.call(target, xhr);            target.dispatchEvent("xhrcomplete", {     xhr: xhr });        };        xhr.onerror = function () {                target.dispatchEvent("xhrerror", {     xhr: xhr });            if (typeof option.error === "function") option.error.call(target, xhr);            if (typeof option.complete === "function") option.complete.call(target, xhr);            target.dispatchEvent("xhrcomplete", {     xhr: xhr });        };        if ("onabort" in option) {                xhr.onabort = option.onabort;        }        var data = null;        // 默認以url-encode        if (option.data) {                if ( header["Content-Type"] == "application/json") data = JSON.stringify(option.data);            else if (header["Content-Type"] == "multipart/form-data") {                    data = new FormData();                for (var key in option.data) {                        data.append(key, option.data[key]);                }            }            else data = serialize(option.data);        }        xhr.send(data);        target.dispatchEvent("xhrstart", {     xhr: xhr });        return xhr;    },    // 銷毀    destroy: function () {            var list = this.list;        for (var i = list.length - 1; i >= 0; i--) {                // 中斷請求,防止切換頁面導致回調函數中操作dom造成錯誤            list[i].abort();            list.splice(i, 1);        }    }};

          接下來在Page的原型對象中加入post,get方法。

          post: function (url, data, fn) {        var obj = createRequest(this, url, data, feeback, option, "POST");    this.http.ajax(obj);},get: function (url, fn) {            var obj = createRequest(this, url, undefined, feeback, option, "GET");    this.http.ajax(obj);},

          公共函數,創建請求參數的統一方式。

          function createRequest(target, url, data, feeback, option, method) {        option = option || {    };    option.header = option.header || {    };    option.header["x-request-with"] = "XMLHttpRequest";    if (!("Content-Type" in option.header)) option.header["Content-Type"] = "application/json";    option.method = method || "GET";    option.success = feeback.bind(target);    if ("onabort" in option) option.onabort = option.onabort.bind(target);    option.target = target;    option.url = url;    option.data = data;    option.async = typeof option.async === "undefined" ? true : option.async;    return option;}

          [案例地址]http://www.renxuan.tech:2005

          總結

          主要對Page對象的用途做了簡要的介紹,以及它的生命周期,并且著重對ajax做了簡要的封裝, 下一章針對Page與history的綜合 應用進行介紹。

          推廣

          底層框架開源地址:https://gitee.com/string-for-100w/string

          157789.html

          標簽:page對象-

          網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...

          在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...

          在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...

          首創輪胎的優點和缺點?首創輪胎,北京首創輪胎旗艦品牌。綜合經濟實力在輪胎行業排名第15位,半鋼子午線輪胎前5名。產品注冊商標為BCT、經綸、盾、奧特佳等。在輪胎行業可以算是(半鋼子午線輪胎)平均水平。優點:環保,剎車距離短,穩定性好。缺點:噪音大,帶水路面操控差。bct輪胎官網?BCT是北京第一輪胎,全稱是北京車輪??梢哉f經綸輪胎是低端輪胎中的佼佼者,尤其是這款輪胎質量非常好。北京輪輪胎以高強度橡...

          主題WB包什么意思?WB是WindowBlinds5的縮寫。WindowBlinds5是一個系統主題改變軟件。不同于常見的XP系統主題,WindowBlinds5WindowBlinds是一款美化Windows系統的特殊應用,尤其是可以改變所有Windows應用窗口,安裝運行非常簡單。WindowBlinds安裝后可以集成到Windows操作系統中。而且這款軟件是微軟唯一授權的第三方系統美化軟件。...

          成都到重慶的火車經過哪些地方?;1.如果從成都坐高鐵到重慶,高鐵經過璧山、永川、大足、榮昌、隆昌、內江、資陽,到達成都。2.景點大概是重慶的區縣,永川,大足,榮昌,永川茶山竹海,樂和樂都,大足石雕,龍水湖,榮昌路孔古鎮。資陽沒什么特別的。隆昌的石牌坊也被稱為牌坊之鄉。3.如果是高鐵,從成都到重慶,要走大成鐵路,金堂,遂寧然后向南轉到重慶。4.如果是普通列車,走成渝鐵路,簡陽,資陽,內江,隆昌,最后...

          TOP
          国产初高中生视频在线观看|亚洲一区中文|久久亚洲欧美国产精品|黄色网站入口免费进人
          1. <nobr id="easjo"><address id="easjo"></address></nobr>

              <track id="easjo"><source id="easjo"></source></track>
              1. 
                

              2. <bdo id="easjo"><optgroup id="easjo"></optgroup></bdo>
              3. <track id="easjo"><source id="easjo"><em id="easjo"></em></source></track><option id="easjo"><span id="easjo"><em id="easjo"></em></span></option>