<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>

          首頁

          2020年最火的設計趨勢Neumorphism

          藍藍設計的小編

          藍藍注:我非常喜歡這個風格。


          日前,在網上流行起了一種叫 Neumorphism 的新風格,也有人稱為 Soft UI,這是一種類似于浮雕的效果。這種風格的出現,給目前流行的扁平化設計增加了一種新的設計形式,很多媒體甚至還將這個風格列為 2020 的設計趨勢,三星 Galaxy 系列的發布會宣傳海報也使用了這種風格,可見這個風格的火熱程度。那么一開始我們不討論這個風格好還是不好,先來了解一下這個新風格趨勢。

          什么是Neumorphism?

          最開始是一位來自烏克蘭的設計師 Alexander Plyuto 在各平臺發布了新的作品「Skeuomorph Mobile Banking」。這個作品自發布以來就獲得了數十萬瀏覽量,數千點贊數,熱度持續飆升并登上 Popular 榜首。

          作者是用 Skeuomorph 來命名這個作品風格,評論區就開始了這種風格的討論,有的人說這是新的擬物風格(New Skeuomorphism),也有人說這是擬物風格 2.0 版本(Skeuomorph 2.0),而后來就有設計師創出一個新的虛構名詞,把 New Skeuomorphism 兩個詞組合,Neo 諧音 New 就是 Neuomorphism。

          這個名字就這么火了。大家都開始用上了這個名詞出作品,成為了設計新趨勢。甚至連作者后面的作品,也使用了這個名稱。

          再后來國外知名設計師 Michal Malewicz 發布了一篇關于這個風格的文章,將 Neuomorphism,刪減了里面的字母「O」,改成了 Neumorphism。在大神的推動下大家又開始爭先恐后地使用這個名稱。

          目前有各種對名稱的說法,Neuomorphism,Neumorphism,Skeuomorphism,Soft UI,在沒有實際確定的情況下,其實怎樣叫都無所謂,重點是我們要知道這種設計風格趨勢,關注的不是名字,而是設計。

          還記得擬物風格嗎?

          既然 Neumorphism 只是一個虛構詞,也沒有任何官方認定,那就先不糾結應該叫什么,我們還是來說說它的前身吧,也就是 Skeuomorphism(擬物)。這是最早被 Apple 提出的設計概念,就是在界面中模仿現實物體紋理材質的設計,目的是讓人們在使用界面時習慣性地聯想到現實物體的使用方式。

          擬物寫實的設計風格曾經風靡全球,當時的 UI 設計師幾乎都對擬物作品著迷。

          而在 2013 年的 WWDC 大會中,蘋果公司發布的 iOS7 系統,系統 UI 使用更簡潔的設計風格。這場大會也使擬物風格逐漸過時,直到現在扁平風格的全面普及,擬物風格就再沒有被廣泛應用。

          從前幾年的設計趨勢可以看到,扁平風格作為更更簡潔的風格被設計師推崇,再加上蘋果系統 iOS 7 設計風格的面世和谷歌系統規范 Material Design 的普及,扁平風格在 UI 設計中一直占據重要位置。

          但設計的流行趨勢也一直在改變著,在蘋果公司發布的 iOS 13 系統中,就有出現輕擬物的設計手法,接著就有一大堆設計師猜測是不是擬物風格的回歸,但我看系統中大部分界面設計也還是扁平風格,并沒有把擬物風格作為主要設計風格,也許只是某種程度上解決了畫筆的視覺識別問題。

          擬物效果能否回歸,這個言之尚早,但是新的風格趨勢也許可以在扁平同質化的時候增添一點靈感與樂趣。

          能用在實際項目中嗎?

          1. 設計

          其實要做到這個效果并不難,了解一下這個風格的結構。

          主要有三個樣式組成,1 個背景+ 2 個投影。在這個基礎上,通過改變顏色和大小參數來達到不同效果。

          我嘗試著使用彩色去做這個效果,使用淺色背景時還是有效果的,但使用深一點的顏色時,問題就出現了,效果更像是外發光或者普通投影。這也可能是為什么大多數作品都采用比較素的顏色作為背景的原因。

          2. 瀏覽

          這個風格最大的問題就是缺少對比度。在色彩使用上比較克制,沒有大面積的平鋪顏色,僅在極少的位置進行色彩點綴,作用是吸引眼球。從眾多設計師的作品可以看出,整體視覺是比較平的,缺少層次。

          我拿其中兩張圖進行了 15% 強度的模糊處理,可以看到除了點綴的位置以外,界面是沒有重點的。

          3. 操作

          因為在界面中除了文字以外,幾乎所有元素都應用了這種效果,導致界面所有內容看起來都是按鈕的錯覺。界面中的主要操作按鈕也沒有被重點提亮。正常態和點擊態的對比度并沒有拉開,容易造成狀態混淆。點擊欲望比較低,不利于引導用戶進行下一步操作。

          4. 動畫

          跟擬物效果的動畫有同樣的問題,元素動畫效果很難做得輕快,更適合按鈕的使用。由于視覺層級跟背景沒有實際分離開,就像固定在了背景上一樣,所以動畫效果只要出現移動,就會讓人覺得不合理,容易給人一種蟲子在皮膚底下蠕動的感覺。

          5. 開發

          問題跟當年的擬物效果的實現類似,要實現這個風格,主要有兩個方式。

          切圖:對元素的每個狀態(Normal、Hover、Pressed),設計師都需要分別提供一張切圖,這個會導致資源庫增加大量的圖片。 代碼實現:這個風格的實現效果是對元素增加兩個不同方向的投影,通過代碼可以實現。但是需要開發對每個元素添加投影,樣式代碼增多,繁瑣的工作量,開發也不會樂意。

          附 CSS 實現新風格的網站:Neumorphism 的生成器

          綜合分析來看,這種設計風格目前在項目中推廣和實現中并不合適。

          總結

          這個風格的出現也確實給大家帶來了一個新的思考,這個風格會持續嗎?可用嗎?也許扁平風格的多年流行后,設計潮流開始往回走,但并不是直接回到擬物風格,而是在效率和視覺效果中找一個平衡點。不論這個風格的對錯,起碼引起了設計師的注意,也激發了很多設計師的靈感,就像當年擬物風格和扁平風格的討論一樣,不分對錯,設計師也不妨多留意一下這個風格,試著做一下效果圖,或許會有新的發現。

          JavaScript中的Event Loop(事件循環)機制

          seo達人

          事件循環

          JavaScript是單線程,非阻塞的

          瀏覽器的事件循環


          執行棧和事件隊列

          宏任務和微任務

          node環境下的事件循環


          和瀏覽器環境有何不同

          事件循環模型

          宏任務和微任務

          經典題目分析

          1. JavaScript是單線程,非阻塞的

          單線程:


          JavaScript的主要用途是與用戶互動,以及操作DOM。如果它是多線程的會有很多復雜的問題要處理,比如有兩個線程同時操作DOM,一個線程刪除了當前的DOM節點,一個線程是要操作當前的DOM階段,最后以哪個線程的操作為準?為了避免這種,所以JS是單線程的。即使H5提出了web worker標準,它有很多限制,受主線程控制,是主線程的子線程。


          非阻塞:通過 event loop 實現。


          2. 瀏覽器的事件循環

          執行棧和事件隊列

          為了更好地理解Event Loop,請看下圖(轉引自Philip Roberts的演講 《Help, I'm stuck in an event-loop》)

          Help, I'm stuck in an event-loop


          執行棧: 同步代碼的執行,按照順序添加到執行棧中


          function a() {

             b();

             console.log('a');

          }

          function b() {

             console.log('b')

          }

          a();

          我們可以通過使用 Loupe(Loupe是一種可視化工具,可以幫助您了解JavaScript的調用堆棧/事件循環/回調隊列如何相互影響)工具來了解上面代碼的執行情況。


          調用情況


          執行函數 a()先入棧

          a()中先執行函數 b() 函數b() 入棧

          執行函數b(), console.log('b') 入棧

          輸出 b, console.log('b')出棧

          函數b() 執行完成,出棧

          console.log('a') 入棧,執行,輸出 a, 出棧

          函數a 執行完成,出棧。

          事件隊列: 異步代碼的執行,遇到異步事件不會等待它返回結果,而是將這個事件掛起,繼續執行執行棧中的其他任務。當異步事件返回結果,將它放到事件隊列中,被放入事件隊列不會立刻執行起回調,而是等待當前執行棧中所有任務都執行完畢,主線程空閑狀態,主線程會去查找事件隊列中是否有任務,如果有,則取出排在第一位的事件,并把這個事件對應的回調放到執行棧中,然后執行其中的同步代碼。


          我們再上面代碼的基礎上添加異步事件,


          function a() {

             b();

             console.log('a');

          }

          function b() {

             console.log('b')

             setTimeout(function() {

                 console.log('c');

             }, 2000)

          }

          a();

          此時的執行過程如下

          img


          我們同時再加上點擊事件看一下運行的過程


          $.on('button', 'click', function onClick() {

             setTimeout(function timer() {

                 console.log('You clicked the button!');    

             }, 2000);

          });


          console.log("Hi!");


          setTimeout(function timeout() {

             console.log("Click the button!");

          }, 5000);


          console.log("Welcome to loupe.");

          img


          簡單用下面的圖進行一下總結


          執行棧和事件隊列


          宏任務和微任務

          為什么要引入微任務,只有一種類型的任務不行么?


          頁面渲染事件,各種IO的完成事件等隨時被添加到任務隊列中,一直會保持先進先出的原則執行,我們不能準確地控制這些事件被添加到任務隊列中的位置。但是這個時候突然有高優先級的任務需要盡快執行,那么一種類型的任務就不合適了,所以引入了微任務隊列。


          不同的異步任務被分為:宏任務和微任務

          宏任務:


          script(整體代碼)

          setTimeout()

          setInterval()

          postMessage

          I/O

          UI交互事件

          微任務:


          new Promise().then(回調)

          MutationObserver(html5 新特性)

          運行機制

          異步任務的返回結果會被放到一個任務隊列中,根據異步事件的類型,這個事件實際上會被放到對應的宏任務和微任務隊列中去。


          在當前執行棧為空時,主線程會查看微任務隊列是否有事件存在


          存在,依次執行隊列中的事件對應的回調,直到微任務隊列為空,然后去宏任務隊列中取出最前面的事件,把當前的回調加到當前指向棧。

          如果不存在,那么再去宏任務隊列中取出一個事件并把對應的回到加入當前執行棧;

          當前執行棧執行完畢后時會立刻處理所有微任務隊列中的事件,然后再去宏任務隊列中取出一個事件。同一次事件循環中,微任務永遠在宏任務之前執行。


          在事件循環中,每進行一次循環操作稱為 tick,每一次 tick 的任務處理模型是比較復雜的,但關鍵步驟如下:


          執行一個宏任務(棧中沒有就從事件隊列中獲?。?

          執行過程中如果遇到微任務,就將它添加到微任務的任務隊列中

          宏任務執行完畢后,立即執行當前微任務隊列中的所有微任務(依次執行)

          當前宏任務執行完畢,開始檢查渲染,然后GUI線程接管渲染

          渲染完畢后,JS線程繼續接管,開始下一個宏任務(從事件隊列中獲?。?

          簡單總結一下執行的順序:

          執行宏任務,然后執行該宏任務產生的微任務,若微任務在執行過程中產生了新的微任務,則繼續執行微任務,微任務執行完畢后,再回到宏任務中進行下一輪循環。


          宏任務和微任務


          深入理解js事件循環機制(瀏覽器篇) 這邊文章中有個特別形象的動畫,大家可以看著理解一下。


          console.log('start')


          setTimeout(function() {

           console.log('setTimeout')

          }, 0)


          Promise.resolve().then(function() {

           console.log('promise1')

          }).then(function() {

           console.log('promise2')

          })


          console.log('end')

          瀏覽器事件循環


          全局代碼壓入執行棧執行,輸出 start

          setTimeout壓入 macrotask隊列,promise.then 回調放入 microtask隊列,最后執行 console.log('end'),輸出 end

          調用棧中的代碼執行完成(全局代碼屬于宏任務),接下來開始執行微任務隊列中的代碼,執行promise回調,輸出 promise1, promise回調函數默認返回 undefined, promise狀態變成 fulfilled ,觸發接下來的 then回調,繼續壓入 microtask隊列,此時產生了新的微任務,會接著把當前的微任務隊列執行完,此時執行第二個 promise.then回調,輸出 promise2

          此時,microtask隊列 已清空,接下來會會執行 UI渲染工作(如果有的話),然后開始下一輪 event loop, 執行 setTimeout的回調,輸出 setTimeout

          最后的執行結果如下


          start

          end

          promise1

          promise2

          setTimeout

          node環境下的事件循環

          和瀏覽器環境有何不同

          表現出的狀態與瀏覽器大致相同。不同的是 node 中有一套自己的模型。node 中事件循環的實現依賴 libuv 引擎。Node的事件循環存在幾個階段。


          如果是node10及其之前版本,microtask會在事件循環的各個階段之間執行,也就是一個階段執行完畢,就會去執行 microtask隊列中的任務。


          node版本更新到11之后,Event Loop運行原理發生了變化,一旦執行一個階段里的一個宏任務(setTimeout,setInterval和setImmediate)就立刻執行微任務隊列,跟瀏覽器趨于一致。下面例子中的代碼是按照的去進行分析的。


          事件循環模型

          ┌───────────────────────┐

          ┌─>│        timers         │

          │  └──────────┬────────────┘

          │  ┌──────────┴────────────┐

          │  │     I/O callbacks     │

          │  └──────────┬────────────┘

          │  ┌──────────┴────────────┐

          │  │     idle, prepare     │

          │  └──────────┬────────────┘      ┌───────────────┐

          │  ┌──────────┴────────────┐      │   incoming:   │

          │  │         poll          │<──connections───     │

          │  └──────────┬────────────┘      │   data, etc.  │

          │  ┌──────────┴────────────┐      └───────────────┘

          │  │        check          │

          │  └──────────┬────────────┘

          │  ┌──────────┴────────────┐

          └──┤    close callbacks    │

            └───────────────────────┘

          事件循環各階段詳解

          node中事件循環的順序


          外部輸入數據 --> 輪詢階段(poll) --> 檢查階段(check) --> 關閉事件回調階段(close callback) --> 定時器檢查階段(timer) --> I/O 事件回調階段(I/O callbacks) --> 閑置階段(idle, prepare) --> 輪詢階段...


          這些階段大致的功能如下:


          定時器檢測階段(timers): 這個階段執行定時器隊列中的回調如 setTimeout() 和 setInterval()。

          I/O事件回調階段(I/O callbacks): 這個階段執行幾乎所有的回調。但是不包括close事件,定時器和setImmediate()的回調。

          閑置階段(idle, prepare): 這個階段僅在內部使用,可以不必理會

          輪詢階段(poll): 等待新的I/O事件,node在一些特殊情況下會阻塞在這里。

          檢查階段(check): setImmediate()的回調會在這個階段執行。

          關閉事件回調階段(close callbacks): 例如socket.on('close', ...)這種close事件的回調

          poll:

          這個階段是輪詢時間,用于等待還未返回的 I/O 事件,比如服務器的回應、用戶移動鼠標等等。

          這個階段的時間會比較長。如果沒有其他異步任務要處理(比如到期的定時器),會一直停留在這個階段,等待 I/O 請求返回結果。

          check:

          該階段執行setImmediate()的回調函數。


          close:

          該階段執行關閉請求的回調函數,比如socket.on('close', ...)。


          timer階段:

          這個是定時器階段,處理setTimeout()和setInterval()的回調函數。進入這個階段后,主線程會檢查一下當前時間,是否滿足定時器的條件。如果滿足就執行回調函數,否則就離開這個階段。


          I/O callback階段:

          除了以下的回調函數,其他都在這個階段執行:


          setTimeout()和setInterval()的回調函數

          setImmediate()的回調函數

          用于關閉請求的回調函數,比如socket.on('close', ...)

          宏任務和微任務

          宏任務:


          setImmediate

          setTimeout

          setInterval

          script(整體代碼)

          I/O 操作等。

          微任務:


          process.nextTick

          new Promise().then(回調)

          Promise.nextTick, setTimeout, setImmediate的使用場景和區別

          Promise.nextTick

          process.nextTick 是一個獨立于 eventLoop 的任務隊列。

          在每一個 eventLoop 階段完成后會去檢查 nextTick 隊列,如果里面有任務,會讓這部分任務優先于微任務執行。

          是所有異步任務中最快執行的。


          setTimeout:

          setTimeout()方法是定義一個回調,并且希望這個回調在我們所指定的時間間隔后第一時間去執行。


          setImmediate:

          setImmediate()方法從意義上將是立刻執行的意思,但是實際上它卻是在一個固定的階段才會執行回調,即poll階段之后。


          經典題目分析

          一. 下面代碼輸出什么

          async function async1() {

             console.log('async1 start');

             await async2();

             console.log('async1 end');

          }

          async function async2() {

             console.log('async2');

          }

          console.log('script start');

          setTimeout(function() {

             console.log('setTimeout');

          }, 0)

          async1();

          new Promise(function(resolve) {

             console.log('promise1');

             resolve();

          }).then(function() {

             console.log('promise2');

          });

          console.log('script end');

          先執行宏任務(當前代碼塊也算是宏任務),然后執行當前宏任務產生的微任務,然后接著執行宏任務


          從上往下執行代碼,先執行同步代碼,輸出 script start

          遇到setTimeout,現把 setTimeout 的代碼放到宏任務隊列中

          執行 async1(),輸出 async1 start, 然后執行 async2(), 輸出 async2,把 async2() 后面的代碼 console.log('async1 end')放到微任務隊列中

          接著往下執行,輸出 promise1,把 .then()放到微任務隊列中;注意Promise本身是同步的立即執行函數,.then是異步執行函數

          接著往下執行, 輸出 script end。同步代碼(同時也是宏任務)執行完成,接下來開始執行剛才放到微任務中的代碼

          依次執行微任務中的代碼,依次輸出 async1 end、 promise2, 微任務中的代碼執行完成后,開始執行宏任務中的代碼,輸出 setTimeout

          最后的執行結果如下


          script start

          async1 start

          async2

          promise1

          script end

          async1 end

          promise2

          setTimeout

          二. 下面代碼輸出什么

          console.log('start');

          setTimeout(() => {

             console.log('children2');

             Promise.resolve().then(() => {

                 console.log('children3');

             })

          }, 0);


          new Promise(function(resolve, reject) {

             console.log('children4');

             setTimeout(function() {

                 console.log('children5');

                 resolve('children6')

             }, 0)

          }).then((res) => {

             console.log('children7');

             setTimeout(() => {

                 console.log(res);

             }, 0)

          })

          這道題跟上面題目不同之處在于,執行代碼會產生很多個宏任務,每個宏任務中又會產生微任務


          從上往下執行代碼,先執行同步代碼,輸出 start

          遇到setTimeout,先把 setTimeout 的代碼放到宏任務隊列①中

          接著往下執行,輸出 children4, 遇到setTimeout,先把 setTimeout 的代碼放到宏任務隊列②中,此時.then并不會被放到微任務隊列中,因為 resolve是放到 setTimeout中執行的

          代碼執行完成之后,會查找微任務隊列中的事件,發現并沒有,于是開始執行宏任務①,即第一個 setTimeout, 輸出 children2,此時,會把 Promise.resolve().then放到微任務隊列中。

          宏任務①中的代碼執行完成后,會查找微任務隊列,于是輸出 children3;然后開始執行宏任務②,即第二個 setTimeout,輸出 children5,此時將.then放到微任務隊列中。

          宏任務②中的代碼執行完成后,會查找微任務隊列,于是輸出 children7,遇到 setTimeout,放到宏任務隊列中。此時微任務執行完成,開始執行宏任務,輸出 children6;

          最后的執行結果如下


          start

          children4

          children2

          children3

          children5

          children7

          children6

          三. 下面代碼輸出什么

          const p = function() {

             return new Promise((resolve, reject) => {

                 const p1 = new Promise((resolve, reject) => {

                     setTimeout(() => {

                         resolve(1)

                     }, 0)

                     resolve(2)

                 })

                 p1.then((res) => {

                     console.log(res);

                 })

                 console.log(3);

                 resolve(4);

             })

          }



          p().then((res) => {

             console.log(res);

          })

          console.log('end');

          執行代碼,Promise本身是同步的立即執行函數,.then是異步執行函數。遇到setTimeout,先把其放入宏任務隊列中,遇到p1.then會先放到微任務隊列中,接著往下執行,輸出 3

          遇到 p().then 會先放到微任務隊列中,接著往下執行,輸出 end

          同步代碼塊執行完成后,開始執行微任務隊列中的任務,首先執行 p1.then,輸出 2, 接著執行p().then, 輸出 4

          微任務執行完成后,開始執行宏任務,setTimeout, resolve(1),但是此時 p1.then已經執行完成,此時 1不會輸出。

          最后的執行結果如下


          3

          end

          2

          4

          你可以將上述代碼中的 resolve(2)注釋掉, 此時 1才會輸出,輸出結果為 3 end 4 1。


          const p = function() {

             return new Promise((resolve, reject) => {

                 const p1 = new Promise((resolve, reject) => {

                     setTimeout(() => {

                         resolve(1)

                     }, 0)

                 })

                 p1.then((res) => {

                     console.log(res);

                 })

                 console.log(3);

                 resolve(4);

             })

          }



          p().then((res) => {

             console.log(res);

          })

          console.log('end');

          3

          end

          4

          1

          最后強烈推薦幾個非常好的講解 event loop 的視頻:


          What the heck is the event loop anyway? | Philip Roberts | JSConf EU

          Jake Archibald: In The Loop - JSConf.Asia

          大屏數據可視化設計指南

          鶴鶴

          可能是目前大屏數據可視化設計介紹最詳盡的一篇文章了,可以當做設計手冊使用的一篇經驗分享

          Image title


          一、基礎概念


          1、什么是數據可視化


          把相對復雜、抽象的數據通過可視的方式以人們更易理解的形式展示出來的一系列手段叫做數據可視化,數據可視化是為了更形象地表達數據內在的信息和規律,促進數據信息的傳播和應用。


          在當前新技術支持下,數據可視化除了“可視”,還可有可交流、可互動的特點。數據可視化的本質是數據空間到圖形空間的映射,是抽象數據的具象表達。

          Image title


          數據可視化作品《launchit》

          作者:Shane Mielke 

          作者寫了本書,地圖上顯示了世界各地讀者的分布情況及對應人數

          Image title


          數據可視化作品《world-drawn-by-travelers》

          作者:TripHappy

          國家之間相互連通的旅游路線,顏色越相近的國家,表明兩國家的人們互動越頻繁

          Image title


          2、什么是大屏數據可視化


          大屏數據可視化是以大屏為主要展示載體的數據可視化設計。

          “大面積、炫酷動效、豐富色彩”,大屏易在觀感上給人留下震撼印象,便于營造某些獨特氛圍、打造儀式感。電商雙11類大屏利用此特點打造了熱烈、狂歡的節日氛圍,原本看不見的數據可視化后,便能調動人的情緒、引發人的共鳴,傳遞企業文化和價值。

          Image title

          Image title


          利用面積大、可展示信息多的特點,通過關鍵信息大屏共享的方式可方便團隊討論、決策,故大屏也常用來做數據分析監測使用。大屏數據可視化目前主要有信息展示、數據分析及監控預警三大類。


          數據分析類

          圖片來源:必應;圖片作者:帆軟軟件有限公司

          Image title


          二、大屏數據可視化設計原則:設計服務需求、先總覽后細節


          設計服務需求


          大屏設計要避免為了展示而展示,排版布局、圖表選用等應服務于業務,所以大屏設計是在充分了解業務需求的基礎上進行的。那什么是業務需求呢?業務需求就是要解決的問題或達成的目標。設計師通過設計的手段幫助相關人員達成這個目標,是大屏數據可視化的價值所在。


          先總覽后細節


          大屏因為大,承載數據多,為了避免觀者迷失,大屏信息呈現要有焦點、有主次。可以通過對比,先把核心數據拋給用戶,待用戶理解大屏主要內容與展示邏輯后,再逐級瀏覽二三級內容。部分細節數據可暫時隱藏,用戶需要時可通過鼠標點擊等交互方式喚起。



          三、大屏可視化設計流程


          規范的流程是好結果的保證。找到一個可參考的流程,然后步步為營,就能避免很多不必要的返工,保證設計質量和項目進度。

          Image title


          1、根據業務場景抽取關鍵指標


          關鍵指標是一些概括性詞語,是對一組或者一系列數據的統稱。一般情況下,一個指標在大屏上獨占一塊區域,所以通過關鍵指標定義,我們就知道大屏上大概會顯示哪些內容以及大屏會被分為幾塊。以共享單車電子圍欄監控系統為例,這里的關鍵指標有:企業停車時長、企業違停量、熱點違停區域、車輛入欄率等。


          確定關鍵指標后,根據業務需求擬定各個指標展示的優先級(主、次、輔)。

          Image title



          2、確立指標分析維度


          “橫看成嶺側成峰”。同一個指標的數據,從不同維度分析就有不同結果。很多小伙伴做完可視化設計,發現可視化圖形并沒有準確表達自己的意圖,也沒能向觀者傳達出應有的信息,可視化圖形讓人困惑或看不懂。出現這種情況很大程度就是因為分析的維度沒有找準或定義的比較混亂。

          Image title

          上圖向大家展示了數據分析常用的4個維度,我們在選定指標后,就需要跟項目組其他小伙伴討論:我們的各個指標主要想給大家展示什么,更進一步的講,是我們想通過可視化表達什么樣的規律和信息。而上圖,可以引導我們從“聯系、分布、比較、構成”四個維度更有邏輯的思考這個問題。


          聯系:數據之間的相關性

          分布:指標里的數據主要集中在什么范圍、表現出怎樣的規律

          比較:數據之間存在何種差異、差異主要體現在哪些方面

          構成:指標里的數據都由哪幾部分組成、每部分占比如何


          當然,上圖例舉的示例圖表都比較傳統,在大屏數據可視化中常還有另一類地理信息(常以2/3D地圖、地球呈現)出現。上圖雖未包含這類圖形,但它提供給我們的確定數據分析維度的思路和方法是相通的,可借鑒。


          3、選定可視化圖表類型


          當確定好分析維度后,事實上我們所能選用的圖表類型也就基本確定了。接下來我們只需要從少數幾個圖表里篩選出最能體現我們設計意圖的那個就好了。


          選定圖表注意事項:易理解、可實現;


          易理解就是可視化設計要考慮大屏最終用戶,可視化結果應該是一看就懂,不需要思考和過度理解,因而選定圖表時要理性,避免為了視覺上的效果而選擇一些對用戶不太友好的圖形。

          Image title


          可實現


          1、我們需要了解現有數據的信息、規模、特征、聯系等,然后評估數據是否能夠支撐相應的可視化表現

          2、我們設計的圖形圖表,要開發能夠實現。實際工作中,一些可視化效果開發用代碼寫很容易實現,效果也不錯,但這些效果設計師用Ps/Ai/Ae這些工具模擬時會發現比較困難;同樣的,某些效果設計師用設計工具可以輕易實現,但開發要用代碼落地卻非常困難,所以大屏設計中跟開發常溝通非常重要,我們需要明確哪些地方設計師可以盡情發揮,哪些地方需要謹慎設計!一個項目總有周期與預算限制,不會無限期的修改迭代,所以設計師在這里需要抓住重點,有取舍,不鉆牛角尖、死磕不放。

          Image title


          4、了解物理大屏,確定設計稿尺寸

          多數情況下設計稿分辨率即被投大屏的信號源電腦屏幕的分辨率。有多個信號源時,就會有多個設計稿,此時每個設計稿的尺寸即對應信號源電腦屏幕的分辨率

          Image title

          一般情況下設計稿的分辨率就是電腦的分辨率,當有多個信號源時,有時會通過顯卡自定義電腦屏幕分辨率,從而使電腦顯示分辨率不等于其物理分辨率,此時,對應設計稿的分辨率也就變成了設置后的分辨率;此外,當被投電腦分辨率長寬比與大屏物理長寬比不一致時(單信號源),也會對被投電腦屏幕分辨率做自定義調整,這種情況設計稿分辨率也會發生變化。所以設計開始前了解物理大屏長寬比很重要。



          5、頁面布局、劃分


          尺寸確立后,接下來要對設計稿進行布局和頁面的劃分。這里的劃分,主要根據我們之前定好的業務指標進行,核心業務指標安排在中間位置、占較大面積;其余的指標按優先級依次在核心指標周圍展開。一般把有關聯的指標讓其相鄰或靠近,把圖表類型相近的指標放一起,這樣能減少觀者認知上的負擔并提高信息傳遞的效率。

          Image title


          6、定義設計風格


          很多小伙伴也許沒接觸過大屏設計工作,但大多數人都應該有APP或者Web風格定義的經驗。我們在定義一款APP或者Web頁面設計風格時常用的方法是什么呢?情緒版!

          大屏雖酷炫,但實際上也是運行在瀏覽器里的Web頁面,所以大屏設計風格定義方法也同樣可以是用情緒版來做,這種方法也是目前比較科學的風格定義手段

          Image title

          上圖提供了情緒版應用的腦圖,具體操作細節不做介紹,不太了解的小伙伴可以自己找找資料哈。

          情緒版的一套流程下來,我們定義的風格基本是科學準確的,可以指導我們執行設計。如果是給甲方爸爸做大屏,這個流程也可以讓我們提出的方案更有說服力



          7、可視化設計


          根據定義好的設計風格與選定的圖表類型進行合理的可視化設計。目前來講大屏可視化主要有指標類信息點和地理類信息點兩大可視化數據。指標類信息點可視化效果相對簡單易實現,而地理類信息點一般可視化效果酷炫,但是開發相對困難,需要設計師跟開發多溝通的。地理類信息一般具有很強的空間感、豐富的粒子、流光等動效、高精度的模型和材質以及可交互實時演算等特點,所以對于被投電腦、大屏拼接器等硬件設備的性能會有要求,硬件配置不夠的情況下可能出現卡頓甚至崩潰的情況,所以這點也是需要提前溝通評估的。

          Image title


          8、樣圖溝通確認


          這里的溝通分三個層面:設計師對內溝通、設計師對外溝通、設計師與大屏的“溝通”。

          Image title

          樣圖溝通環節,最初的樣圖不需要十分精致,我們可以把它理解為一個“低保真”原型,然后通過不斷溝通修改,讓它逐步完善精致起來,也就是小步快跑,避免那種一下子走到終點,然后又大修大改的情況。


          因為我們在前幾步已經分別確定了頁面布局、圖表類型、頁面風格特點,所以這一步我們需要用盡可能簡單的方法 ,把之前幾步的成果在頁面上快速體現出來,然后根據樣圖效果嘗試確定五方面內容:

          1、之前確立的布局在放入設計內容后是否依然合適

          2、確立的圖表類型帶入數據后是否仍然客觀準確

          3、根據關鍵元素、色彩、結構、質感打造出的頁面風格是否基本傳達出了預期的氛圍和感受

          4、已有的樣式、數據內容、動效等在開發實現方面是否存在問題

          5、大屏是否存在色差、文字內容是否清晰可見、頁面是否存在變形拉伸等現象


          跟大屏“溝通”是比較重要也是個特殊的環節,這也是我覺得大屏設計跟其它設計不一樣的地方,大屏有它自己獨特的分辨率、屏幕組成、色彩顯示以及運行、展示環境,這里的很多問題只有設計稿投到大屏上才能夠被發現,所以這一步在樣圖溝通確認環節非常重要,有時候需要開發出demo,反復測試多次。



          9、頁面定稿、開發


          事實上頁面開發階段并不是到了這一步才進行,這里說的頁面開發僅指前端樣式的實現,實際上后臺數據準備工作在定義好分析指標后就已經開始進行了,而我們當前的工作是把數據接入到前端,然后用設計的樣式呈現出來。

          Image title

          切圖與標注

          由于大屏實際就是一個web頁面,所以開發階段的切圖與標注是少不了的。


          切圖:哪些元素需要切圖,怎么切?

          一般開發用代碼寫不出的樣式或動效,都需要設計師切圖作支持:比如數據容器的邊框、小的動效、頁面整體大背景、部分圖標等。切圖按正常網頁設計標準切就可以了。


          標注

          Web頁面用什么插件做標注這個大家都很熟悉,我就不多說了。需要注意的是,如果大屏頁面需要在不同比例的終端展示,那么此時的標注與開發可以使用rem作為基本單位來實現,這樣實現的大屏頁面在后期會有更好的擴展性與適應性。



          10、整體細節調優與測試


          這部分是指頁面開發完成后,將真實頁面投放到大屏進行的測試與優化。這里主要有兩部分工作。


          視覺方面的測試(有點像APP的UI走查):關鍵視覺元素、字體字號、頁面動效、圖形圖表等是否按預期顯示、有無變形、錯位等情況。


          性能與數據方面的測試:圖形圖表動畫是否流暢、數據加載、刷新有無異常;頁面長時間展示是否存在奔潰、卡死等情況;后臺控制系統能否正常切換前端頁面顯示。



          四、大屏設計的注意事項


          1、字體使用


          字體優先使用系統默認字體,需要嵌入字體時考慮字體的可識別性、與當前設計風格是否融合、是否可免費商用。

          Image title

          如果頁面是云端部署,需要嵌入字體包時,我們可以使用FontCreator這類的軟件把那些用不到的字符從字體包中刪掉,然后重新打包上傳,減小字體包大小,可以優化頁面加載體驗,避免在替換默認字體的過程中出現頁面文字跳動等現象。(一般來講一套字體文件包含了阿拉伯文、符號、拉丁文、日文、西里爾文、希臘文、拼音、注音符號等多種字符,對于大屏這個明確的場景,我們可以刪掉其它使用不到的字符,僅保留中文、拼音和數字)

          Image title

          關于字體版權獲取相關問題,公眾號回復“可視化”獲取



          2、顏色搭配


           1、色彩明度與飽和度差異顯著、對比鮮明, 盡量避免使用鄰近色配色

          Image title

          2、使用深色暗色背景:深色暗色背景可減少拼縫帶來的不適感。由于背景面積大,使用暗色背景還能夠減少屏幕色差對整體表現的影響;同時暗色背景更能聚焦視覺,也方便突出內容、做出一些流光、粒子等酷炫的效果,


          3、漸變色慎重使用:大屏普遍色域有偏差,顯示偏色,因而使用漸變色需要根據大屏反饋確定是否調整,純色最佳。



          3、頁面布局

          主次分明、條理清晰、注意留白,合理利用大屏上各小的顯示單元,并盡量避免關鍵數據被拼縫分割

          Image title



          五、Q&A


          1、設計稿投到大屏上顯示效果不佳怎么辦?

          大屏的分辨率、比例、使用環境、投射方式等均會對設計造成影響。理想情況下,我們應該在設計開始前,就能打開大屏系統做一些簡單測試。我們可以從網上收集不同設計師不同風格的大屏設計作品,然后投上去查看實際效果。因為大多數時候大屏都會存在色彩偏差,這時通過測試我們就能發現漸變色、鄰近色等不同類型的色彩搭配是否可以在目標大屏上良好呈現,如果不可以,那我們設計進行時就不要使用顯示效果不佳的色彩搭配。另一方面,樣圖溝通環節及時測試也很重要。



          2、大屏設計定稿后,切圖切幾倍圖?

          由于是將我們電腦屏幕投射到了大屏,大屏上的內容是運行在我們電腦瀏覽器上的頁面。所以切圖根據我們電腦的分辨率,正常切1倍圖就可以



          3、1920*1080的設計稿,投到9000*4320的屏幕上,文字圖片會發虛么?

          看情況,視大屏系統硬件規格與觀看距離來定。這塊有四個概念需要跟大家交流下。

          大屏邏輯分辨率(設計稿尺寸)——顯卡輸出分辨率——視頻矩陣切換器(DVI)支持分辨率——大屏實際物理分辨率。


          一般后兩個是沒問題的,大屏跟矩陣切換器是由大屏廠商提供,一般剛好配套大屏。容易問題的是顯卡輸出分辨率,我們電腦屏幕分辨率并不是最終顯卡傳遞到DVI接口的分辨率,傳遞到DVI接口的分辨率是電腦顯卡所能輸出的最大分辨率(部分電腦可設置或自定義輸出分辨率)。輸出分辨率等于DVI支持分辨率時顯示效果最佳。輸出分辨率低于DVI支持分辨率,DVI會將信號放大后傳遞到大屏,放大的過程中就有圖像信息丟失,雖然此過程中有各種算法支持去保證圖像盡可能清晰,但算法再好,跟真實圖形還是有差距的。此外,多信號源投射效果優于單個信號源投射。對于現場直播數據大屏,一般至少有兩個信號源,一個投屏,另一個也投屏但是處于備用狀態。


          離大屏的距離也影響觀感,一般離得近,顆粒感明顯,距離稍遠,會顯的較為清晰



          4、設計稿完成開發后,發現在大屏上頁面有被拉伸或者壓縮的情況,怎么補救?

          一般來講,開發只需要對設計圖做還原即可。但特殊情況下,比如顯示器擴展不正確導致頁面被拉伸或壓縮,這時就需做處理:我們可以先得到被拉伸/壓縮的比例,然后對整體視圖做壓縮/拉伸處理,再由其拉伸/壓縮,這樣被拉伸/壓縮的瑕疵就可以得到一定程度上的矯正。另外,了解被投電腦硬件特點,有的電腦可以通過自定義分辨率解決這部分問題。



          5、除自行開發可視化大屏外,還可以通過哪些第三方服務來快速實現?

          阿里云DataV、騰訊云圖、百度Sugar等



          6、數據可視化的圖表樣式可以在那些地方找到參考?

          圖表部分的二個庫是我們設計師可以打開瀏覽產看的,這里面所有的圖表樣式都是基于代碼實現的,可以作為我們設計圖表的參考,也可以讓開發拿代碼去用,或者在這些圖表的基礎修改

          工具類的需要有一定的代碼基礎,里面同樣有豐富的圖表,所以跟開發的溝通也很重要,因為他們可能會了解多一些更新的前沿的圖表形式是我們設計師不知道的,所以彼此多溝通交流是在太重要了

          Image title


          總結:數據可視化是一門龐大系統的科學,本文所有討論僅針對大屏數據可視化這一特定領域,管中窺豹,如有遺漏或不足之處歡迎大家討論交流

          轉自UI中國-BYMD


          交互設計師常用的設計理論與心理學

          鶴鶴

          掌握好常用的設計理論與心理學知識,能幫助我們對用戶的人性特征的拿捏,幫助我們較大的影響用戶底層決策,以產品實現業務目標。

          一、尼爾森10大可用性原則


          1、狀態可見原則

          不局限于:用戶的當前狀態、知道當前任務要做什么、任務進度等。

          2、環境貼切原則

          設計要復合目標用戶的認知,符合用戶的心智模型,于是熟悉的事物越容易被用戶所接受。

          3、撤銷重做原則

          操作前可預知,操作中有反饋、操作后可撤銷。

          4、一致性原則

          不局限于:業內產品的一致性、產品內的一致性、版本迭代間的一致性

          5、防錯原則

          錯誤行動發生前,引導用戶向正確的方向前進;用戶觸碰到危險操作時給予提示;危險操作發生之后,提供撤回的入口。

          6、易取原則

          通過使用對象、動作和選項的可視化表達,最大限度地減輕用戶的記憶負擔。

          記住用戶的操作記錄、一個流程對應一個操作目標、提供適量的信息、選擇而不是輸入。

          7、靈活原則

          好的產品需要同時兼顧新用戶和資深用戶的需求。對新用戶來說,需要功能明確、清晰,對于老用戶需要快捷使用高頻功能。不可迎合某一種用戶,把不必要的信息占據重要部分。

          8、易掃(讀)原則

          不要包含不相關或低頻次的信息/操作。頁面中的每個額外信息都會降低主要內容的相對可見性。

          產品設計的四大基本原則:親密性、對齊、重復、對比。

          9、容錯原則

          錯誤信息應該用通俗易懂的語言表達,較準確地指出問題,并且提出解決方案。避免通過代碼等用戶難以理解的形式

          即:提供解決方案、幫助用戶從錯誤中恢復

          10、人性化幫助

          如果系統能讓用戶不需要閱讀文檔就會使用那是最好的,但通常情況下還是需要幫助文檔的。任何信息應該容易被搜索,且專注于用戶的目標任務,并列出具體的步驟來告知用戶。


          二、費茨定律

          翻譯成人話就是:

          1. 按鈕做大點(W大點)更易于點擊

          2. 將按鈕放置在離開始點較近的地方

          3. 相關按鈕之間距離近點(D小點)更易于點擊

          4. 屏幕的四角與四邊是「無限可選中」位置(非移動端)

          5. 通過費茨定律的反向使用,可以降低按鈕被點擊的可能


          三、米勒定律


          米勒定律預測人的工作記憶能夠記住的項為7(±2)個。1956年認知心理學家喬治·米勒發表了一篇論文,他討論了短期記憶和記憶跨度的極限。

          不要亂用 “神奇的7” 為設計進行不必要的限制;

          將內容整理為較小的單元,以便用戶輕松地處理、理解和記憶。


          比如電話號碼的顯示方式、銀行卡的顯示方式等


          四、接近法則


          觀察者看到彼此鄰近(空間或時間)的物體時,會將它們視為一個整體。

          在界面設計中,對信息的組織已經離不開這個法則了,他在界面中所體現的就是把相關的信息塊組合在一起,不太相關的分離開,增強與區分元素之間的關聯性,所強調的是空間和位置。

          接近法則產生于群組,它可以減少信息設計的復雜性,對引導用戶的視覺流、便于用戶對界面的解讀起到至關重要的作用。


          五、席克定律


          ??硕墒且环N心理物理學定律。用戶所面臨的選擇數量越多,做出選擇所花費的時間就越長,在人機交互的界面中選項越多,意味著用戶做出決策的時間越長。


          六、泰斯勒定律(復雜性守恒定律)


          泰斯勒定律又稱復雜性守恒定律,該定律認為每一個過程都有其固有的復雜性,這個復雜性存在一個臨界點,超過了這個點就不能再簡化了,你只能將固有的復雜性從一個地方移動到另外一個地方。


          七、奧卡姆剃刀原理


          奧卡姆剃刀原理的核心思想為:“切勿浪費較多東西去做用較少東西同樣可以做好的事——如無必要,勿增實體,即簡單有效原理”。


          八、防錯原則


          操作前有提示,操作中有反饋、操作后可撤銷。


          九、損失厭惡


          損失厭惡是指人們面對同樣數量的收益和損失時,認為損失更加令他們難以忍受。同量的損失帶來的負效用為同量收益的正效用的2.5倍。損失厭惡反映了人們的風險偏好并不是一致的,當涉及的是收益時,人們表現為風險厭惡;當涉及的是損失時,人們則表現為風險尋求。


          十、安慰劑效應


          “安慰劑效應”指的是,對于某種無效的療法或干預手段,僅僅是“相信它有效”,就能改善健康,并能改變認知


          十一、多爾蒂門檻


          研究結果表明,計算機的響應速度直接影響了使用者做出下一個決定所要花費的時間(這個時間被稱為用戶響應時間),換句話說,計算機相應的時間越長,用戶就要花費越多的時間來思考和決定下一步的操作。


          合理的操作響應時長、方式有助于用戶保持專注和提率。

          軟件操作的過度動畫時間不宜太短或太長,最常見于 400ms 左右。

          如果無法避免操作中較長讀取、等待時間,那么就用其他更有趣的動畫、頁面來減少用戶的焦慮感。


          十二、馬斯洛需求層次理論


          馬斯洛需求層次理論是人本主義科學的理論之一,由美國心理學家亞伯拉罕?馬斯洛在1943年在《人類動機理論》論文中所提出。書中將人類需求像階梯一樣從低到高按層次分為五種,從低到高依次是:生理需求、安全需求、社交需求、尊重需求和自我實現需求。

          但最終馬斯洛添加求知需求和審美需求,自此馬斯洛需求層次理論最終定型為8層。

          十三、格式塔心理學


          格式塔原則描述了當某些條款和條件被應用時,人類大腦如何感知視覺成分。它幫助大腦創造視覺的意象。因此,格式塔原則基于六個主要類別:

          位置和位置;

          接近;

          對稱與秩序;

          類似;

          關閉;

          連續性。


          十四、自我參照效應


          第一種是精細加工說:在記憶過程中,這些事物在頭腦中被進行了精細加工,與頭腦中的已有知識之間建立了更多的聯系,因此回憶時的提示線索更多,回憶效果更好。

          第二種是組織加工說:于自我的知識是頭腦中存在的一種結構良好的組織體系,它對與自己相關的事物有更好的固著作用;同時,由于自我知識常常被激活,因此與之相關的信息也更容易被相應地激活起來,這樣回憶起來也就更容易。

          第三種是雙過程說:即自我參照任務能提高記憶的機制既包括精細加工因素,也有組織作用的參與

          廣告商會挖空心思的建立商品和你的關聯,告知我們如果你購買了我的商品,你就會獲得怎樣的好處。而自媒體人則在標題上盡量簡明扼要的說明,我要說的事情和你密切相關,不看就虧了。所以,稍微有深度的文章在快餐式的自媒體平臺中反而閱讀量不高,這是因為文章標題所涵蓋的內容可能只和少部分人有關。


          十五、上癮模型


          1、觸發:提醒人們采取下一步行動


          觸發分為外部觸發與內部觸發

          外部觸發又分為:

          付費型觸發、回饋型觸發、人際型觸發、自主型觸發。

          內部觸發

          內部觸發通過用戶記憶存儲中的各種關聯來提醒他們采取下一步行動。

          比如餓了的時候想起餓了么,想健身的時候想起keep


          2、行動:人們在期待酬賞時的直接反應


          福格行為模型可以用公式來呈現,即B=MAT。B代表行為,M代表動機,A代表能力,T代表觸發。要想使人們完成特定的行為,動機、能力、觸發這三樣缺一不可。 否則,人們將無法跨過“行動線”,也就是說,不會實施某種行為。

          比如說中午十一點你餓了想到餓了么訂餐但是由于你的手機沒電了定不了餐,中午要吃飯是動機,訂餐想到叫餓了么外賣是觸發,能夠用手機訂餐是能力,但是因為手機沒有電 你就缺乏了相應的能力所以這個行為就沒法完成。(當然你也能用朋友的手機訂餐,這里只是舉個例子)


          福格總結了簡潔性所包含的6個元素 ,即影響任務難易程度的6個要素,它們是:


          • 時間——完成這項活動所需的時間。

          • 金錢——從事這項活動所需的經濟投入。

          • 體力——完成這項活動所需消耗的體力。

          • 腦力——從事這項活動所需消耗的腦力。

          • 社會偏差——他人對該項活動的接受度。

          • 非常規性——按照福格的定義,“該項活動與常規活動之間的匹配程度或矛盾程度”。


          四種非常規的效應刺激動機:


          • 稀缺效應:(限量1000件)

          • 環境效應:(同一款啤酒在便利店和高檔就把價格不一,但人們愿意為價格買單)

          • 錨定效應:(瑞幸咖啡定價24元的拿鐵對標星巴克的32元拿鐵)

          • 贈券效應:(利益進度吸引用戶動機)


          3、多變的酬賞:滿足用戶的需求,激發使用欲


          多變性會使大腦中的伏隔核更加活躍,并且會提升神經傳遞素多巴胺的含量,促使我們對酬賞產生迫切的渴望。 研究測試表明,當賭博者贏了錢,或是異性戀男性看到美女的圖片時,大腦伏隔核中的多巴胺含量會上升。

          多變的酬賞主要表現為三種形式:社交酬賞、獵物酬賞、自我酬賞。那些讓我們欲罷不能的習慣養成類產品或多或少都利用了這幾類酬賞。


          社交酬賞

          所謂社交酬賞,是指人們從產品中通過與他人的互動而獲取的人際獎勵。比如微信的點贊評論、站酷的推薦,用戶能夠獲得社交的認同。


          獵物酬賞

          獵物酬賞,是指人們從產品中獲得的具體資源或信息。


          自我酬賞

          所謂自我酬賞,是指人們從產品中體驗到的操控感、成就感和終結感。


          4、投入:通過用戶對產品的投入,培養忠實用戶


          要想讓用戶產生心理聯想并自動采取行動,首先必須讓他們對產品有所投入。


          用戶對某件產品或某項服務投入的時間和精力越多,對該產品或服務就越重視。事實上,有充分證據表明,用戶投入的多寡與其熱愛某項事物的程度成正比。


          1、文飾效應心理


          (1)我們總是高估自己的勞動成果。

          (2)我們總是盡力和過去保持行為一致。

          (3)我們總是避免認知失調。


          2、點滴投入


          (1)儲存價值

          (2)內容

          (3)數據資料

          (4)關注者

          (5)信譽

          (6)技能


          3、加載下一個觸發


          用戶投入的同時也可以通過加載下一個觸發的令自己重新開始上癮循環,從而增加了進入上癮循環的可能性。


          十六、雅各布定律


          雅各布定律(簡稱雅各布互聯網用戶體驗法則),它指出如果用戶已將大部分時間花費在某個網站上,那么他們會希望你的網站可以與那些他們已熟悉的網站一樣擁有相似的使用模式。


          我們在與新事物互動的過程中,用戶使用的是以往的經驗


          對設計師來說,我們可以匹配用戶的心智模型來改善體驗。因此,用戶可以輕松地將已有經驗從一種產品或體驗轉移到另一種上,無需額外了解新系統的工作原理。

          當設計師與用戶的心智模型一致時,良好的用戶體驗就得以實現。


          十七、KANO模型


          KANO模型大家可以看看這個童鞋的總結很詳細

          https://www.zcool.com.cn/article/ZMTAyMjQ3Mg==.html


          十八、古藤堡表圖表法


          人們在瀏覽頁面或布局時視線趨于從左上角移動到右下角

          古騰堡圖表法說明我們觀看頁面的視線并不是鏡面對稱的,我們需要在設計中避免出現此類錯誤但絕不是墨守成規,將頁面的 Logo放置在左上角而主體向右下角延伸,左下和右上作為視覺的盲點可以添加輔助元素


          十九、尼爾森F型視覺模型


          尼爾森F型視覺模型由 Jakob Nielsen于2006年提出

          他指出,我們在第一次觀看頁面時,視線會呈 F的形狀關注頁面。
          1.先從頂部開始從左到右水平移動。
          2.目光再下移開始從左到右觀察但是長度會相對短些。
          3.以較短的長度向下掃視,形成一個 F形狀,此時我們的閱讀速度較慢,更為系統和條理性。


          二十、序列效應


          1.在列舉信息時,排在最前和最后的元素,比排在中間的更容易讓人記住。

          2.對排在開頭的信息產生加強的回想效果,稱為:初始效應,人們有時候會把最前面的信息儲存在長期記憶中。排在結尾的信息產生加強的回想效果,稱為:時近效應。時近效應適用于聽覺刺激。初始效應適用于視覺刺激。

          3.在列舉信息元素時,如果列舉信息屬于視覺性,那么把重要的信息放在最前面;如果是聽覺性,就放在最后面。如果是用戶必須做決定,并且是最后一項出現后馬上做決定,那么就將想要用戶做決定的信息放置最后,以便增加獲選概率,否則放在最前面。

          4. 應用例子:比如在很多app產品設計時,個人賬戶與設置基本放在頁面的最前面和最后面,這體現著產品信息的序列關系,重要次序,所以在進行設計時,可以在信息排序上遵循序列效應。 當然還有一些產品想對用戶進行引導操作,也可以利用這個法則,將信息放置最前或最后。

          轉自:站酷-YELLOW_J 

          啥?你說我不懂如何設計消息中心?

          鶴鶴

          消息中心設計樣式的簡單匯總

          作為APP標配的消息中心,我們無時無刻不在與其打交道,看似千篇一律的設計實際上其中也有許多值得我們深入探討的內容,今天我們一起從消息中心頁入口出發,一層一層剝開它的秘密。


          全文分為五個部分:

          一、消息中心頁入口位置

          二、消息中心頁常見的組成模塊

          三、消息中心頁分類導航方式的選擇

          四、消息列表的呈現形式

          五、劃重點


          一、消息中心頁入口位置


          消息中心頁是應用內系統發送給用戶的各種信息的一個集合頁面,它的本質是與用戶互動溝通。也就是說,產品越是需要與用戶進行溝通,消息中心的重要程度也就越高。


          一般情況下,不同類型的APP消息中心的重要程度為:社交通訊類>電商類>資訊類>工具類


          而消息中心頁的入口位置正好側面反映了其在產品中的重要程度。


          1.底部導航欄

          消息中心頁入口位置放在底部導航欄,屬于一級導航,重要程度很高,常見于即時通訊、社交社群類產品,如下圖:

          即時通訊類的QQ,核心業務就是通訊交流,消息頁入口不僅放在底部導航欄,且做為APP的首頁。而微博作為最早的社群內容類產品,社交溝通需求也很高,固將消息中心入口放置在底部導航欄。


          當然也不是只有社交通訊類產品會選擇該位置作為消息中心的入口,如下圖淘寶和小紅書也將消息中心入口放置在底部導航欄。

          淘寶本是電商類產品,消息入口放置在底部導航欄,結合官方號、內容號、小黑群等功能,我的理解是淘寶是想通過社交溝通促使用戶更多的購物。


          小紅書主打生活內容分享,輔助電商購物,是現在比較常見的某個核心業務+社交的產品,這類產品可根據自身一級導航類別的多少決定是否將消息中心入口放置在底部導航欄。


          2.頂部導航欄

          消息中心頁入口放置在頂部導航欄,重要程度根據入口跟隨頁面的多少分成兩種情況:


          1)幾乎每頁跟隨,重要程度較高

          京東和豆瓣幾乎是每個一級頁面的頂部都有消息頁入口圖標,京東甚至在一些二級頁面也還保留了頂部消息入口,方便用戶隨時查看。


          2)僅在動態頁、首頁或個人中心頂部有入口,重要程度較低

          如上圖所示,愛奇藝的消息入口僅出現在泡泡頁面的頂部,KEEP的消息入口在個人中心頁的頂部,二者都只有一個入口。


          3.個人中心頁

          消息中心頁入口放置在個人中心頁除頂部外的區域,重要程度一般,某些APP會在個人中心消息入口直接對其分類展示,用戶能快速地到達想去的消息分類。

          波洞的消息中心入口在個人中心頁就分好了類別,用戶點擊進入對應的類別,消息頁內部沒有做類別的劃分,相比放一個消息圖標入口在個人中心頂部,更加直觀。


          入口不一定只有一個,三種情況混合使用也是可以的,重點是方便用戶,引導用戶。即便入口位置本身不顯眼,加上紅點數字后一樣會被用戶看到的。



          二、消息中心頁常見的組成模塊


          消息中心頁的主要組成模塊有:分類消息導航、消息列表;輔助組成模塊有:搜索區、全部已讀、消息設置、通訊錄等。


          1.主要的組成模塊

          消息中心的主要組成模塊中消息列表是必不可少的(有些在下一級界面中),分類消息導航根據消息類別的多少不一定都有。


          前文對消息中心的定義說過:消息中心頁是應用內系統發送給用戶的各種信息的一個集合頁面。集合頁面意味著消息本身被劃分成了各種類型,這時候適合的分類消息導航能幫助用戶快速找到需要的信息。


          消息列表引導用戶進入消息詳情頁,做為整個消息中心的核心,需要設計師根據產品需求盡可能多的考慮到囊括的信息類型,從而選擇合適的消息列表呈現形式。


          在第三部分中會著重介紹4種不同的分類消息導航,第四部分介紹3種不同的消息內容呈現形式。


          2.輔助組成模塊

          所謂輔助的組成模塊,就是不一定所有消息中心都有的,要結合產品實際情況增減。主要包括搜索區、全部已讀、消息設置、通訊錄等。

          上圖中微博的消息中心基本包括了所有的輔助組成模塊,用戶可以收發消息,設置消息,搜索消息,形成了針對消息功能的一個閉環。像微博這種消息功能重要,類別多,有社交屬性的產品加入這些輔助功能是合適的,但不適合所有產品。


          1)搜索區

          用來在消息中心頁搜索消息、聯系人、群聊等的,僅適合消息中心頁用戶之間互動頻繁的產品,如即時通訊類、聊天頻繁的社群類產品。搜索區是全局搜索的根據產品自身性能選擇加入。


          2)全部已讀/一鍵清除

          對于用戶體量不算大,消息溝通還不太頻繁的產品可以不加。但對于消息溝通頻繁的產品,不加的話,可能會逼死強迫癥......


          3)消息設置

          用來設置消息提醒方式或屏蔽消息推送,大部分產品會將此功能放入設置中避免用戶關閉消息推送,放在消息中心雖可增加用戶體驗,但也方便了用戶直接屏蔽消息。


          4)通訊錄/發起聊天

          常見在有好友通訊錄體系或關注粉絲體系的產品中。



          三、消息中心頁分類導航方式的選擇


          消息中心分類導航方式主要有四種:頂部固定圖標導航、頂部Tab導航、列表導航、頂部Tab混合導航,接下來通過分析它們各自的優缺點幫助你選擇合適的消息中心分類導航方式。


          1.頂部固定圖標導航

          頂部固定展示重要的3~5個消息類別,消息列表按照發送的時間順序依次展示。

          優點:可以突出重點消息類別。


          缺點:類別切換不方便,需要返回上一級重新進入;超過5個類別后,其他類別只能歸入消息列表中。


          2.頂部Tab導航

          頂部純文字標簽Tab導航,消息類別以標簽的形式出現,可左右切換。

          優點:切換方便,類別可拓展性強,占據空間小,為消息列表留出更多的空間,純文字標簽設計所需時間成本小。


          缺點:分類標簽不要超過9個,過多的標簽用戶切換到后面的成本較高,容易被忽略。


          3.列表導航

          消息中心列表導航有分類列表導航和混合列表導航兩種形式。


          1)分類列表導航

          分類列表導航將不同的消息類別按照icon+文字的形式從上至下展示,左側是消息類別,右側是消息未讀紅點提醒,每一個列表對應進入一種消息類別。

          優點:類別可拓展性強,分類清晰,設計簡潔明了,適合輕量、極簡風的消息中心頁。


          缺點:到達具體消息內容的路徑較長,不適合復雜的消息中心頁。


          2)混合列表導航

          消息列表與消息類別混合,按照消息發布時間順序以列表形式展示,常見于重社交、即時通訊類產品。

          優點:可拓展性極強,能容納各種類別的消息。


          缺點:消息內容太多后查找麻煩,需要配合搜索區使用,易產生閱讀疲勞。


          4.頂部Tab混合導航

          頂部Tab混合導航,進一步對消息類別細致劃分,一級Tab標簽一般會劃分為兩部分:通知及消息/私信,通知一般是產品發送的一些系統消息或推送,消息一般是用戶與用戶之間的互動消息(包括官方號的信息),私信主要是有關注粉絲體系的產品的分類。二級內容根據需要選擇進一步分類導航,如下圖:

          優點:將消息做了更細致的劃分


          缺點:有二級分類的頁面占的空間大,消息列表展示空間少。



          四、消息列表的呈現形式


          消息列表是消息中心的核心,我們需要根據內容類型的不同選擇合適的呈現形式,便于用戶理解。主要的呈現形式有3種,分別是:icon/頭像+縮略內容列表、圖文列表、純文字列表。


          1.icon/頭像+縮略內容列表

          最常見的一種消息列表,以icon或頭像+縮略內容的形式展示,符合從左到右的瀏覽習慣,能承載多種類型的消息,包括對話聊天類、訂閱號、官方活動、系統通知等等,需要引入下一級頁面展示消息詳情。適合大部分的產品。


          2.圖文列表

          消息列表采用圖文形式,對用戶更具吸引力,一般用在消息類別比較單一的消息中心。常見的有上圖下文卡片(大圖)和左圖右文的展現形式。需要注意的是上圖下文(大圖)的展現形式對圖片質量要求較高。常用在活動消息、資訊消息。


          3.純文字列表

          消息列表以純文字形式展示,形式較單一,能展示較多的文字信息,常見于通知消息。



          五、劃重點


          本文主要通過消息入口位置、消息中心頁組成、消息中心頁分類導航選擇、消息列表呈現形式介紹了消息中心頁的設計。


          消息中心頁入口:底部導航欄、頂部導航欄、個人中心頁


          消息中心頁組成模塊:分類消息導航、消息列表;、搜索區、全部已讀、消息設置、通訊錄。


          消息中心頁分類導航:頂部固定圖標導航、頂部Tab導航、列表導航、頂部Tab混合導航。


          消息列表的呈現形成:icon/頭像+縮略內容列表、圖文列表、純文字列表。

          轉自:站酷-人類君 

          小程序入門到精通:了解小程序開發4個重要文件

          前端達人

          點擊查看原圖


          1. 小程序沒有DOM對象,一切基于組件化

          2. 小程序的四個重要的文件

          • *.js —> view邏輯 —> javascript
          • *.wxml —> view結構 ----> html
          • *.wxss —> view樣式 -----> css
          • *. json ----> view 數據 -----> json文件

          注意:為了方便開發者減少配置項,描述頁面的四個文件必須具有相同的路徑與文件名。

          2.1 WXML

          WXML(WeiXin Markup Language)是框架設計的一套標簽語言,結合基礎組件、事件系統,可以構建出頁面的結構。WXML 充當的就是類似 HTML 的角色
          要完整了解 WXML 語法,請參考WXML 語法參考。

          2.2 WXSS

          WXSS (WeiXin Style Sheets)是一套樣式語言,用于描述 WXML 的組件樣式。

          WXSS 用來決定 WXML 的組件應該怎么顯示。

          為了適應廣大的前端開發者,WXSS 具有 CSS 大部分特性。同時為了更適合開發微信小程序,WXSS 對 CSS 進行了擴充以及修改。

          與 CSS 相比,WXSS 擴展的特性有:



          尺寸單位

          樣式導入

          2.3 json

          JSON 是一種數據格式,并不是編程語言,在小程序中,JSON扮演的靜態配置的角色。



          全局配置

          小程序根目錄下的 app.json 文件用來對微信小程序進行全局配置,決定頁面文件的路徑、窗口表現、設置網絡超時時間、設置多 tab 等。



          頁面配置

          每一個小程序頁面也可以使用同名 .json 文件來對本頁面的窗口表現進行配置,頁面中配置項會覆蓋 app.json 的 window 中相同的配置項。



          工具配置 project.config.json

          通常大家在使用一個工具的時候,都會針對各自喜好做一些個性化配置,例如界面顏色、編譯配置等等,當你換了另外一臺電腦重新安裝工具的時候,你還要重新配置。

          考慮到這點,小程序開發者工具在每個項目的根目錄都會生成一個 project.config.json,你在工具上做的任何配置都會寫入到這個文件,當你重新安裝工具或者換電腦工作時,你只要載入同一個項目的代碼包,開發者工具就自動

          注意:

          JSON文件都是被包裹在一個大括號中 {},通過key-value的方式來表達數據。JSON的Key必須包裹在一個雙引號中,在實踐中,編寫 JSON 的時候,忘了給 Key 值加雙引號或者是把雙引號寫成單引號是常見錯誤。

          JSON的值只能是以下幾種數據格式,其他任何格式都會觸發報錯,例如 JavaScript 中的 undefined。



          數字,包含浮點數和整數

          字符串,需要包裹在雙引號中

          Bool值,true 或者 false

          數組,需要包裹在方括號中 []

          對象,需要包裹在大括號中 {}

          Null

          還需要注意的是 JSON 文件中無法使用注釋,試圖添加注釋將會引發報錯。


          2.4 js

          一個服務僅僅只有界面展示是不夠的,還需要和用戶做交互:響應用戶的點擊、獲取用戶的位置等等。在小程序里邊,我們就通過編寫 JS 腳本文件來處理用戶的操作。


          注冊頁面

          對于小程序中的每個頁面,都需要在頁面對應的 js 文件中進行注冊,指定頁面的初始數據、生命周期回調、事件處理函數等



          使用 Page 構造器注冊頁面

          簡單的頁面可以使用 Page() 進行構造。



          使用 Component 構造器構造頁面

          Page 構造器適用于簡單的頁面。但對于復雜的頁面, Page 構造器可能并不好用。

          此時,可以使用 Component 構造器來構造頁面。 Component 構造器的主要區別是:方法需要放在 methods: { } 里面。

          ————————————————

          版權聲明:本文為CSDN博主「前端嵐楓」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。

          原文鏈接:https://blog.csdn.net/yilanyoumeng3/java/article/details/106292742





          2020年,令人驚嘆的Echarts!

          前端達人

          點擊查看原圖


          1.可視化面板介紹

          應對現在數據可視化的趨勢,越來越多企業需要在很多場景(營銷數據,生產數據,用戶數據)下使用,可視化圖表來展示體現數據,讓數據更加直觀,數據特點更加突出。

          01-技術要點

          1. div + css 布局
          2. flex 布局
          3. Less
          4. 原生js + jquery 使用
          5. rem適配
          6. echarts基礎

          02-案例適配方案

          1. 設計稿是1920px
          2. flexible.js 把屏幕分為 24 等份
          3. cssrem 插件的基準值是 80px
            插件-配置按鈕—配置擴展設置–Root Font Size 里面 設置。
            但是別忘記重啟vscode軟件保證生效


          03-頁面主體布局

          1. header布局
          2. mainbox布局
          3. 公共面板模塊 panel
          4. 柱形圖 bar
          因為我們今天的主題是echarts部分所以前面的這些,我就為大家寫好框架,里面的布局相信以大家的能力都是分分鐘解決的事情。


          2.Echarts(重點)

          echarts介紹

          常見的數據可視化庫:

          D3.js 目前 Web 端評價最高的 Javascript 可視化工具庫(入手難)
          ECharts.js 百度出品的一個開源 Javascript 數據可視化庫
          Highcharts.js 國外的前端數據可視化庫,非商用免費,被許多國外大公司所使用
          AntV 螞蟻金服全新一代數據可視化解決方案 等等
          Highcharts 和 Echarts 就像是 Office 和 WPS 的關系

          ECharts,一個使用 JavaScript 實現的開源可視化庫,可以流暢的運行在 PC 和移動設備上,兼容當前絕大部分瀏覽器(IE8/9/10/11,Chrome,Firefox,Safari等),底層依賴矢量圖形庫 ZRender,提供直觀,交互豐富,可高度個性化定制的數據可視化圖表。

          官網地址:https://www.echartsjs.com/zh/index.html

          echarts體驗
          下載echarts https://github.com/apache/incubator-echarts/tree/4.5.0

          使用步驟(5大步驟):
          1.引入echarts 插件文件到html頁面中
          2.準備一個具備大小的DOM容器

          <div id="main" style="width: 600px;height:400px;"></div>

          3.初始化echarts實例對象

          var myChart = echarts.init(document.getElementById('main'));

          4.指定配置項和數據(option)

          var option = {
              xAxis: {
                  type: 'category',
                  data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
              },
              yAxis: {
                  type: 'value'
              },
              series: [{
                  data: [820, 932, 901, 934, 1290, 1330, 1320],
                  type: 'line'
              }]
          };

          5.將配置項設置給echarts實例對象


          myChart.setOption(option);  
          


          echarts基礎配置

          這是要求同學們知道以下配置每個模塊的主要作用干什么的就可以了

          series

          系列列表。每個系列通過 type 決定自己的圖表類型

          大白話:圖標數據,指定什么類型的圖標,可以多個圖表重疊。

          xAxis:直角坐標系 grid 中的 x 軸

          boundaryGap: 坐標軸兩邊留白策略 true,這時候刻度只是作為分隔線,標簽和數據點都會在兩個刻度之間的帶(band)中間。

          yAxis:直角坐標系 grid 中的 y 軸

          grid:直角坐標系內繪圖網格。

          title:標題組件

          tooltip:提示框組件

          legend:圖例組件

          color:調色盤顏色列表

          數據堆疊,同個類目軸上系列配置相同的stack值后 后一個系列的值會在前一個系列的值上相加。



          option = {

              // color設置我們線條的顏色 注意后面是個數組

              color: ['pink', 'red', 'green', 'skyblue'],

              // 設置圖表的標題

              title: {

                  text: '折線圖堆疊123'

              },

              // 圖表的提示框組件 

              tooltip: {

                  // 觸發方式

                  trigger: 'axis'

              },

              // 圖例組件

              legend: {

                 // series里面有了 name值則 legend里面的data可以刪掉

              },

              // 網格配置  grid可以控制線形圖 柱狀圖 圖表大小

              grid: {

                  left: '3%',

                  right: '4%',

                  bottom: '3%',

                  // 是否顯示刻度標簽 如果是true 就顯示 否則反之

                  containLabel: true

              },

              // 工具箱組件  可以另存為圖片等功能

              toolbox: {

                  feature: {

                      saveAsImage: {}

                  }

              },

              // 設置x軸的相關配置

              xAxis: {

                  type: 'category',

                  // 是否讓我們的線條和坐標軸有縫隙

                  boundaryGap: false,

                  data: ['星期一', '周二', '周三', '周四', '周五', '周六', '周日']

              },

               // 設置y軸的相關配置

              yAxis: {

                  type: 'value'

              },

              // 系列圖表配置 它決定著顯示那種類型的圖表

              series: [

                  {

                      name: '郵件營銷',

                      type: 'line',

                     

                      data: [120, 132, 101, 134, 90, 230, 210]

                  },

                  {

                      name: '聯盟廣告',

                      type: 'line',



                      data: [220, 182, 191, 234, 290, 330, 310]

                  },

                  {

                      name: '視頻廣告',

                      type: 'line',

                    

                      data: [150, 232, 201, 154, 190, 330, 410]

                  },

                  {

                      name: '直接訪問',

                      type: 'line',

                    

                      data: [320, 332, 301, 334, 390, 330, 320]

                  }

              ]

          };



          3.Echarts快速使用

          1.官網實例

          點擊查看原圖



          官網默認為我們提供了大量的案例,我們需要使用那一種只需要直接點擊打開后復制他們的相關配置,然后按照我上面說的5大步驟進行使用即可。

          2.社區Gallery

          點擊查看原圖



          官方自帶的圖例,可能在很多時候并不能滿足我們的需要,在社區這里可以找到一些基于echart的高度定制好的圖表,相當于基于jquery開發的插件,這里是基于echarts開發的第三方的圖表。

          本案例中使用了地圖模擬飛行的案例就是從社區中進行引用的,
          參考社區的例子:https://gallery.echartsjs.com/editor.html?c=x0-ExSkZDM (模擬飛機航線)
          實現步驟:

          第一需要下載china.js提供中國地圖的js文件
          第二個因為里面代碼比較多,我們新建一個新的js文件 myMap.js 引入
          使用社區提供的配置即可。
          代碼已經上傳至我的碼云如有需要的小伙伴可自行下載:
          https://gitee.com/jiuyueqi/echarts

          ps:最后呢,如果大家看完樓主的文章覺得對echarts的學習和了解有所幫助,麻煩大家路過點個贊點個關注唄!樓主后續還會繼續更新有關前端方面的面試題資料或者其他方面的知識。
          ————————————————
          版權聲明:本文為CSDN博主「程序猿玖月柒」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
          原文鏈接:https://blog.csdn.net/weixin_45257157/java/article/details/106300587

          關于JavaScript獲取時間函數及實現倒計時

          前端達人

          JavaScript數組對象的迭代方法詳解

          上一篇博客講到了數組的方法,當然里邊比較復雜的就是數組的迭代方法,因為涉及到了回調函數,所以這篇博客我們來詳細講解一下js數組迭代方法的使用。


          1.forEach(funcrion(value,index,arr){}):對數組的每一項運行給定函數,這個方法不進行返回,所以一般用于讓數組循環執行某方法。

            var arr=[1,2,3,4,5,6];

              arr.forEach(function(val,index,arr){

                  console.log(val,index,arr);

              })

              // 其中:

              // value:每一個數組項的值 必填項

              // index:每一個數組項對應的索引

              // arr:當前的數組


          注意:forEach()方法不返回值,所以回調函數中使用return會打印出來undefined。

          2.map(funcrion(value,index,arr){}):對數組的每一項運行給定函數,它將返回執行函數后的結果組成的新數組。

           var aNum2 = [1.2, 1.8, 2.0, 4.3];

              console.log(aNum2.map(Math.floor()));// [1,1,2,4]

              

              var arr=[1,2,3];

              console.log(arr.map(function(val,index){

                  return val*3

              }));// 3 6 9

              // 其中:

              // value:每一個數組項的值 必填項

              // index:每一個數組項對應的索引

              // arr:當前的數組

          注意:map()方法有返回值,返回值為新的數組,所以可以直接再回調函數中return。

          3.every(funcrion(value,index,arr){}):對數組的每一項都運行給定函數,進項判斷,若對于每項執行函數都返回了true,則其結果為true。

           var arr=[10,20,30];

              console.log(arr.every(function(val){

                  return val>20;

              }));// false

              

              console.log(arr.every(function(val){

                  return val>0;

              }));// true

              

              // 其中:

              // value:每一個數組項的值 必填項

              // index:每一個數組項對應的索引

              // arr:當前的數組



          注意:every()方法所有的數組項都符合判斷時返回true,否則返回false。

          4.some(funcrion(value,index,arr){}):對數組的每一項都運行給定函數,進行判斷,若存在一項符合條件的數組項,則其結果為true。

              var arr=[10,20,30];

              console.log(arr.some(function(val){

                  return val>20;

              }));// true

              

              console.log(arr.some(function(val){

                  return val>0;

              }));// true

              

              console.log(arr.some(function(val){

                  return val<0;

              }));// false

              

              arr.some(function(val){

                  console.log(val<0);

              });//fasle false false

              // 其中:

              // value:每一個數組項的值 必填項

              // index:每一個數組項對應的索引

              // arr:當前的數組


          注意:some()方法如果回調函數執行完會根據結果返回true或false,但是回調函數中打印判斷是,只會作為判斷條件的返回值,則會打印多遍。

          5.fliter(funcrion(value,index,arr){}):對數組的每一項都運行給定函數,進行過濾,將符合條件的數組項添加到新的數組中,并返回新的數組。

             var aNum=[1,2,3,4];
              console.log(aNum.filter(function (num) {
                  return num > 1;
              }));//[2,3,4,]
              aNum.filter(function (num) {
                  console.log(num > 1);//true true true
              })

          注意:filter()方法對數組項進行過濾,然后將符合條件的數組項添加到一個新的數組并返回,但是如果直接打印這個判斷條件,相當于打印的判斷條件的結果,只會返回true或者false。

          6.ES6中新增的迭代方法

          1.find():返回第一個符合傳入測試(函數)條件的數組元素。


            var aNum=[10,20,30,40];

              console.log(aNum.find(function (num) {

                  return num > 19;

              }));//1

              console.log(aNum.find(function (num) {

                  return num < 0;

              }));//undefined



          2.findIndex():返回符合傳入測試(函數)條件的數組元素索引。


          console.log(aNum.findIndex(function (num) { return num > 19; }));//3


          3.includes():判斷一個數組是否包含一個指定的值。

          總結:

          forEach()與map()是一對,用于數組遍歷執行指定函數,前者不返回數組,后者返回 處理過的新數組。
          every()與some()是一對,分別適用于檢測數組是否全部滿足某條件或者存在滿足的數組項,返回true或false。
          filter()則是相當于過濾器的存在,過濾掉數組中不符合條件的數據,將符合條件的數組項添加到新數組,并返回。
          ————————————————
          版權聲明:本文為CSDN博主「Mr_Han119」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
          原文鏈接:https://blog.csdn.net/qq_39155611/java/article/details/106294417


          了不起的 tsconfig.json 指南

          seo達人

          在 TypeScript 開發中,tsconfig.json 是個不可或缺的配置文件,它是我們在 TS 項目中最常見的配置文件,那么你真的了解這個文件嗎?它里面都有哪些優秀配置?如何配置一個合理的 tsconfig.json 文件?本文將全面帶大家一起詳細了解 tsconfig.json 的各項配置。



          本文將從以下幾個方面全面介紹 tsconfig.json 文件:

          了不起的 tsconfig.json 指南.png




          水平有限,歡迎各位大佬指點~~


          一、tsconfig.json 簡介


          1. 什么是 tsconfig.json

          TypeScript 使用 tsconfig.json 文件作為其配置文件,當一個目錄中存在 tsconfig.json 文件,則認為該目錄為 TypeScript 項目的根目錄。

          通常 tsconfig.json 文件主要包含兩部分內容:指定待編譯文件和定義編譯選項。



          從《TypeScript編譯器的配置文件的JSON模式》可知,目前 tsconfig.json 文件有以下幾個頂層屬性:


          compileOnSave

          compilerOptions

          exclude

          extends

          files

          include

          references

          typeAcquisition


          文章后面會詳細介紹一些常用屬性配置。



          2. 為什么使用 tsconfig.json

          通常我們可以使用 tsc 命令來編譯少量 TypeScript 文件:


          /*

           參數介紹:

           --outFile // 編譯后生成的文件名稱

           --target  // 指定ECMAScript目標版本

           --module  // 指定生成哪個模塊系統代碼

           index.ts  // 源文件

          */

          $ tsc --outFile leo.js --target es3 --module amd index.ts

          但如果實際開發的項目,很少是只有單個文件,當我們需要編譯整個項目時,就可以使用 tsconfig.json 文件,將需要使用到的配置都寫進 tsconfig.json 文件,這樣就不用每次編譯都手動輸入配置,另外也方便團隊協作開發。



          二、使用 tsconfig.json

          目前使用 tsconfig.json 有2種操作:


          1. 初始化 tsconfig.json

          在初始化操作,也有 2 種方式:


          手動在項目根目錄(或其他)創建 tsconfig.json 文件并填寫配置;

          通過 tsc --init 初始化 tsconfig.json 文件。


          2. 指定需要編譯的目錄

          在不指定輸入文件的情況下執行 tsc 命令,默認從當前目錄開始編譯,編譯所有 .ts 文件,并且從當前目錄開始查找 tsconfig.json 文件,并逐級向上級目錄搜索。


          $ tsc

          另外也可以為 tsc 命令指定參數 --project 或 -p 指定需要編譯的目錄,該目錄需要包含一個 tsconfig.json 文件,如:


          /*

           文件目錄:

           ├─src/

           │  ├─index.ts

           │  └─tsconfig.json

           ├─package.json

          */

          $ tsc --project src

          注意,tsc 的命令行選項具有優先級,會覆蓋 tsconfig.json 中的同名選項。



          更多 tsc 編譯選項,可查看《編譯選項》章節。



          三、使用示例

          這個章節,我們將通過本地一個小項目 learnTsconfig 來學著實現一個簡單配置。

          當前開發環境:windows / node 10.15.1 / TypeScript3.9



          1. 初始化 learnTsconfig 項目

          執行下面命令:


          $ mkdir learnTsconfig

          $ cd .\learnTsconfig\

          $ mkdir src

          $ new-item index.ts

          并且我們為 index.ts 文件寫一些簡單代碼:


          // 返回當前版本號

          function getVersion(version:string = "1.0.0"): string{

             return version;

          }


          console.log(getVersion("1.0.1"))

          我們將獲得這么一個目錄結構:


           └─src/

              └─index.ts


          2. 初始化 tsconfig.json 文件

          在 learnTsconfig 根目錄執行:


          $ tsc --init


          3. 修改 tsconfig.json 文件

          我們設置幾個常見配置項:


          {

           "compilerOptions": {

             "target": "ES5",             // 目標語言的版本

             "module": "commonjs",        // 指定生成代碼的模板標準

             "noImplicitAny": true,       // 不允許隱式的 any 類型

             "removeComments": true,      // 刪除注釋

             "preserveConstEnums": true,  // 保留 const 和 enum 聲明

             "sourceMap": true            // 生成目標文件的sourceMap文件

           },

           "files": [   // 指定待編譯文件

             "./src/index.ts"  

           ]

          }

          其中需要注意一點:

          files 配置項值是一個數組,用來指定了待編譯文件,即入口文件。

          當入口文件依賴其他文件時,不需要將被依賴文件也指定到 files 中,因為編譯器會自動將所有的依賴文件歸納為編譯對象,即 index.ts 依賴 user.ts 時,不需要在 files 中指定 user.ts , user.ts 會自動納入待編譯文件。



          4. 執行編譯

          配置完成后,我們可以在命令行執行 tsc 命令,執行編譯完成后,我們可以得到一個 index.js 文件和一個 index.js.map 文件,證明我們編譯成功,其中 index.js 文件內容如下:


          function getVersion(version) {

             if (version === void 0) { version = "1.0.0"; }

             return version;

          }

          console.log(getVersion("1.0.1"));

          //# sourceMappingURL=index.js.map

          可以看出,tsconfig.json 中的 removeComments 配置生效了,將我們添加的注釋代碼移除了。



          到這一步,就完成了這個簡單的示例,接下來會基于這個示例代碼,講解《七、常見配置示例》。



          四、tsconfig.json 文件結構介紹


          1. 按頂層屬性分類

          在 tsconfig.json 文件中按照頂層屬性,分為以下幾類:

          tsconfig.json 文件結構(頂層屬性).png


          了不起的 tsconfig.json 指南.png



          2. 按功能分類

          tsconfig.json 文件結構(功能).png




          五、tsconfig.json 配置介紹


          1. compileOnSave

          compileOnSave 屬性作用是設置保存文件的時候自動編譯,但需要編譯器支持。


          {

             // ...

           "compileOnSave": false,

          }


          2. compilerOptions

          compilerOptions 屬性作用是配置編譯選項。

          若 compilerOptions 屬性被忽略,則編譯器會使用默認值,可以查看《官方完整的編譯選項列表》。

          編譯選項配置非常繁雜,有很多配置,這里只列出常用的配置。


          {

           // ...

           "compilerOptions": {

             "incremental": true, // TS編譯器在第一次編譯之后會生成一個存儲編譯信息的文件,第二次編譯會在第一次的基礎上進行增量編譯,可以提高編譯的速度

             "tsBuildInfoFile": "./buildFile", // 增量編譯文件的存儲位置

             "diagnostics": true, // 打印診斷信息

             "target": "ES5", // 目標語言的版本

             "module": "CommonJS", // 生成代碼的模板標準

             "outFile": "./app.js", // 將多個相互依賴的文件生成一個文件,可以用在AMD模塊中,即開啟時應設置"module": "AMD",

             "lib": ["DOM", "ES2015", "ScriptHost", "ES2019.Array"], // TS需要引用的庫,即聲明文件,es5 默認引用dom、es5、scripthost,如需要使用es的高級版本特性,通常都需要配置,如es8的數組新特性需要引入"ES2019.Array",

             "allowJS": true, // 允許編譯器編譯JS,JSX文件

             "checkJs": true, // 允許在JS文件中報錯,通常與allowJS一起使用

             "outDir": "./dist", // 指定輸出目錄

             "rootDir": "./", // 指定輸出文件目錄(用于輸出),用于控制輸出目錄結構

             "declaration": true, // 生成聲明文件,開啟后會自動生成聲明文件

             "declarationDir": "./file", // 指定生成聲明文件存放目錄

             "emitDeclarationOnly": true, // 只生成聲明文件,而不會生成js文件

             "sourceMap": true, // 生成目標文件的sourceMap文件

             "inlineSourceMap": true, // 生成目標文件的inline SourceMap,inline SourceMap會包含在生成的js文件中

             "declarationMap": true, // 為聲明文件生成sourceMap

             "typeRoots": [], // 聲明文件目錄,默認時node_modules/@types

             "types": [], // 加載的聲明文件包

             "removeComments":true, // 刪除注釋

             "noEmit": true, // 不輸出文件,即編譯后不會生成任何js文件

             "noEmitOnError": true, // 發送錯誤時不輸出任何文件

             "noEmitHelpers": true, // 不生成helper函數,減小體積,需要額外安裝,常配合importHelpers一起使用

             "importHelpers": true, // 通過tslib引入helper函數,文件必須是模塊

             "downlevelIteration": true, // 降級遍歷器實現,如果目標源是es3/5,那么遍歷器會有降級的實現

             "strict": true, // 開啟所有嚴格的類型檢查

             "alwaysStrict": true, // 在代碼中注入'use strict'

             "noImplicitAny": true, // 不允許隱式的any類型

             "strictNullChecks": true, // 不允許把null、undefined賦值給其他類型的變量

             "strictFunctionTypes": true, // 不允許函數參數雙向協變

             "strictPropertyInitialization": true, // 類的實例屬性必須初始化

             "strictBindCallApply": true, // 嚴格的bind/call/apply檢查

             "noImplicitThis": true, // 不允許this有隱式的any類型

             "noUnusedLocals": true, // 檢查只聲明、未使用的局部變量(只提示不報錯)

             "noUnusedParameters": true, // 檢查未使用的函數參數(只提示不報錯)

             "noFallthroughCasesInSwitch": true, // 防止switch語句貫穿(即如果沒有break語句后面不會執行)

             "noImplicitReturns": true, //每個分支都會有返回值

             "esModuleInterop": true, // 允許export=導出,由import from 導入

             "allowUmdGlobalAccess": true, // 允許在模塊中全局變量的方式訪問umd模塊

             "moduleResolution": "node", // 模塊解析策略,ts默認用node的解析策略,即相對的方式導入

             "baseUrl": "./", // 解析非相對模塊的基地址,默認是當前目錄

             "paths": { // 路徑映射,相對于baseUrl

               // 如使用jq時不想使用默認版本,而需要手動指定版本,可進行如下配置

               "jquery": ["node_modules/jquery/dist/jquery.min.js"]

             },

             "rootDirs": ["src","out"], // 將多個目錄放在一個虛擬目錄下,用于運行時,即編譯后引入文件的位置可能發生變化,這也設置可以虛擬src和out在同一個目錄下,不用再去改變路徑也不會報錯

             "listEmittedFiles": true, // 打印輸出文件

             "listFiles": true// 打印編譯的文件(包括引用的聲明文件)

           }

          }


          3. exclude

          exclude 屬性作用是指定編譯器需要排除的文件或文件夾。

          默認排除 node_modules 文件夾下文件。


          {

             // ...

           "exclude": [

             "src/lib" // 排除src目錄下的lib文件夾下的文件不會編譯

           ]

          }

          和 include 屬性一樣,支持 glob 通配符:


          * 匹配0或多個字符(不包括目錄分隔符)

          ? 匹配一個任意字符(不包括目錄分隔符)

          **/ 遞歸匹配任意子目錄


          4. extends

          extends 屬性作用是引入其他配置文件,繼承配置。

          默認包含當前目錄和子目錄下所有 TypeScript 文件。


          {

             // ...

           // 把基礎配置抽離成tsconfig.base.json文件,然后引入

             "extends": "./tsconfig.base.json"

          }


          5. files

          files 屬性作用是指定需要編譯的單個文件列表。

          默認包含當前目錄和子目錄下所有 TypeScript 文件。


          {

             // ...

           "files": [

             // 指定編譯文件是src目錄下的leo.ts文件

             "scr/leo.ts"

           ]

          }


          6. include

          include 屬性作用是指定編譯需要編譯的文件或目錄。


          {

             // ...

           "include": [

             // "scr" // 會編譯src目錄下的所有文件,包括子目錄

             // "scr/*" // 只會編譯scr一級目錄下的文件

             "scr/*/*" // 只會編譯scr二級目錄下的文件

           ]

          }


          7. references

          references 屬性作用是指定工程引用依賴。

          在項目開發中,有時候我們為了方便將前端項目和后端node項目放在同一個目錄下開發,兩個項目依賴同一個配置文件和通用文件,但我們希望前后端項目進行靈活的分別打包,那么我們可以進行如下配置:


          {

             // ...

           "references": [ // 指定依賴的工程

              {"path": "./common"}

           ]

          }


          8. typeAcquisition

          typeAcquisition 屬性作用是設置自動引入庫類型定義文件(.d.ts)相關。

          包含 3 個子屬性:


          enable  : 布爾類型,是否開啟自動引入庫類型定義文件(.d.ts),默認為 false;

          include  : 數組類型,允許自動引入的庫名,如:["jquery", "lodash"];

          exculde  : 數組類型,排除的庫名。

          {

             // ...

           "typeAcquisition": {

             "enable": false,

             "exclude": ["jquery"],

             "include": ["jest"]

           }

          }


          六、常見配置示例

          本部分內容中,我們找了幾個實際開發中比較常見的配置,當然,還有很多配置需要自己摸索喲~~



          1. 移除代碼中注釋

          tsconfig.json:


          {

           "compilerOptions": {

             "removeComments": true,

           }

          }

          編譯前:


          // 返回當前版本號

          function getVersion(version:string = "1.0.0"): string{

             return version;

          }

          console.log(getVersion("1.0.1"))

          編譯結果:


          function getVersion(version) {

             if (version === void 0) { version = "1.0.0"; }

             return version;

          }

          console.log(getVersion("1.0.1"));


          2. 開啟null、undefined檢測

          tsconfig.json:


          {

             "compilerOptions": {

                 "strictNullChecks": true

             },

          }

          修改 index.ts 文件內容:


          const leo;

          leo = new Pingan('leo','hello');


          這時候編輯器也會提示錯誤信息,執行 tsc 后,控制臺報錯:


          src/index.ts:9:11 - error TS2304: Cannot find name 'Pingan'.


          9 leo = new Pingan('leo','hello');


          Found 1 error.


          3. 配置復用

          通過 extends 屬性實現配置復用,即一個配置文件可以繼承另一個文件的配置屬性。

          比如,建立一個基礎的配置文件 configs/base.json :


          {

           "compilerOptions": {

             "noImplicitAny": true,

             "strictNullChecks": true

           }

          }

          在tsconfig.json 就可以引用這個文件的配置了:


          {

           "extends": "./configs/base",

           "files": [

             "main.ts",

             "supplemental.ts"

           ]

          }


          4. 生成枚舉的映射代碼

          在默認情況下,使用 const 修飾符后,枚舉不會生成映射代碼。

          如下,我們可以看出:使用 const 修飾符后,編譯器不會生成任何 RequestMethod 枚舉的任何映射代碼,在其他地方使用時,內聯每個成員的值,節省很大開銷。


          const enum RequestMethod {

           Get,

           Post,

           Put,

           Delete

          }


          let methods = [

           RequestMethod.Get,

           RequestMethod.Post

          ]

          編譯結果:


          "use strict";

          let methods = [

             0 /* Get */,

             1 /* Post */

          ];

          當然,我們希望生成映射代碼時,也可以設置 tsconfig.json 中的配置,設置 preserveConstEnums 編譯器選項為 true :


          {

           "compilerOptions": {

             "target": "es5",

             "preserveConstEnums": true

           }

          }


          最后編譯結果變成:


          "use strict";

          var RequestMethod;

          (function (RequestMethod) {

             RequestMethod[RequestMethod["Get"] = 0] = "Get";

             RequestMethod[RequestMethod["Post"] = 1] = "Post";

             RequestMethod[RequestMethod["Put"] = 2] = "Put";

             RequestMethod[RequestMethod["Delete"] = 3] = "Delete";

          })(RequestMethod || (RequestMethod = {}));

          let methods = [

             0 /* Get */,

             1 /* Post */

          ];


          5. 關閉 this 類型注解提示

          通過下面代碼編譯后會報錯:


          const button = document.querySelector("button");

          button?.addEventListener("click", handleClick);

          function handleClick(this) {

          console.log("Clicked!");

          this.removeEventListener("click", handleClick);

          }


          報錯內容:


          src/index.ts:10:22 - error TS7006: Parameter 'this' implicitly has an 'any' type.

          10 function handleClick(this) {

          Found 1 error.


          這是因為 this 隱式具有 any 類型,如果沒有指定類型注解,編譯器會提示“"this" 隱式具有類型 "any",因為它沒有類型注釋?!?。



          解決方法有2種:


          指定 this 類型,如本代碼中為 HTMLElement 類型:

          HTMLElement 接口表示所有的 HTML 元素。一些HTML元素直接實現了 HTMLElement 接口,其它的間接實現HTMLElement接口。

          關于 HTMLElement 可查看詳細。


          使用 --noImplicitThis 配置項:


          在 TS2.0 還增加一個新的編譯選項: --noImplicitThis,表示當 this 表達式值為 any 類型時生成一個錯誤信息。我們設置為 true 后就能正常編譯。


          {

           "compilerOptions": {

             "noImplicitThis": true

           }

          }


          七、Webpack/React 中使用示例


          1. 配置編譯 ES6 代碼,JSX 文件

          創建測試項目 webpack-demo,結構如下:


          webpack-demo/

           |- package.json

           |- tsconfig.json

           |- webpack.config.js

           |- /dist

             |- bundle.js

             |- index.html

           |- /src

             |- index.js

             |- index.ts

           |- /node_modules

          安裝 TypeScript 和 ts-loader:


          $ npm install --save-dev typescript ts-loader

          配置 tsconfig.json,支持 JSX,并將 TypeScript 編譯為 ES5:


          {

           "compilerOptions": {

             "outDir": "./dist/",

             "noImplicitAny": true,

          +   "module": "es6",

          +   "target": "es5",

          +   "jsx": "react",

             "allowJs": true

           }

          }

          還需要配置 webpack.config.js,使其能夠處理 TypeScript 代碼,這里主要在 rules 中添加 ts-loader :


          const path = require('path');


          module.exports = {

           entry: './src/index.ts',

           module: {

             rules: [

               {

                 test: /\.tsx?$/,

                 use: 'ts-loader',

                 exclude: /node_modules/

               }

             ]

           },

           resolve: {

             extensions: [ '.tsx', '.ts', '.js' ]

           },

           output: {

             filename: 'bundle.js',

             path: path.resolve(__dirname, 'dist')

           }

          };


          2. 配置 source map

          想要啟用 source map,我們必須配置 TypeScript,以將內聯的 source map 輸出到編譯后的 JavaScript 文件中。

          只需要在 tsconfig.json 中配置 sourceMap 屬性:


           {

             "compilerOptions": {

               "outDir": "./dist/",

          +     "sourceMap": true,

               "noImplicitAny": true,

               "module": "commonjs",

               "target": "es5",

               "jsx": "react",

               "allowJs": true

             }

           }

          然后配置 webpack.config.js 文件,讓 webpack 提取 source map,并內聯到最終的 bundle 中:


           const path = require('path');


           module.exports = {

             entry: './src/index.ts',

          +   devtool: 'inline-source-map',

             module: {

               rules: [

                 {

                   test: /\.tsx?$/,

                   use: 'ts-loader',

                   exclude: /node_modules/

                 }

               ]

             },

             resolve: {

               extensions: [ '.tsx', '.ts', '.js' ]

             },

             output: {

               filename: 'bundle.js',

               path: path.resolve(__dirname, 'dist')

             }

           };


          八、總結

          本文較全面介紹了 tsconfig.json 文件的知識,從“什么是 tsconfig.js 文件”開始,一步步帶領大家全面認識 tsconfig.json 文件。

          文中通過一個簡單 learnTsconfig 項目,讓大家知道項目中如何使用 tsconfig.json 文件。在后續文章中,我們將這么多的配置項進行分類學習。最后通過幾個常見配置示例,解決我們開發中遇到的幾個常見問題。

          vue.js路由與vuex數據模型設計

          seo達人

          路由設計

          本則路由考慮驗證進入登錄頁面,完成登錄操作進入首頁。


          import Vue from "vue";

          import Router from "vue-router";

          Vue.use(Router);


          import store from "@/store/store";


          // (延遲加載)

          const Login = () => import("@/views/login");

          const Home = () => import("@/views/home");


          const HomeRoute = {

           path: "/",

           name: "首頁",

           component: Home

          };


          export { HomeRoute };


          const router = new Router({

           base: process.env.BASE_URL,

           routes: [

             {

               path: "/login",

               name: "登錄",

               component: Login

             },

             HomeRoute

           ]

          });


          router.beforeEach((to, from, next) => {

           let loginName = store.state.user.loginName;

           if (to.path === "/" && loginName == "") {

             next("/login");

           } else {

             next();

           }

          });


          export default router;

          數據模型

          const state = {

           loginName: ""

          };

          const mutations = {

           SET_LOGINNAME(state, loginName) {

             state.loginName = loginName;

           }

          };

          const actions = {

           login({ commit }, userInfo) {

             return new Promise((res, ret) => {

               commit("SET_LOGINNAME", userInfo);

               res();

             });

           },

           logout({ commit }) {

             return new Promise((res, ret) => {

               commit("SET_LOGINNAME", "");

               res();

             });

           }

          };

          export default {

           namespaced: true,

           state,

           mutations,

           actions

          };

          import Vue from "vue";

          import Vuex from "vuex";

          Vue.use(Vuex);


          import user from "./modules/user";


          const store = new Vuex.Store({

           modules: {

             user

           }

          });


          export default store;

          組件

          <div class="modify">

           <input

             type="text"

             @keydown.enter.prevent="handleKeydown"

             v-model="currentVal"

             placeholder="使用enter鍵切換頻道"

           />

           <button @click="reset" style="margin-left:5px;outline:none;cursor:pointer;">復位</button>

          </div>

          import { mapState, mapMutations, mapActions } from "vuex";

          export default {

           name: "login",

           data() {

             return {

               currentVal: "",

               list: ["咨詢服務", "音悅臺", "體育臺", "財經頻道", "時尚資訊"],

               index: 0

             };

           },

           computed: {

             ...mapState({

               loginName: state => state.user.loginName

             })

           },

           methods: {

             ...mapActions({

               login: "user/login"

             }),

             handleToHome() {

               let userInfo = "user";

               this.login(userInfo);

               this.$router.push({

                 path: "/"

               });

             },

          日歷

          鏈接

          個人資料

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

          存檔

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