<address id="ttjl9"></address>

      <noframes id="ttjl9"><address id="ttjl9"><nobr id="ttjl9"></nobr></address>
      <form id="ttjl9"></form>
        <em id="ttjl9"><span id="ttjl9"></span></em>
        <address id="ttjl9"></address>

          <noframes id="ttjl9"><form id="ttjl9"></form>

          首頁

          開發中我們需要遵循的幾個設計原則!

          周周

          出處:https://www.cnblogs.com/pengdai


          一、開發原則
          S:單一職責SRP
          O:開放封閉原則OCP
          L:里氏替換原則LSP
          I:接口隔離法則
          D:依賴倒置原則DIP
          合成/聚合復用原則
          迪米特法則
          在軟件開發中,前人對軟件系統的設計和開發總結了一些原則和模式, 不管用什么語言做開發,都將對我們系統設計和開發提供指導意義。本文主要將總結這些常見的原則和具體闡述意義。
          面向對象的基本原則(solid)是五個,但是在經常被提到的除了這五個之外還有迪米特法則和合成復用原則等,所以在常見的文章中有表示寫六大或七大原則的; 除此之外我還將給出一些其它相關書籍和互聯網上出現的原則;

          二、S單一職責SRP

          Single-Responsibility Principle,一個類,最好只做一件事,只有一個引起它的變化。單一職責原則可以看做是低耦合、高內聚在面向對象原則的引申,將職責定義為引起變化的原因,以提高內聚性減少引起變化的原因。

          1、定義

          一個對象應該只包含單一的職責,并且該職責被完整地封裝在一個類中。(Every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class.),即又定義有且僅有一個原因使類變更。

          2、原則分析

          一個類或者大到模塊,小到方法,承擔的職責越多,它被復用的可能性越小,而且如果一個類承擔的職責過多,就相當于將這些職責耦合在一起,當其中一個職責變化時,可能會影響其他職責的運作。
          類的職責主要包括兩個方面:數據職責和行為職責,數據職責通過其屬性來體現,而行為職責通過其方法來體現。
          單一職責原則是實現高內聚、低耦合的指導方針,在很多代碼重構手法中都能找到它的存在,它是最簡單但又最難運用的原則,需要設計人員發現類的不同職責并將其分離,而發現類的多重職責需要設計人員具有較強的分析設計能力和相關重構經驗。

          3、優點

          降低類的復雜性,類的職責清晰明確。比如數據職責和行為職責清晰明確;
          提高類的可讀性和維護性;
          變更引起的風險減低,變更是必不可少的,如果接口的單一職責做得好,一個接口修改只對相應的類有影響,對其他接口無影響,這對系統的擴展性、維護性都有非常大的幫助。
          注意:單一職責原則提出了一個編寫程序的標準,用“職責”或“變化原因”來衡量接口或類設計得是否合理,但是“職責”和“變化原因”都是沒有具體標準的,一個類到底要負責那些職責?這些職責怎么細化?細化后是否都要有一個接口或類?這些都需從實際的情況考慮。因項目而異,因環境而異。

          4、例子

          SpringMVC中Entity、DAO、Service、Controller、Util等的分離。

          三、O開放封閉原則OCP

          Open - ClosedPrinciple,OCP對擴展開放,對修改關閉(設計模式的核心原則)

          1、定義

          一個軟件實體(如類、模塊和函數)應該對擴展開放,對修改關閉。意思是在一個系統或者模塊中,對于擴展是開放的,對于修改是關閉的。一個 好的系統是在不修改源代碼的情況下,可以擴展你的功能。而實現開閉原則的關鍵就是抽象化。

          2、原則分析

          當軟件實體因需求要變化時, 盡量通過擴展已有軟件實體,可以提供新的行為,以滿足對軟件的新的需求,而不是修改已有的代碼,使變化中的軟件有一定的適應性和靈活性 。已有軟件模塊,特別是最重要的抽象層模塊不能再修改,這使變化中的軟件系統有一定的穩定性和延續性。
          實現開閉原則的關鍵就是抽象化 :在"開-閉"原則中,不允許修改的是抽象的類或者接口,允許擴展的是具體的實現類,抽象類和接口在"開-閉"原則中扮演著極其重要的角色..即要預知可能變化的需求.又預見所有可能已知的擴展..所以在這里"抽象化"是關鍵!
          可變性的封閉原則:找到系統的可變因素,將它封裝起來。這是對"開-閉"原則最好的實現。不要把你的可變因素放在多個類中,或者散落在程序的各個角落。你應該將可變的因素,封套起來..并且切忌不要把所用的可變因素封套在一起。最好的解決辦法是,分塊封套你的可變因素!避免超大類、超長類、超長方法的出現!!給你的程序增加藝術氣息,將程序藝術化是我們的目標!

          3、例子

          設計模式中模板方法模式和觀察者模式都是開閉原則的極好體現。

          四、L里氏替換原則LSP

          Liskov Substitution Principle,LSP:任何基類可以出現的地方,子類也可以出現;這一思想表現為對繼承機制的約束規范,只有子類能夠替換其基類時,才能夠保證系統在運行期內識別子類,這是保證繼承復用的基礎。

          1、定義

          第一種定義方式相對嚴格:如果對每一個類型為S的對象o1,都有類型為T的對象o2,使得以T定義的所有程序P在所有的對象o1都代換成o2時,程序P的行為沒有變化,那么類型S是類型T的子類型。
          第二種更容易理解的定義方式:所有引用基類(父類)的地方必須能透明地使用其子類的對象。即子類能夠必須能夠替換基類能夠從出現的地方。子類也能在基類 的基礎上新增行為。
          里氏代換原則由2008年圖靈獎得主、美國第一位計算機科學女博士、麻省理工學院教授BarbaraLiskov和卡內基.梅隆大學Jeannette Wing教授于1994年提出。其原文如下:Let q(x) be a property provableabout objects x of type T. Then q(y) should be true for objects y of type Swhere S is a subtype of T.

          2、原則分析

          講的是基類和子類的關系,只有這種關系存在時,里氏代換原則才存在。正方形是長方形是理解里氏代換原則的經典例子。
          里氏代換原則可以通俗表述為:在軟件中如果能夠使用基類對象,那么一定能夠使用其子類對象。把基類都替換成它的子類,程序將不會產生任何錯誤和異常,反過來則不成立,如果一個軟件實體使用的是一個子類的話,那么它不一定能夠使用基類。

          里氏代換原則是實現開閉原則的重要方式之一,由于使用基類對象的地方都可以使用子類對象,因此在程序中盡量使用基類類型來對對象進行定義,而在運行時再確定其子類類型,用子類對象來替換父類對象。

          五、I接口隔離法則

          (Interface Segregation Principle,ISL):客戶端不應該依賴那些它不需要的接口。(這個法則與迪米特法則是相通的)

          1、定義

          客戶端不應該依賴那些它不需要的接口。
          另一種定義方法:一旦一個接口太大,則需要將它分割成一些更細小的接口,使用該接口的客戶端僅需知道與之相關的方法即可。
          注意,在該定義中的接口指的是所定義的方法。例如外面調用某個類的public方法。這個方法對外就是接口。

          2、原則分析:

          (1)接口隔離原則是指使用多個專門的接口,而不使用單一的總接口。每一個接口應該承擔一種相對獨立的角色,不多不少,不干不該干的事,該干的事都要干。
          ? 一個接口就只代表一個角色,每個角色都有它特定的一個接口,此時這個原則可以叫做“角色隔離原則”。
          ? 接口僅僅提供客戶端需要的行為,即所需的方法,客戶端不需要的行為則隱藏起來,應當為客戶端提供盡可能小的單獨的接口,而不要提供大的總接口。
          (2)使用接口隔離原則拆分接口時,首先必須滿足單一職責原則,將一組相關的操作定義在一個接口中,且在滿足高內聚的前提下,接口中的方法越少越好。
          (3)可以在進行系統設計時采用定制服務的方式,即為不同的客戶端提供寬窄不同的接口,只提供用戶需要的行為,而隱藏用戶不需要的行為。

          六、D依賴倒置原則DIP

          Dependency-Inversion Principle 要依賴抽象,而不要依賴具體的實現, 具體而言就是高層模塊不依賴于底層模塊,二者共同依賴于抽象。抽象不依賴于具體,具體依賴于抽象。

          1、定義

          高層模塊不應該依賴低層模塊,它們都應該依賴抽象。抽象不應該依賴于細節,細節應該依賴于抽象。簡單的說,依賴倒置原則要求客戶端依賴于抽象耦合。原則表述:
          (1)抽象不應當依賴于細節;細節應當依賴于抽象;
          (2)要針對接口編程,不針對實現編程。

          2、原則分析

          (1)如果說開閉原則是面向對象設計的目標,依賴倒轉原則是到達面向設計"開閉"原則的手段..如果要達到最好的"開閉"原則,就要盡量的遵守依賴倒轉原則. 可以說依賴倒轉原則是對"抽象化"的最好規范! 我個人感覺,依賴倒轉原則也是里氏代換原則的補充..你理解了里氏代換原則,再來理解依賴倒轉原則應該是很容易的。
          (2)依賴倒轉原則的常用實現方式之一是在代碼中使用抽象類,而將具體類放在配置文件中。
          (3)類之間的耦合:零耦合關系,具體耦合關系,抽象耦合關系。依賴倒轉原則要求客戶端依賴于抽象耦合,以抽象方式耦合是依賴倒轉原則的關鍵。

          3、例子1

          理解這個依賴倒置,首先我們需要明白依賴在面向對象設計的概念:
          依賴關系(Dependency):是一種使用關系,特定事物的改變有可能會影響到使用該事物的其他事物,在需要表示一個事物使用另一個事物時使用依賴關系。(假設A類的變化引起了B類的變化,則說名B類依賴于A類。)大多數情況下,依賴關系體現在某個類的方法使用另一個類的對象作為參數。在UML中,依賴關系用帶箭頭的虛線表示,由依賴的一方指向被依賴的一方。
          4、例子2
          某系統提供一個數據轉換模塊,可以將來自不同數據源的數據轉換成多種格式,如可以轉換來自數據庫的數據(DatabaseSource)、也可以轉換來自文本文件的數據(TextSource),轉換后的格式可以是XML文件(XMLTransformer)、也可以是XLS文件(XLSTransformer)等。
          由于需求的變化,該系統可能需要增加新的數據源或者新的文件格式,每增加一個新的類型的數據源或者新的類型的文件格式,客戶類MainClass都需要修改源代碼,以便使用新的類,但違背了開閉原則。現使用依賴倒轉原則對其進行重構。
          當然根據具體的情況,也可以將AbstractSource注入到AbstractStransformer,依賴注入的方式有以下三種:

          [img]https://ss.csdn.net/p?https://mmbiz.qpic.cn/mmbiz_png/ ... rFZQ/640?wx_fmt=png[/img]

          七、合成/聚合復用原則

          (Composite/Aggregate ReusePrinciple ,CARP):要盡量使用對象組合,而不是繼承關系達到軟件復用的目的。

          1、定義

          經常又叫做合成復用原則(Composite ReusePrinciple或CRP),盡量使用對象組合,而不是繼承來達到復用的目的。
          就是在一個新的對象里面使用一些已有的對象,使之成為新對象的一部分;新對象通過向這些對象的委派達到復用已有功能的目的。簡而言之,要盡量使用合成/聚合,盡量不要使用繼承。

          2、原則分析

          (1)在面向對象設計中,可以通過兩種基本方法在不同的環境中復用已有的設計和實現,即通過組合/聚合關系或通過繼承。
          繼承復用:實現簡單,易于擴展。破壞系統的封裝性;從基類繼承而來的實現是靜態的,不可能在運行時發生改變,沒有足夠的靈活性;只能在有限的環境中使用。(“白箱”復用)
          組合/聚合復用:耦合度相對較低,選擇性地調用成員對象的操作;可以在運行時動態進行。(“黑箱”復用)
          (2)組合/聚合可以使系統更加靈活,類與類之間的耦合度降低,一個類的變化對其他類造成的影響相對較少,因此一般首選使用組合/聚合來實現復用;其次才考慮繼承,在使用繼承時,需要嚴格遵循里氏代換原則,有效使用繼承會有助于對問題的理解,降低復雜度,而濫用繼承反而會增加系統構建和維護的難度以及系統的復雜度,因此需要慎重使用繼承復用。
          (3)此原則和里氏代換原則氏相輔相成的,兩者都是具體實現"開-閉"原則的規范。違反這一原則,就無法實現"開-閉"原則,首先我們要明白合成和聚合的概念:
          注意:聚合和組合的區別是什么?
          合成(組合):表示一個整體與部分的關系,指一個依托整體而存在的關系(整體與部分不可以分開);比如眼睛和嘴對于頭來說就是組合關系,沒有了頭就沒有眼睛和嘴,它們是不可分割的。在UML中,組合關系用帶實心菱形的直線表示。
          聚合:聚合是比合成關系的一種更強的依賴關系,也表示整體與部分的關系(整體與部分可以分開);比如螺絲和汽車玩具的關系,螺絲脫離玩具依然可以用在其它設備之上。在UML中,聚合關系用帶空心菱形的直線表示。

          八、迪米特法則

          (Law of Demeter,LoD:系統中的類,盡量不要與其他類互相作用,減少類之間的耦合度。

          1、定義

          又叫最少知識原則(Least Knowledge Principle或簡寫為LKP)幾種形式定義:
          不要和“陌生人”說話。英文定義為:Don't talk to strangers.
          只與你的直接朋友通信。英文定義為:Talk only to your immediate friends.
          每一個軟件單位對其他的單位都只有最少的知識,而且局限于那些與本單位密切相關的軟件單位。
          簡單地說,也就是,一個對象應當對其它對象有盡可能少的了解。一個類應該對自己需要耦合或調用的類知道得最少,你(被耦合或調用的類)的內部是如何復雜都和我沒關系,那是你的事情,我就知道你提供的public方法,我就調用這么多,其他的一概不關心。

          2、法則分析

          朋友類:在迪米特法則中,對于一個對象,其朋友包括以下幾類:
          (1) 當前對象本身(this);
          (2) 以參數形式傳入到當前對象方法中的對象;
          (3) 當前對象的成員對象;
          (4) 如果當前對象的成員對象是一個集合,那么集合中的元素也都是朋友;
          (5) 當前對象所創建的對象。
          任何一個對象,如果滿足上面的條件之一,就是當前對象的“朋友”,否則就是“陌生人”。
          3、狹義法則和廣義法則:
          在狹義的迪米特法則中,如果兩個類之間不必彼此直接通信,那么這兩個類就不應當發生直接的相互作用,如果其中的一個類需要調用另一個類的某一個方法的話,可以通過第三者轉發這個調用。
          狹義的迪米特法則:可以降低類之間的耦合,但是會在系統中增加大量的小方法并散落在系統的各個角落,它可以使一個系統的局部設計簡化,因為每一個局部都不會和遠距離的對象有直接的關聯,但是也會造成系統的不同模塊之間的通信效率降低,使得系統的不同模塊之間不容易協調。
          廣義的迪米特法則:指對對象之間的信息流量、流向以及信息的影響的控制,主要是對信息隱藏的控制。信息的隱藏可以使各個子系統之間脫耦,從而允許它們獨立地被開發、優化、使用和修改,同時可以促進軟件的復用,由于每一個模塊都不依賴于其他模塊而存在,因此每一個模塊都可以獨立地在其他的地方使用。一個系統的規模越大,信息的隱藏就越重要,而信息隱藏的重要性也就越明顯。
          4、迪米特法則的主要用途:在于控制信息的過載。
          在類的劃分上,應當盡量創建松耦合的類,類之間的耦合度越低,就越有利于復用,一個處在松耦合中的類一旦被修改,不會對關聯的類造成太大波及;
          在類的結構設計上,每一個類都應當盡量降低其成員變量和成員函數的訪問權限;
          在類的設計上,只要有可能,一個類型應當設計成不變類;
          在對其他類的引用上,一個對象對其他對象的引用應當降到。

          5、例子

          外觀模式Facade(結構型)
          迪米特法則與設計模式Facade模式、Mediator模式
          系統中的類,盡量不要與其他類互相作用,減少類之間的耦合度,因為在你的系統中,擴展的時候,你可能需要修改這些類,而類與類之間的關系,決定了修改的復雜度,相互作用越多,則修改難度就越大,反之,如果相互作用的越小,則修改起來的難度就越小..例如A類依賴B類,則B類依賴C類,當你在修改A類的時候,你要考慮B類是否會受到影響,而B類的影響是否又會影響到C類. 如果此時C類再依賴D類的話,呵呵,我想這樣的修改有的受了。

          九、Q&A1、面向對象設計其他原則?

          封裝變化;
          少用繼承多用組合;
          針對接口編程、不針對實現編程;
          為交互對象之間的松耦合設計而努力;
          類應該對擴展開發、對修改封閉(開閉OCP原則);
          依賴抽象,不要依賴于具體類(依賴倒置DIP原則);
          密友原則:只和朋友交談(最少知識原則,迪米特法則);
          說明:一個對象應當對其他對象有盡可能少的了解,將方法調用保持在界限內,只調用屬于以下范圍的方法: 該對象本身(本地方法)對象的組件 被當作方法參數傳進來的對象 此方法創建或實例化的任何對象;
          別找我(調用我) 我會找你(調用你)(好萊塢原則);
          一個類只有一個引起它變化的原因(單一職責SRP原則);

          2、你能解釋一下里氏替換原則嗎?

          嚴格定義:如果對每一個類型為S的對象o1,都有類型為T的對象o2,使得以T定義的所有程序P在所有的對象用o1替換o2時,程序P的行為沒有變化,那么類型S是類型T的子類型。
          通俗表述:所有引用基類(父類)的地方必須能透明地使用其子類的對象。也就是說子類可以擴展父類的功能,但不能改變父類原有的功能。它包含以下4層含義:
          • 子類可以實現父類的抽象方法,但不能覆蓋父類的非抽象方法。
          • 子類中可以增加自己特有的方法。
          • 當子類的方法重載父類的方法時,方法的前置條件(即方法的形參)要比父類方法的輸入參數更寬松。
          • 當子類的方法實現父類的抽象方法時,方法的后置條件(即方法的返回值)要比父類更嚴格。

          3、什么情況下會違反迪米特法則?為什么會有這個問題?

          迪米特法則建議“只和朋友說話,不要陌生人說話”,以此來減少類之間的耦合。

          4、給我一個符合開閉原則的設計模式的例子?

          開閉原則要求你的代碼對擴展開放,對修改關閉。這個意思就是說,如果你想增加一個新的功能,你可以很容易的在不改變已測試過的代碼的前提下增加新的代碼。有好幾個設計模式是基于開閉原則的,如策略模式,如果你需要一個新的策略,只需要實現接口,增加配置,不需要改變核心邏輯。一個正在工作的例子是 Collections.sort() 方法,這就是基于策略模式,遵循開閉原則的,你不需為新的對象修改 sort() 方法,你需要做的僅僅是實現你自己的 Comparator 接口。

          5、什么時候使用享元模式(蠅量模式)?

          享元模式通過共享對象來避免創建太多的對象。為了使用享元模式,你需要確保你的對象是不可變的,這樣你才能安全的共享。JDK 中 String 池、Integer 池以及 Long 池都是很好的使用了享元模式的例子。




          談談移動端布局

          周周

          移動端推廣速度快,效果好,越來越多的企業,商家開始重視移動站的建設和移動頁面(h5)的制作。隨著移動頁面的玩法越來越多,對前端技術的要求也會越來越高。

          選擇合適的布局,是寫好移動頁面的第一步。今天我們就來談談移動端的布局問題。
          為什么移動端布局如此混亂?這是由多方的原因造成的。
          1. css這套技術系統本身十分混亂,基本上可以說毫無規律可言,依賴于技術人員的熟練程度而不是邏輯更多一些;
          2.css歷經了多個時代的升級,每一次升級之后,新的技術標準和舊的基本上沒有任何關聯。比如:table布局,div+css布局,flex布局,grid布局等;
          3. 手機終端市場的混亂。當前市場上手機的尺寸五花八門;加上由iphone的retina技術帶來的dpr的混亂;

          關于移動設備一些基本概念的理解。



          一. 物理設備像素。
          思考:為什么手電筒只能發出一種顏色的光,而我們的屏幕能發出這么多種顏色的光?
          因為我們的屏幕是由無數個小的手電筒組成的,每個點可以發不同顏色的光,最后就組成了我們看到的彩色的效果。
          每張圖片都是由色點組成的,每個色點稱為一個像素。一張圖片由30萬個色點組成,這個圖片的像素就是30W。我們常說相機是多少像素,這個像素實際就是在說這款照相機的感器件有多少個,有100W個感光器件的相機就是100W像素的相機,有4000W個感光器件的相機就是4000W像素,以此類推。一臺100W像素的相機拍攝的照片洗成5寸的照片會比洗成6寸清晰一點。
          二. 屏幕分辨率
          屏幕分辨率是屏幕每行的像素點數*每列的像素點數,每個屏幕有自己的分辨率。屏幕分辨率越高,所呈現的色彩越多,清晰度越高。
          結論:
          1. 像素的單位本質上是:個數,100像素你可以理解成你有100個手電筒;
          2. 同樣大小(比如1cm*1cm大小的矩形),里面的像素越多,畫面越清晰;
          三.css像素
          在pc端1css像素相當于1物理設備像素。
          思考:
          我們的手機分辨率是640*1136(iphone 5和iphone 5s的物理設備分辨率),如果我們打開一個純粹pc端的網站會出現什么情況?
          (比如jumei.com,min-width是1090px,在pc端的我的電腦的設備寬度是1280,通過screen.width進行檢測)
          我們會發現網站會縮小到我們可以看到整個網站(www.jubi.com)
          則會發現,有滾動條了,因為禁止縮放了
          四. dpr
          1個css像素占多少物理設備像素
          思考:iphone 5或者iphone 5s一屏幕能看到的極限是多少寬度?
          應該是320(這是默認的可視區的css寬度) * 2 = 640px
          以上,我們學習完了所有關于移動端布局相關的概念,接下來,我們來聊一聊布局的思路。
          假如我們有640px的設計稿,我們如何才能讓用戶全部看到呢?
          思路一:百分比布局
          把尺寸除以2,比如我們量出來的是640px ---> 實際上我們只寫320px;
          如果是iphone 6怎么辦? iphone 6的寬度是375px;
          由于320和375的寬度其實差別不大,我們可以不定寬度,也就是把整體寬度設定為100%,然后其他的全部量出來是多少。
          布局方法
          - 拿到設計師給我們的設計稿之后(推薦640px),把所有量出來的尺寸除以2即可
          - 遇到等分就用百分比
          - 左浮動 + 右浮動(導航部分實現、折扣推薦導航部分) --> 適合于所有的元素寬度固定的
          - 左浮動 + padding擠(見超值折扣推薦內容部分) 本質上元素大小在任何尺寸下面都是一致,改變的其實是元素與元素之間的間距大小 --> 適合一個元素寬度固定,另一個寬度自適應;

          網站示例

          http://m.duba.com/

          http://m.lagou.com/

          百分比布局的缺點
          在大屏幕的手機下顯示效果會變成有些頁面元素寬度被拉的很長,但是高度還是和原來一樣,實際顯示非常的不協調,這就是流式布局的最致命的缺點,往往只有幾個尺寸的手機下看到的效果是令人滿意的,其實很多視覺設計師應該無法接受這種效果,因為他們的設計圖在大屏幕手機下看到的效果相當于是被橫向拉長來一樣。流式布局并不是最理想的實現方式,通過大量的百分比布局,會經常出現許多兼容性的問題,還有就是對設計有很多的限制,因為他們在設計之初就需要考慮流式布局對元素造成的影響,只能設計橫向拉伸的元素布局,設計的時候存在很多局限性。
          思路二:rem布局
          如何理解rem布局?
          思考一個問題,假如我們的設計稿是750px,我們量出來一個盒子的寬度是75px,那么在640px下面,它應該是多少合適呢? 答案是:64
          問題,如果才能保證你寫的css的尺寸只需要寫一次,在不同的屏幕尺寸下面不用改?
          假如我們在750px下面,我們讓html的font-size為75,則這個盒子的寬度是1rem,在640px下面我們讓html的font-size為64,則這個盒子的寬度也是1rem,問題就這樣解決了。
          那么實際開發中,該用什么樣等布局思路?
          我們打開m.jd.com,m.vip.com,會發現,實際上沒有一個網站用了純粹的百分比或者rem布局,經常會發現各種布局思路混在一起,因為沒有一套布局思路能夠通用保證不出問題
          為什么rem不是萬能的?
          比如1px,如果我們在dpr是2的情況下就會變得很粗,我們知道那并不是真正的1像素。
          推薦布局思路——使用由阿里出品的lib-flexible庫。

          網址:https://github.com/amfe/lib-flexible;


          該如何使用呢?
          1. 引入布局用的flexible.js要注意的是不要再寫meta:viewport標簽了,因為flexible.js會自動幫你創建;
          2. 引入base.css;
          3. 把設計師的設計稿拿過來,標注稿基準字體大小 = 標注稿寬度 / 10,如標注稿寬為750,標注稿基準字體大小為75;標注稿寬為640,標注稿基準字體大小為64;
          4. 除了字體大小以外,其他所有的均按rem來,比如你的設計稿是750px的,那么,假如你量出來的是75px,則是1rem;
          字體除外,要根據不同的dpr設置不同的大小,比如如果是750的設計稿,那么字體假如是24px,則在dpr為1的情況下是16px,dpr2的情況下是24px,dpr3的情況下是32px(這塊涉及到字體專業知識,總結一句話就是沒有人會考慮用奇數字體,https://www.zhihu.com/question/20440679,所以不能讓工具幫我們自動算,得寫死。
          以上是我個人關于移動端布局的一些總結。如有不妥的地方,還請指正。
          最后附上關于移動端常見問題當網址:



          js json的格式、存儲與發送

          周周

          1.Json的格式

          其實json就是對象。源生的js代碼并沒有類的概念。對象救就是object。對象有自己的屬性,也可以有自己的方法。json是一種輕量級的存儲和交換信息的語言。他有自己的格式。

          較為簡單的json。里面只有簡單的對象,key+value的形式:

          • var CellInfo = {


          •                 "CellId":         document.getElementById("CellId").value,


          •                 "UEAmount":         document.getElementById("UE value").innerText,


          •                 "BearAddDel":         document.getElementById("bearvalue").innerText,


          •                 "UEAttachDe":         document.getElementById("attachvalue").innerText,


          •                 "TotalDLTP":         document.getElementById("dlvalue").innerText,

          •               "TotalULTP":         document.getElementById("ulvalue").innerText,


          •                 };



          每個元素之間用逗號隔開。調用每個key的值可用語句。例如:CellInfo.UEAmunt,就可取出其中的值。

          較為復雜的json。里面包含了對象。


          • var UEGroup1 = {



          •                 "UEAmount": ua[1],



          •                 "DBR1": {



          •                         "DLPackageSize": DS[1],



          •                         "ULPackageSize": US[1],



          •                         "DLTP": DP[1],



          •                         "ULTP": UP[1],



          •                         "QCI": QCI[0]



          •                 },



          •                 "DBR2": {



          •                         "DLPackageSize": DS[2],



          •                         "ULPackageSize": US[2],



          •                         "DLTP": DP[2],



          •                         "ULTP": UP[2],



          •                         "QCI": QCI[1]



          •                 },



          •                 "DBR3": {



          •                         "DLPackageSize": DS[3],



          •                         "ULPackageSize": US[3],



          •                         "DLTP": DP[3],



          •                         "ULTP": UP[3],



          •                         "QCI": QCI[2]



          •                 }



          •         };




          例如這個UEGroup1,里面的元素不僅有簡單的key+value,還包含了三個對象。對象里的元素用{}括起來,彼此之間用逗號隔開。想具體訪問某個元素的值也是通過逐層key,例如:UEGrooup1.DBR1.DLPackageSize

          動態的往json只增加元素,增加對象。

          前面說的幾個都是靜態的,提前寫好的。那如果臨時想加一個元素,例如在Cellinfo這個json中相加一個number的元素:

          CellInfo.number=10;

          對于往json中添加對象。例如我們想把Cellinfo和UEGroup1這兩個object作為兩個元素加入到另外一個大的json中:

          • var PETInfo = {};//聲明了一個空的對象



          • var CellInfo = {



          •                 "CellId":         document.getElementById("CellId").value,



          •                 "UEAmount":         document.getElementById("UE value").innerText,



          •                 "BearAddDel":         document.getElementById("bearvalue").innerText,



          •                 "UEAttachDe":         document.getElementById("attachvalue").innerText,



          •                 "TotalDLTP":         document.getElementById("dlvalue").innerText,



          •                 "TotalULTP":         document.getElementById("ulvalue").innerText,



          •                 };



          • str_CellInfo = JSON.stringify(CellInfo);//將CellInfo轉為字符串對象



          • PETInfo.CellInfo=str_CellInfo;//在PETInfo中添加名為Cellinfo的屬性,并賦值


          2.json的發送

          json寫好后,發送給后臺。至于后臺怎么處理數據我們不關心。發送json的函數如下:

          • function post(path, params, method) {



          •         method = method || "post";



          •         var form = document.createElement("form");



          •         form.setAttribute("method", method);



          •         form.setAttribute("action", path);





          •         for (var key in params) {



          •                 if (params.hasOwnProperty(key)) {



          •                         var hiddenField = document.createElement("input");



          •                         hiddenField.setAttribute("type", "hidden");



          •                         hiddenField.setAttribute("name", key);



          •                         hiddenField.setAttribute("value", params[key]);



          •                         form.appendChild(hiddenField);



          •                 }



          •         }



          •         document.body.appendChild(form);



          •         form.submit();



          • }

            參數分別是后臺的地址,變量,方法。變量就是我們自己寫好的json,方法默認為post。例如我們想發剛剛的PETInfo

            $.post('http://10.140.160.64:3012/users/ueinfo', PETInfo);

            數據的發送、并獲取結果的實例:

            需求描述:用戶填寫一系列的輸入框,前端獲取數據,封裝成json并發送給服務器,服務器會返回一個返回值,表示狀態。前端需要展示這個內容提示客戶。

            • function sendBook(){



            •         var Book={



            •                 "openstackIP":document.getElementById("openstackIP").value,



            •                 "RAPName":document.getElementById("RAPName").value,



            •                 "RAPVer":document.getElementById("ver").value,



            •                 "OAMIP":document.getElementById("OAMIP").value



            •         };//json封裝用戶輸入的數據



            •         $.post('http://10.140.160.64:3012/servers/env/book', Book)//調用post傳輸數據



            •         .done((resp) => {//傳輸后獲取服務器的返回值



            •         alert(resp);//展示返回值



            •        // window.location.href = 'Environment-List.html';//選擇性界面跳轉



            •     });



            • }

            3.json在本地的存儲

            存儲數據有很多方法。這里我用的是localStorage。localStorage與cookie的區別如下:

            ① cookie在瀏覽器與服務器之間來回傳遞。
            sessionStorage和localStorage不會把數據發給服務器,僅在本地保存

            ②數據有效期不同:
            cookie只在設置的cookie過期時間之前一直有效,即使窗口或瀏覽器關閉。
            sessionStorage:僅在當前瀏覽器窗口關閉前有效。
            localStorage  始終有效,長期保存。

            ③cookie數據還有路徑的概念,可以限制cookie只屬于某個路徑下。
            存儲大小也不同,cookie數據不能超過4k,sessionStorage和localStorage 雖然也有存儲大小的限制,但比cookie大得多,可以達到5M或更大。

            ④ 作用域不用
            sessionStorage不在不同的瀏覽器窗口中共享;
            localStorage在所有同源窗口中都是共享的;
            cookie也是在所有同源窗口中都是共享的;

            WebStorage 支持事件通知機制,可以將數據更新的通知發送給監聽者。Web Storage 的 api 接口使用更方便。

            用localstage存儲json的實例:

            • str_PETInfo=JSON.stringify(PETInfo);//將json轉為字符串對象



            • window.localStorage.setItem("PET",str_PETInfo);//存入本地,該json的key為PET


            將json取出來:



            • var PET=JSON.parse(window.localStorage.getItem("PET"));//將字符串轉化為json



            • var CellInfo=JSON.parse(PET.CellInfo);//json中的Cellinfo對象轉化為json



          手機端頁面常見的問題

          周周

          1.解決頁面使用overflow: scroll在iOS上滑動卡頓的問題?



          首先你可能會給頁面的html和body增加了height: 100%, 然后就可能造成IOS上頁面滑動的卡頓問題。解決方案是:



          (1) 看是否能把body和html的height: 100%去除掉。

          (2) 在滾動的容器中增加:-webkit-overflow-scrolling: touch或者給body增加:body {overflow-x: hidden}。



          2.ios頁面橡皮彈回效果遮擋頁面選項卡?



          (1) 有時body和html的height: 100%去除掉問題可能就沒有了。

          (2) 到達臨界值的時候在阻止事件默認行為

          var startY,endY;
          //記錄手指觸摸的起點坐標
          $('body').on('touchstart',function (e) {
               startY = e.touches[0].pageY;
          });
          $('body').on('touchmove',function (e) {
               endY = e.touches[0].pageY;  //記錄手指觸摸的移動中的坐標
               //手指下滑,頁面到達頂端不能繼續下滑
               if(endY>startY&& $(window).scrollTop()<=0){
                   e.preventDefault();
               }
             //手指上滑,頁面到達底部能繼續上滑
               if(endY<startY&& $(window).scrollTop()+ 
                   $(window).height()>=$('body')[0].scrollHeight){
                   e.preventDefault();
               }
          })
          有時也會碰見彈窗出來后兩個層的橡皮筋效果出現問題,我們可以在彈出彈出時給底層頁面加上一個類名,類名禁止頁面滑動這樣下層的橡皮筋效果就會被禁止,就不會影響彈窗層。 3.IOS機型margin屬性無效問題? (1) 設置html body的高度為百分比時,margin-bottom在safari里失效 (2) 直接padding代替margin 4.Ios綁定點擊事件不執行?  (1)添加樣式cursor :pointer。點擊后消除背景閃一下的css:-webkit-tap-highlight-color:transparent;  5.Ios鍵盤換行變為搜索? 首先,input 要放在 form里面。 這時 "換行" 已經變成 “前往”。 如果想變成 “搜索”,input 設置 type="search"。 6.Jq對a標簽點擊事件不生效? 出現這種情況的原因不明,有的朋友解釋:我們平時都是點擊的A標簽中的文字了。 所以要想用JS模擬點擊A標簽事件,就得先往A標簽中的文字添加能被JS捕獲的元素,然后再用JS模擬點擊該元素即可。但是我覺得不合理,雖然找不到原因但是解決辦法還是有的。 (1)document.getElementById("abc ").click(); (2)$("#abc ")[0].click(); 7.有時因為服務器或者別的原因導致頁面上的圖片沒有找到? 這是我們想需要用一個本地的圖片代替沒有找的的圖片
          <script type="text/javascript"> 
          function nofind(){ 
          var img=event.srcElement; 
          img.src="images/logoError.png"; 
          img.onerror=null; 控制不要一直跳動 
          } 
          </script> 
          <img src="images/logo.png" />
          8.transform屬性影響position:fixed?

          (1)規范中有規定:如果元素的transform值不為none,則該元素會生成包含塊和層疊上下文。CSS Transforms Module Level 1不只在手機上,電腦上也一樣。除了fixed元素會受影響之外,z-index(層疊上下文)值也會受影響。絕對定位元素等和包含塊有關的屬性都會受到影響。當然如果transform元素的display值為inline時又會有所不同。最簡單的解決方法就是transform元素內部不能有absolute、fixed元素.

          9.ios對position: fixed不太友好,有時我們需要加點處理?

          在安卓上面,點擊頁面底部的輸入框,軟鍵盤彈出,頁面移動上移。
          而ios上面,點擊頁面底部輸入框,軟鍵盤彈出,輸入框看不到了。。。查資料說什么的都有,iscroll,jquery-moblie,absolute,fixe,static都非常復雜,要改很多。。。
          讓他彈出時讓滾動條在部
          var u = navigator.userAgent, app = navigator.appVersion;
          var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios終端
          if (isiOS) {
              $('textarea').focus(function () {
                  window.setTimeout('scrollBottom()', 500);
              });
          }
          function scrollBottom() {
              window.scrollTo(0, $('body').height());
          }
          10.jq validate插件驗證問題?

          (1)所以的input必須有name不然會出錯

          11.有時手機會出現斷網的情況,我沒可能會對斷網的情況做一些處理?

          (1)navigator.onLine可判斷是否是脫機狀態.

          12.判斷對象的長度?

          (1)用Object.keys,Object.keys方法返回的是一個數組,數組里面裝的是對象的屬性
          var person = {
              "name" : "zhangshan",
              "sex" : "man",
              "age" : "50",
              "height" : "180",
              "phone" : "1xxxxxxxxxx",
              "email" : "xxxxxxxxx@xxx.com"
          };
          var arr = Object.keys(person);
          console.log(arr.length);
          (2)Object.getOwnPropertyNames(obj).length

          13.上一題我們用到了Object.keys與Object.getOwnPropertyNames他們的區別?

          Object.keys定義:返回一個對象可枚舉屬性的字符串數組;
          Object.getOwnPropertyNames定義:返回一個對象可枚舉、不可枚舉屬性的名稱;
          屬性的可枚舉性、不可枚舉性:定義:可枚舉屬性是指那些內部 “可枚舉” 標志設置為 true 的屬性,對于通過直接的賦值和屬性初始化的屬性,該標識值默認為即為 true,對于通過 Object.defineProperty 等定義的屬性,該標識值默認為 false。
          var obj = { "prop1": "v1" };
          Object.defineProperty(obj, "prop2", { value: "v2", enumerable: false });
          console.log(Object.keys(obj).length);           //output:1
          console.log(Object.getOwnPropertyNames(obj).length);    //output:2
          console.log(Object.keys(obj));           //output:Array[1] => [0: "prop1"]
          console.log(Object.getOwnPropertyNames(obj));    //output:Array[2] => [0: "prop1", 1: "prop2"]

          綜合實例


          var obj = { "prop1": "v1" };
          Object.defineProperty(obj, "prop2", { value: "v2", enumerable: false});
          console.log(obj.hasOwnProperty("prop1")); //output: true
          console.log(obj.hasOwnProperty("prop2")); //output: true
          console.log(obj.propertyIsEnumerable("prop1")); //output: true
          console.log(obj.propertyIsEnumerable("prop2")); //output: false
          console.log('prop1' in obj);    //output: true
          console.log('prop2' in obj);    //output: true
          for (var item in obj) {
              console.log(item);
          }
          //output:prop1
          for (var item in Object.getOwnPropertyNames(obj)) {
              console.log(Object.getOwnPropertyNames(obj)[item]);
          }
          //ouput:[prop1,prop2]

          14.移動開發不同手機彈出數字鍵盤問題?



          (1)type="tel"

          iOS和Android的鍵盤表現都差不多

          (2)type="number"

          優點是Android下實現的一個真正的數字鍵盤

          缺點一:iOS下不是九宮格鍵盤,輸入不方便

          缺點二:舊版Android(包括微信所用的X5內核)在輸入框后面會有超級雞肋的小尾巴,好在Android 4.4.4以后給去掉了。

          不過對于缺點二,我們可以用webkit私有的偽元素給fix掉:


          input[type=number]::-webkit-inner-spin-button,  
          input[type=number]::-webkit-outer-spin-button { 
                  -webkit-appearance: none; 
                  appearance: none; 
                  margin: 0; 
          }

          (3)pattern屬性



          pattern用于驗證表單輸入的內容,通常HTML5的type屬性,比如email、tel、number、data類、url等,已經自帶了簡單的數據格式驗證功能了,加上pattern后,前端部分的驗證更加簡單了。

          顯而易見,pattern的屬性值要用正則表達式。

          實例 簡單的數字驗證

          數字的驗證有兩個:

          <input type="number" pattern="d"> 

          <input type="number" pattern="[0-9]*">



          15.input[number]類型輸入非數字字符



          js獲取的值是空;比如-12,+123等



          16.Javascript:history.go()和history.back()的用法與區別?




          簡單的說就是:go(-1):返回上一頁,原頁面表單中的內容會丟失;back():返回上一頁,原頁表表單中的內容會保留。history.go(-1):后退+刷新history.back():后退

          之所以注意到這個區別,是因為不同的瀏覽器后退行為也是有區別的,而區別就跟javascript:history.go()和history.back()的區別類似。

          Chrome和ff瀏覽器后退頁面,會刷新后退的頁面,若有數據請求也會提交數據申請。類似于history.go(-1);

          而safari(包括桌面版和ipad版)的后退按鈕則不會刷新頁面,也不會提交數據申請。類似于javascript:history.back();



          17.Meta基礎知識:



          <meta name="viewport"content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />

          // width    設置viewport寬度,為一個正整數,或字符串‘device-width’

          // height   設置viewport高度,一般設置了寬度,會自動解析出高度,可以不用設置

          // initial-scale    默認縮放比例,為一個數字,可以帶小數

          // minimum-scale    允許用戶最小縮放比例,為一個數字,可以帶小數

          // maximum-scale    允許用戶最大縮放比例,為一個數字,可以帶小數

          // user-scalable    是否允許手動縮放 

          空白頁基本meta標簽

          <!-- 設置縮放 -->

          <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, minimal-ui" />

          <!-- 可隱藏地址欄,僅針對IOS的Safari(注:IOS7.0版本以后,safari上已看不到效果) -->

          <meta name="apple-mobile-web-app-capable" content="yes" />

          <!-- 僅針對IOS的Safari頂端狀態條的樣式(可選default/black/black-translucent ) -->

          <meta name="apple-mobile-web-app-status-bar-style" content="black" />

          <!-- IOS中禁用將數字識別為電話號碼/忽略Android平臺中對郵箱地址的識別 -->

          <meta name="format-detection"content="telephone=no, email=no" />

          其他meta標簽

          <!-- 啟用360瀏覽器的極速模式(webkit) -->

          <meta name="renderer" content="webkit">

          <!-- 避免IE使用兼容模式 -->

          <meta http-equiv="X-UA-Compatible" content="IE=edge">

          <!-- 針對手持設備優化,主要是針對一些老的不識別viewport的瀏覽器,比如黑莓 -->

          <meta name="HandheldFriendly" content="true">

          <!-- 微軟的老式瀏覽器 -->

          <meta name="MobileOptimized" content="320">

          <!-- uc強制豎屏 -->

          <meta name="screen-orientation" content="portrait">

          <!-- QQ強制豎屏 -->

          <meta name="x5-orientation" content="portrait">

          <!-- UC強制全屏 -->

          <meta name="full-screen" content="yes">

          <!-- QQ強制全屏 -->

          <meta name="x5-fullscreen" content="true">

          <!-- UC應用模式 -->

          <meta name="browsermode" content="application">

          <!-- QQ應用模式 -->

          <meta name="x5-page-mode" content="app">

          <!-- windows phone 點擊無高光 -->

          <meta name="msapplication-tap-highlight" content="no">



          18.移動端如何定義字體font-family?



          @ --------------------------------------中文字體的英文名稱

          @ 宋體 SimSun

          @ 黑體 SimHei

          @ 微信雅黑 Microsoft Yahei

          @ 微軟正黑體 Microsoft JhengHei

          @ 新宋體 NSimSun

          @ 新細明體 MingLiU

          @ 細明體 MingLiU

          @ 標楷體 DFKai-SB

          @ 仿宋 FangSong

          @ 楷體 KaiTi

          @ 仿宋_GB2312 FangSong_GB2312

          @ 楷體_GB2312 KaiTi_GB2312 

          @

          @ 說明:中文字體多數使用宋體、雅黑,英文用Helvetica



          body { font-family: Microsoft Yahei,SimSun,Helvetica; }



          19.打電話發短信寫郵件怎么實現?


          // 一、打電話
          <a href="tel:0755-10086">打電話給:0755-10086</a>
          //  二、發短信,winphone系統無效
          <a href="sms:10086">發短信給: 10086</a>
          // 三、寫郵件
          <a href="mailto:863139978@qq.com">點擊我發郵件</a>
          //2.收件地址后添加?cc=開頭,可添加抄送地址(Android存在兼容問題)
          <a href="mailto:863139978@qq.com?cc=zhangqian0406@yeah.net">點擊我發郵件</a>
          //3.跟著抄送地址后,寫上&bcc=,可添加密件抄送地址(Android存在兼容問題)
          <a href="mailto:863139978@qq.com?cc=zhangqian0406@yeah.net&bcc=384900096@qq.com">點擊我發郵件</a>
          //4.包含多個收件人、抄送、密件抄送人,用分號(;)隔開多個郵件人的地址
          <a href="mailto:863139978@qq.com;[url=mailto:384900096@qq.com]384900096@qq.com[/url]">點擊我發郵件</a>
          //5.包含主題,用?subject=
          <a href="mailto:863139978@qq.com?subject=郵件主題">點擊我發郵件</a>
          //6.包含內容,用?body=;如內容包含文本,使用%0A給文本換行 
          <a href="mailto:863139978@qq.com?body=郵件主題內容%0A騰訊誠信%0A期待您的到來">點擊我發郵件</a>
          //7.內容包含鏈接,含http(s)://等的文本自動轉化為鏈接
          <a href="mailto:863139978@qq.com?body=http://www.baidu.com">點擊我發郵件</a>
          //8.內容包含圖片(PC不支持)
          <a href="mailto:863139978@qq.com?body=<img src='images/1.jpg' />">點擊我發郵件</a>
          //9.完整示例
          <a href="mailto:863139978@qq.com;[url=mailto:384900096@qq.com]384900096@qq.com[/url]?cc=zhangqian0406@yeah.net&bcc=993233461@qq.com&subject=[郵件主題]&body=騰訊誠邀您參與%0A%0A[url=http://www.baidu.com]http://www.baidu.com[/url]%0A%0A<img src='images/1.jpg' />">點擊我發郵件</a>
          20.移動端touch事件(區分webkit和winphone)?

          // 以下支持webkit
          touchstart——當手指觸碰屏幕時候發生。不管當前有多少只手指
          touchmove——當手指在屏幕上滑動時連續觸發。通常我們再滑屏頁面,會調用event的preventDefault()可以阻止默認情況的發生:阻止頁面滾動
          touchend——當手指離開屏幕時觸發
          touchcancel——系統停止跟蹤觸摸時候會觸發。例如在觸摸過程中突然頁面alert()一個提示框,此時會觸發該事件,這個事件比較少用

          //TouchEvent說明:
          touches:屏幕上所有手指的信息
          targetTouches:手指在目標區域的手指信息
          changedTouches:最近一次觸發該事件的手指信息
          touchend時,touches與targetTouches信息會被刪除,changedTouches保存的最后一次的信息,最好用于計算手指信息

          //參數信息(changedTouches[0])
          clientX、clientY在顯示區的坐標
          target:當前元素

          //事件響應順序
          ontouchstart > ontouchmove > ontouchend > onclick


          前端工程師必備實用網站

          周周

          素材類網站


          千庫網,一個免費下載圖片素材的網站:http://588ku.com/ 
          千庫網.jpg.png


          Unsplash是一個分享免費高質量照片的網站,照片分辨率都挺大,而且都是真實的攝影師作品,圖片多是風景和靜物:https://unsplash.com/ 

          Unsplash.jpg.pngUnsplash2.jpg.png

          插件類網站

          jq22,分享jQuery插件和提供各種jQuery的詳細使用方法,在線預覽,jQuery插件下載及教程http://www.jq22.com/

          jq22.jpg.png


          http://www.htmleaf.com/ 這個網站與上一個網站類似,也提供了大量的jQuery插件。

                          htmleaf.jpg.png

          layui,這是一個強大的模塊化前端框架http://www.layui.com/

                       layui1.jpg.png

          layui2.jpg.png

          H-ui,端框架,一個輕量級前端框架,簡單免費,兼容性好,服務中國網站:http://www.h-ui.net/index.shtml

          H-ui.jpg.png 

          字體類網站

          有字庫,一個免下載字體,直接在線引用字體的網站http://www.youziku.com/onlinefont/index

          有字庫.jpg.png



          PS字體庫,包含了幾乎所有類型的字體,下載好安裝,PS中就可以使用了:http://www.psjia.com/pssc/fontxz/list_18_3.html


                         PS字體庫.png

          圖標類網站

          iconfont,這是阿里巴巴旗下的圖標庫網站,直接搜索關鍵詞就可以找到大批的圖標。下載圖標的時候我們還可以選擇顏色、大小、格式,根據自己的需要下載就好了:http://www.iconfont.cn/plus

                             iconfont.jpg.png

          easyicon,這也是一個非常有名的圖標庫,與上面那個不同的是,這里的圖標不是單一顏色的,而是設計好的顏色。下載圖標也很簡單,直接點擊對應圖標上面的格式就可以下載:http://www.easyicon.net/iconsearch/ios/

                            easyicon.jpg.png

          奧森圖標(Font Awesome),提供豐富的矢量字體圖標—通過CSS可以任意控制所有圖標的大小 ,顏色,陰影:http://www.thinkcmf.com/font/search.html

                          奧森圖標.jpg.png

                           奧森圖標1.jpg.png

          配色類網站

          http://colorhunt.co這個網站給我們提供了很多的配色方案,我們直接使用就OK了。

          使用方法也很簡單,鼠標移動到對應的顏色上,我們就可以看到顏色的十六進制碼,復制這個顏色到工具里就可以使用了。

                          colorhunt.jpg.png

          https://webgradients.com/180種漸變方案供你選擇,還可以直接復制CSS樣式應用到網頁中。

                        webgradients.jpg.png

          adobe這個是Adobe公司出的,他提供了多種配色方案。我們點擊圓盤中間的點,就可以調整出我們想要的配色方案:https://color.adobe.com/zh/create/color-wheel

                          Adobe.jpg.png

          http://www.colorhunter.com/,這是一個提取現有圖片配色方案的工具。我們上傳一張圖片,它就會幫我們把圖片的配色提取出來供我們使用。

                          colorhunt.jpg.png

          bootcss,這個網站是為WEB設計,開發中經常用到的安全色。網站內列出了顏色的十六進制碼和RGB碼,復制粘貼就可以了:http://www.bootcss.com/p/websafecolors/

                         bootcss..jpg.png

          sioe,這是一個在線RGB和十六進制顏色碼轉換工具。在對應的位置填入十六進制代碼,點擊轉換,我們就可以獲取到RGB顏色的代碼了http://www.sioe.cn/yingyong/yanse-rgb-16/

                        sioe.jpg.png




          由‘==’和‘===’引出的js的隱式轉換問題

          周周

          ‘==’和‘===’都是Javascript中的比較運算符,都是比較運算符兩邊是否相等。對于‘==’和‘===’的區別,大家也都知道:

            ‘==’僅僅是比較運算符兩邊的數值是否相等,如果數值相等則返回true;‘===’不僅會判斷運算符兩邊的數值是否相等,并且還會判斷兩邊的類型是否相等,只有數值和類型都相等才會返回true。雖然知道以上的判斷依據已經能解決絕大數此類問題,但是如果往其中深究來說,會有同學問:在比較的時候‘===’先判斷類型,如果類型不同就直接返回false,這個沒什么問題。但是如果是‘==’比較兩個不同類型的數據時,具體是怎么進行計算判斷的呢?

           既然是不同類型進行比較,肯定最終參與比較的結果必須是同一個類型的,因此JS會存在一個隱式轉換的問題,并且很多JS的隱式轉換很難通過console.log()等方法直觀的觀察到,因此很多初學者會對JS的隱式轉換感到疑惑。

           首先讓我們回憶一下,咱們的JS中一共有哪些數據類型?

                 六大數據類型
                 基本數據類型(簡單數據類型)
                 number 數值型(NaN)
                 string 字符串
                 boolean 布爾型
                 undefined 未定義
                 null 空引用
                 引用數據類型(復雜數據類型)
                 object

                 JS基礎中,我們學習到咱們的JS中一共有六種數據類型,分為基本數據類型(簡單數據類型)和引用數據類型(復雜數據類型),不同類型的值進行比較的時候,存在隱式轉換的問題,咱們通過‘==’來驗證一下JS隱式轉換的情況。

                 1.我們首先來看看下列的語句計算結果:

          console.log(NaN==true);//false
          console.log(NaN==false);//false
          console.log(NaN==0);//false
          console.log(NaN==1);//false
          console.log(NaN==NaN);//false

                 由上面的例子可以看出,NaN屬于Number數據類型中一個特殊情況,如果‘==’兩邊同為Number數據類型的數字,很直觀的可以看出值是否相同一眼就可以看出結果,但是作為Number類型的特殊情況,NaN在進行比較的時候,也會有特殊的結果:如果 x 或 y 中有一個為 NaN,則返回 false;

                 2.我們繼續看看下列的語句計算結果:

          console.log(null == undefined); //true(特殊情況)---------------------------------
          console.log(null == ''); //false
          console.log(undefined == ''); //false

                在上述例子中,引出了一個null,null是一個簡單數據類型,它的意義就是一個空應用,但是你如果通過console.log(typeof null) 來打印結果的時候卻發現,結果竟然是object?此時你可能會懷疑人生,然后瘋狂的翻閱之前學習的資料,因為object明明是一個復雜數據類型,怎么會在判斷null這個簡單數據類型的類型時打印出來呢?其實,這個問題屬于一個歷史問題。咱們學習的JS在發展過程中是通過ECMAScript來確定規范的,每年都會有新的規定和規范提出,在JS的發展過程中,null一開始的作用就是用來指向一個空地址,讓開發者在創建數據的時候,先用null賦值給還未給值的對象用于標準初始化。但是其實咱們開發過程中很少用到,但是這個仍作為規范留了下來。又因為typeof是根據數據的前幾位判斷數據類型的,null相當于空指針,前幾位是地址的格式,所以判斷結果就為object。又因為undefined值是派生自null值的,因此ECMA-262規定對他們的相等測試要返回true。所以這一情況判斷的條件為:如果 x 與 y 皆為 null 或 undefined 中的一種類型,則返回 true(null == undefined // true);否則返回 false(null == 0 // false);

                 3.請看下列例子:

          console.log(true == '123'); //false
          console.log(true == '1'); //true
          console.log(false == '0'); //true
           
          console.log(true == !0); //true
           
          console.log([] == []); //false
          console.log([] == ![]); //true 比較地址 ------------------------------------------------
          var a = c = [];
          var b = [];
          console.log(a == b); //false
          console.log(a == !b); //true
          console.log(a == c); //true
           
          console.log(Boolean([]) == true); //true
          console.log(Number([]) == 0); //true
          console.log(Number(false) == 0); //true

                 其實比較的邏輯為:如果 x,y 類型不一致,且 x,y 為 String、Number、Boolean 中的某一類型,則將 x,y 使用 Number 函數轉化為 Number 類型再進行比較;

                使用Number函數可以將其他的數據類型轉變為Number類型,這一同為Number類型的數據,對比起來就會變得十分簡單。值得注意的是在上述的例子中,兩個空數組進行比較,結果返回的結果仍然為false,這個是怎么回事呢?其實這個很好理解,因為數組也是對象的一種,是復雜數據類型,所以用變量儲存對象時儲存的其實是地址。對象的內容相同,但是儲存在堆區的位置不同,所以地址也是不同的,所以在判斷的時候返回的是false。

                其實在JS中還有很多的隱式轉換情況,以上只是針對于‘==’的隱式轉換情況,對于這些問題,在實際開發過程中,需要作為開發者不斷的學習和積累,這也是咱們作為開發者的一個要求之一。

          jquery原理的簡單分析

          周周

                 jquery是一個輕量級的JS框架,這點相信大部分人都聽過,而jquery之所以有這樣一個稱呼,就是因為它悄悄披了一件外衣,將自己給隱藏了起來。

                /以下截取自jquery源碼片段
                (function( window, undefined ) {
                /*    源碼內容    */
                 })( window );

                上面這一小段代碼來自于1.9.0當中jquery的源碼,它是一個無污染的JS插件的標準寫法,專業名詞叫閉包??梢园阉唵蔚目醋鍪且粋€函數,與普通函數不同的是,這個函數沒有名字,而且會立即執行,就像下面這樣,會直接彈出字符串。

                (function( window, undefined ) {
                   alert("Hello World!");
                 })( window );

                 可以看出來這樣寫的直接效果,就相當于我們直接彈出一個字符串。但是不同的是,我們將里面的變量變成了局域變量,這不僅可以提高運行速度,更重要的是我們在引用jquery的JS文件時,不會因為jquery當中的變量太多,而與其它的JS框架的變量命名產生沖突。對于這一點,我們拿以下這一小段代碼來說明。

               var temp = "Hello World!";
                  (function( window, undefined ) {
                   var temp = "ByeBye World!";
                  })( window );
                  alert(temp);

                 這段代碼的運行結果是Hello而不是ByeBye,也就是說閉包中的變量聲明沒有污染到外面的全局變量,倘若我們去掉閉包,則最終的結果會是ByeBye,就像下面這樣。

                var temp = "Hello World!";
                  //    (function( window, undefined ) {
                   var temp = "ByeBye World!";
                //    })( window );
                 alert(temp);

                 由此就可以看出來,jquery的外衣就是這一層閉包,它是很重要的一個內容,是編寫JS框架必須知道的知識,它可以幫助我們隱藏我們的臨時變量,降低污染。

                 剛才我們說了,jquery將自己聲明的變量全部都用外衣遮蓋起來了,而我們平時使用的Jquery和$,卻是真真實實的全局變量,這個是從何而來,謎底就在jquery的某一行代碼,一般是在文件的末尾。

          window.jQuery = window.$ = jQuery;
                 這一句話將我們在閉包當中定義的jQuery對象導出為全局變量jQuery和$,因此我們才可以在外部直接使用jQuery和$。window是默認的JS上下文環境,因此將對象綁定到window上面,就相當于變成了傳統意義上的全局變量,就像下面這一小段代碼的效果一樣。

                var temp = "Hello World!";
                (function( window, undefined ) {
                   var temp = "ByeBye World!";
                   window.temp = temp;
                 })( window );
                 alert(temp);

                 很明顯,它的結果應該是ByeBye,而不是Hello。因為我們在閉包中導出了temp局部變量為全局變量,從而覆蓋了第一行聲明的全局變量temp。

                  jquery最核心的功能,就是選擇器。而選擇器簡單理解的話,其實就是在DOM文檔中,尋找一個DOM對象的工具。

                  首先我們進入jquery源碼中,可以很容易的找到jquery對象的聲明,看過以后會發現,原來我們的jquery對象就是init對象。

                   jQuery = function( selector, context ) {
                    return new jQuery.fn.init( selector, context, rootjQuery );
                   }

                   jQuery.fn = jQuery.prototype;

                   jQuery.fn.init.prototype = jQuery.fn;
                  這兩句話,第一句把jQuery對象的原型賦給了fn屬性,第二句把jQuery對象的原型又賦給了init對象的原型。也就是說,init對象和jQuery具有相同的原型,因此我們在上面返回的init對象,就與jQuery對象有一樣的屬性和方法。
          很多時候,我們在jQuery和DOM對象之間切換時需要用到[0]這個屬性。從截圖也可以看出,jQuery對象其實主要就是把原生的DOM對象存在了[0]的位置,并給它加了一系列簡便的方法。這個索引0的屬性我們可以從一小段代碼簡單的看一下它的由來,下面是init方法中的一小段對DOMElement對象作為選擇器的源碼。

                // Handle $(DOMElement)
                 if ( selector.nodeType ) {
                      /*     可以看到,這里將DOM對象賦給了jQuery對象的[0]這個位置  */
                      this.context = this[0] = selector;
                      this.length = 1;
                     return this;
                  }

                 這一小段代碼可以在jquery源碼中找到,它是處理傳入的選擇參數是一個DOM對象的情況??梢钥吹?,里面很明顯的將jQuery對象索引0的位置以及context屬性,都賦予了DOM對象。代碼不僅說明了這一點,也同時說明了,我們使用$(DOMElement)可以將一個DOM對象轉換為jQuery對象,從而通過轉換獲得jQuery對象的簡便方法。

          css的多行省略號處理

          周周

                在我們的頁面布局的時候,經常會有這樣的需求,超過指定行文本的時候會進行(省略號...)的處理,那么我們改怎么設置css呢?如下:

          設置盒子的css為:

          • overflow:hidden;;
          • text-overflow:ellipsis;
          • white-space:nowrap;

                 但是這樣只能顯示一行而不能實現指定行,所以還要其他的方法來實現指定行處理的。



               WebKit瀏覽器或移動端的頁面(大部分移動端都是webkit)

                  可以直接使用WebKit的CSS擴展屬性(WebKit是私有屬性)-webkit-line-clamp ;注意:這是一個不規范的屬性,它沒有出現在 CSS 規范草案中。



                  -webkit-line-clamp用來限制在一個塊元素顯示的文本的行數。 為了實現該效果,它需要組合其他的WebKit屬性。
                 常見結合屬性:
          • display: -webkit-box; 必須結合的屬性 ,將對象作為彈性伸縮盒子模型顯示 。
          • -webkit-box-orient 必須結合的屬性 ,設置或檢索伸縮盒對象的子元素的排列方式 。
          • text-overflow: ellipsis;,可以用來多行文本的情況下,用省略號“…”隱藏超出范圍的文本 。

               css 代碼:

          • overflow:hidden;
          • text-overflow: ellipsis;
          • display: -webkit-box;
          • -webkit-line-clamp:2;/*這里控制著顯示多少行*/
          • -webkit-box-orient:vertical;


          原生js的ajax請求

          周周

          傳統方法的缺點:

                傳統的web交互是用戶觸發一個http請求服務器,然后服務器收到之后,在做出響應到用戶,并且返回一個新的頁面,,每當服務器處理客戶端提交的請求時,客戶都只能空閑等待,并且哪怕只是一次很小的交互、只需從服務器端得到很簡單的一個數據,都要返回一個完整的HTML頁,而用戶每次都要浪費時間和帶寬去重新讀取整個頁面。這個做法浪費了許多帶寬,由于每次應用的交互都需要向服務器發送請求,應用的響應時間就依賴于服務器的響應時間。這導致了用戶界面的響應比本地應用慢得多。

          什么是ajax?

                 ajax的出現,剛好解決了傳統方法的缺陷。AJAX 是一種用于創建快速動態網頁的技術。通過在后臺與服務器進行少量數據交換,AJAX 可以使網頁實現異步更新。這意味著可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新。

          XMLHttpRequest 對象

                 XMLHttpRequest對象是ajax的基礎,XMLHttpRequest 用于在后臺與服務器交換數據。這意味著可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新。目前所有瀏覽器都支持XMLHttpRequest。

          方法
          描述
          abort()
          停止當前請求
          getAllResponseHeaders() 
           把HTTP請求的所有響應首部作為鍵/值對返回
          getResponseHeader("header")
          返回指定首部的串值
          open("method","URL",[asyncFlag],["userName"],["password"])
          建立對服務器的調用。method參數可以是GET、POST或PUT。url參數可以是相對URL或絕對URL。這個方法還包括3個可選的參數,是否異步,用戶名,密碼
          send(content)
          向服務器發送請求
          setRequestHeader("header", "value") 
          把指定首部設置為所提供的值。在設置任何首部之前必須先調用open()。設置header并和請求一起發送 ('post'方法一定要 )
          五步使用法:

                 1.創建XMLHTTPRequest對象
                 2.使用open方法設置和服務器的交互信息
                 3.設置發送的數據,開始和服務器端交互
                 4.注冊事件
                 5.更新界面

          下面給大家列出get請求和post請求的例子

          get請求:      

                 //步驟一:創建異步對象
                 var ajax = new XMLHttpRequest();
                 //步驟二:設置請求的url參數,參數一是請求的類型,參數二是請求的url,可以帶參數,動態的傳遞參數starName到服務端
                 ajax.open('get','getStar.php?starName='+name);
                 //步驟三:發送請求
                  ajax.send();
                 //步驟四:注冊事件 onreadystatechange 狀態改變就會調用
                  ajax.onreadystatechange = function () {
                 if (ajax.readyState==4 &&ajax.status==200) {
                 //步驟五 如果能夠進到這個判斷 說明 數據 完美的回來了,并且請求的頁面是存在的
                 console.log(xml.responseText);//輸入相應的內容
                   }
                  } 

          post請求:

                 //創建異步對象  
                 var xhr = new XMLHttpRequest();
                 //設置請求的類型及url
                 //post請求一定要添加請求頭才行不然會報錯
                 xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
                 xhr.open('post', '02.post.php' );
                 //發送請求
                 xhr.send('name=fox&age=18');
                 xhr.onreadystatechange = function () {
                 // 這步為判斷服務器是否正確響應
                 if (xhr.readyState == 4 && xhr.status == 200) {
                        console.log(xhr.responseText);
                       }
                  };    

          為了方便使用,我們可以把他封裝進方法里面,要用的時候,直接調用就好了。

                 function ajax_method(url,data,method,success) {
                 // 異步對象
                 var ajax = new XMLHttpRequest();

                // get 跟post  需要分別寫不同的代碼
                if (method=='get') {
                    // get請求
                    if (data) {
                        // 如果有值
                        url+='?';
                        url+=data;
                    }else{

                   }      

                 // 設置 方法 以及 url
                      ajax.open(method,url);

                     // send即可
                     ajax.send();
                  }else{
                       // post請求
                       // post請求 url 是不需要改變
                       ajax.open(method,url);

                      // 需要設置請求報文
                     ajax.setRequestHeader("Content-type","application/x-www-form-urlencoded");

                     // 判斷data send發送數據
                    if (data) {
                      // 如果有值 從send發送
                          ajax.send(data);
                    }else{
                         // 木有值 直接發送即可
                        ajax.send();
                      }
                   }     

                 // 注冊事件
                 ajax.onreadystatechange = function () {
                 // 在事件中 獲取數據 并修改界面顯示
                      if (ajax.readyState==4&&ajax.status==200) {
                          // console.log(ajax.responseText);

                          // 將 數據 讓 外面可以使用
                         // return ajax.responseText;

                         // 當 onreadystatechange 調用時 說明 數據回來了
                        // ajax.responseText;

                        // 如果說 外面可以傳入一個 function 作為參數 success
                        success(ajax.responseText);
                       }
                   }
                }

          WebVR大潮來襲 ---前端開發能做些什么?

          周周

                  去年谷歌和火狐針對WebVR提出了WebVR API的標準,顧名思義,WebVR即web + VR的體驗方式,我們可以戴著頭顯享受沉浸式的網頁,新的API標準讓我們可以使用js語言來開發。今天,約克先森將介紹如何開發一個WebVR網頁,在此之前,我們有必要了解WebVR的體驗方式。

          WebVR體驗模式

          WebVR的體驗方式可以分為VR模式和裸眼模式

          一、VR模式

          ?滑配式HMD + 移動端瀏覽器

                  如使用cardboard眼鏡來體驗手機瀏覽器的webVR網頁,瀏覽器將根據水平陀螺儀的參數來獲取用戶的頭部傾斜和轉動的朝向,并告知頁面需要渲染哪一個朝向的場景。

          ?分離式HMD + PC端瀏覽器

                  通過佩戴Oculus Rift的分離式頭顯瀏覽連接在PC主機端的網頁,現支持WebVR API的瀏覽器主要是火狐的 Firefox Nightly和設置VR enabled的谷歌chrome beta。

          二、裸眼模式

                  除了VR模式下的體驗方式,這里還考慮了裸眼下的體驗瀏覽網頁的方式,在PC端如果探測的用戶選擇進入VR模式,應讓用戶可以使用鼠標拖拽場景,而在智能手機上則應讓用戶可以使用touchmove或旋轉傾斜手機的方式來改變場景視角。

                  WebVR的概念大概就如此,這次我們將采用cardboard + mobile的方式來測試我們的WebVR場景,現在踏上我們的開發之旅。

          準備工作

                  技術和框架:three.js for WebGL

                   Three.js是構建3d場景的框架,它封裝了WebGL函數,簡化了創建場景的代碼成本,利用three.js我們可以更優雅地創建出三維場景和三維動畫。

                  測試工具:智能手機 + 滑配式頭顯

                  推薦使用cardboard或者某寶上三十塊錢的高仿貨。當然,如果你練就了裸眼就能將手機雙屏畫面看成單屏的能力也可以忽略。

                 需要引入的js插件:

          • three.min.js
          • webvr-polyfill.js
          • VRcontrols.js
          • VReffect.js
          • webvr-manager.js

          webvr-polyfill.js

                  由于WebVR API還沒被各大主流瀏覽器支持,因此需要引入webvr-polyfill.js來支持WebVR網頁,它提供了大量VR相關的API,比如Navigator.getVRDevices()獲取VR頭顯信息的方法。

          VRControls.js

                  VR控制器,是three.js的一個相機控制器對象,引入VRcontrols.js可以根據用戶在空間的朝向渲染場景,它通過調用WebVR API的orientation值控制camera的rotation屬性。

          VREffect.js

                  VR分屏器,這是three.js的一個場景分屏的渲染器,提供戴上VR頭顯的顯示方式,VREffect.js重新創建了左右兩個相機,對場景做二次渲染,產生雙屏效果。

          webvr-manager.js

                   這是WebVR的方案適配插件,它提供PC端和移動端的兩種適配方式,通過new WebVRManager()可以生成一個VR圖標,提供VR模式和裸眼模式的不同體驗,當用戶在移動端點擊按鈕進入VR模式時,WebVRManager便會調用VREffect分屏器進行分屏,而退出VR模式時,WebVRManager便用回renderer渲染器進行單屏渲染。

                  具體使用方法我們將在下文說明。

                  3D場景構建

                  首先我們創建一個HTML文件

                 <!DOCTYPE html>

                 <html lang="en">

                 <head> 

                        <meta charset="UTF-8">

                            <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0, shrink-to-fit=no">

                        <title>webVR-helloworld</title>

                             <style type="text/css">

                                   * { 

                                     margin: 0;

                                     padding: 0;

                                      }

                               html,body {

                                           height: 100%;

                                          overflow: hidden;

                               }

                         </style>

                   </head>

                   <body>

                   </body>

                  <script src="./vendor/three.min.js"></script>

                    <script src="./vendor/webvr-polyfill.js"></script>

                    <script src="./vendor/VRControls.js"></script>

                 <script src="./vendor/VREffect.js"></script>

                 <script src="./vendor/webvr-manager.js"></script>

                 <script src="./main.js"></script>

                 </html>

                   接下來編寫js腳本,開始創建我們的3d場景。

          1、創建場景

                  Three.js中的scene場景是繪制我們3d對象的整個容

                 1.var scene = new THREE.Scene();

          2、添加相機

          Three.js的相機

          Three.js中的camera相機代表用戶的眼睛,我們通過設置FOV確定視野范圍,

          • //定義一個60°的視角,視線范圍在1到1000的透視相機
          • var camera = new THREE. new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,1000);
          • scene.add(camera);

          3、添加渲染器

          • Three.js的渲染器用來渲染camera所看到的畫面


          • //初始化渲染器 antialias參數為ture表示開啟抗鋸齒策略
          • var renderer = new THREE.WebGLRenderer({ antialias: true } );
          • //設置渲染器渲染尺寸
          • renderer.setSize(window.innerWidth,window.innerHeight);
          • //設置渲染背景為白色
          • renderer.setClearColor(0xeeeeee);
          • //將渲染場景的canvas放入body標簽里
          • document.body.appendChild(renderer.domElement);

          • 添加一個立方體網格

          • // 創建立方體
          • var geometry = new THREE.CubeGeometry( 10,10,10);
          • var cubematerial = new THREE.MeshLambertMaterial( { color: 0xef6500,needsUpdate: true,opacity:1,transparent:true} );
          • var cube = new THREE.Mesh( geometry, Cubematerial );
          • cube.position.set(0,100,-50);
          • cube.rotation.set(Math.PI/6,Math.PI/4,0);
          • scene.add(cube);

          4、啟動動畫

          • 產生動畫的原理就是讓camera持續連拍,同時每一次改變物體的屬性,通過requestAnimationFrame()方法遞歸的方式來持續更新場景對象屬性,你可以將它理解為setTimeout的優化版。相比setTimeout函數,requestAnimationFrame可以保證動畫渲染不會因為主線程的阻塞而造成跳幀。


          • function animate() {
          •     //讓立方體旋轉
          •     cube.rotation.y += 0.01;
          •     //渲染器渲染場景,等同于給相機按下快門
          •     renderer.render(scene, camera);
          •     //遞歸運行該函數
          •     requestAnimationFrame( animate );
          • }
          • animate();//啟動動畫

                至此,我們已經繪制了一個簡單的3d場景并且讓它動了起來,接下來,我們需要讓我們的場景可以支持WebVR模式。

          WebVR場景開發

                 WebVR網頁的基本原理其實是通過瀏覽器的WebVR API獲取用戶輸入,進而控制相機的視角,在VR模式下通過VR控制器和VR分屏器以二分屏+gyroscope(使用水平陀螺儀)的方式顯示畫面,裸眼情況下提供全屏+touchmove/gyroscope。

                 現在我們開始分別創建上文所說的VR控制器和VR分屏器

          • //初始化VR控制器需要傳入場景相機
          • var vrControls = new THREE.VRControls(camera);
          • //初始化VR渲染器需要傳入場景渲染器
          • var vrEffect = new THREE.VREffect(renderer);
          • //初始化VR適配器,傳入渲染器和分屏器
          • var vrManager = new WebVRManager(renderer, vrEffect);

                然后在前面創建的場景渲染函數里調用

          • function animate() {
          •     cube.rotation.y += 0.01;
          •     //實時更新相機的位置和轉角
          •     vrControls.update();
          •     vrManager.render(scene, camera);
          •     //遞歸運行該函數
          •     requestAnimationFrame( animate );
          • }

                 至此,我們已經完成了一個基本的webVR網頁,不過少了點交互效果好像,敬請期待Web開發的新世界---WebVR之交互事件。

          • 完整代碼:在文章基礎上添加了天空和地面相關代碼,以及下篇文章將講到VR凝視交互事件。
          • demo演示地址 :手機瀏覽需設置允許橫屏。

          結語

                  目前,國外的谷歌、火狐、Facebook和國內百度已推出支持WebVR瀏覽器的版本,微軟也宣布將推出自己的VR瀏覽器,隨著后期5g網絡極速時代的到來以及HMD頭顯的價格和平臺的成熟,WebVR的體驗方式將是革命性的,用戶通過WebVR瀏覽網上商店,線上教學可進行“面對面”師生交流等,基于這種種應用場景,我們可以找到一個更好的動力去學習WebVR。






          日歷

          鏈接

          個人資料

          藍藍設計的小編 http://www.syprn.cn

          存檔

          亚洲va欧美va天堂v国产综合