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

          首頁

          語音交互中的“等待體驗”研究

          鶴鶴

          語音交互是最自然的人機交互方式,它極大地降低了人們與機器交互時的學習成本,已成為非常重要的人機交互方式。


          回顧人機交互發展史,人類先后經歷了基于命令行的CLI 時代,基于鼠標鍵盤的GUI時代,基于觸摸的初級NUI時代。后面每一個階段比前一個階段更自然,學習成本更低,綜合效率更高。

           


          進入AI時代,人工智能給機器帶來三種能力:感知能力、認知能力、自然語言輸出能力。感知能力使機器能聽得懂人類語言,認知能力使機器能思考如何回答人類問題,自然語言輸出能力使機器可以像人類一樣表達——三種能力的綜合運用將人機交互帶入語音交互階段。語音交互是最自然的人機交互方式,它極大地降低了人們與機器交互時的學習成本,將人機交互綜合效率帶上新的臺階,已成為非常重要的人機交互方式。

          、“等待體驗”——語音交互體驗的三分之一

          生活中人與人的對話場景,對話是由“向對方說出一句話”、“等待對方回復”、“對方給出回復”三個階段不斷循環構成。其中“等待對方回復”是對話體驗的“三分之一”,會對回復的滿意度造成直接影響。在等待回復階段,如果對方處于認真思考的狀態,會讓我們覺得被重視;然而,如果在等待過程中對方的注意力不在對話本身,即便對方給出的回復再好,我們也會心存疑慮。



          對應到人機語音交互中的三個部分——“輸入體驗”、“等待體驗”、“回復體驗”,“等待體驗”同樣處于整個體驗循環鏈的中間環節,在語音交互體驗中起到了承上啟下的重要作用。但是,關于語音交互中的“等待體驗”在行業尚未被系統的研究,依舊處于模糊狀態。

           

          1. 響應時間一定是越短越好嗎?

          數字性能管理平臺Dynatrace對用戶瀏覽網頁的行為進行了研究,發現當網頁加載速度提升0.5秒,可促進用戶在網站的行為轉化核心數據提升10%。因此,在網頁設計和App設計中,盡量縮短等待時間是產品設計的不懈追求。

           

          不同于基于視覺的交互,語音交互天然附帶情感屬性。然而,情感的體驗是復雜的,它不只受效率這個單一變量的控制。大多數情況下,在生活中人與人對話時,一個過快的回答會給用戶帶來輕浮感和搶話感,而一個過慢的回答會給用戶帶來遲緩感和愚鈍感。


          那么,在語音交互中,究竟什么樣的響應時間能有最佳的體驗呢?響應時間的體驗趨勢是怎樣的呢?

           

          2. 等待體驗受哪些變量的影響?
          在視覺設計領域,當設計頁面的loading態時,為降低用戶的跳出率,設計師時常會通過給出進度條,或采用趣味性的情感化設計來消除用戶的不安情緒。

           

          但是在語音交互領域,語音的承載體是無形的,或不確定形態的,我們甚至沒有承載loading態的界面。在這種情況下等待體驗又受哪些變量影響呢?影響的程度怎樣呢?

           

          綜上,可以說在語音交互領域,等待體驗雖然重要,但目前仍是“一團迷霧”。鑒于此,我們以目前語音交互的主要載體——智能音箱產品為例,對AI產品中的等待體驗問題進行專題研究。

           

          二、智能音箱的等待體驗研究

          目前的智能音箱,主要采用先語音喚醒后輸入指令的語音交互流程。鑒于此,我們可以將智能音箱的使用過程分為兩個主要階段:

          1)喚醒階段:用戶通過指定的喚醒詞將音箱從等待態轉換為就緒態,音箱被喚醒后才可以接收用戶的語音指令。

          2)用戶請求及反饋階段:用戶給出語音指令內容以及智能音箱反饋結果滿足用戶的需求。

           


          針對這兩個階段,我們先后通過以下三個實驗進行研究。

          實驗一:喚醒階段的響應時間對等待體驗的影響;

          實驗二:用戶請求及反饋階段的響應時間對等待體驗的影響;

          實驗三:視覺、聲音等不同反饋方式對等待體驗的影響。

          下面我們對每個實驗的結論進行逐一詳述:

          實驗一:喚醒階段的響應時間對等待體驗的影響

          為了全面考察喚醒階段各種因素對等待體驗的影響,在實驗中,我們為用戶提供了不同喚醒響應時間和不同喚醒反饋方式的智能音箱。用戶完成實驗任務后,需要對音箱的喚醒響應速度進行評價(5點量表:太快了,接受不了;有點快,能夠接受;剛剛好;有點慢,能夠接受;太慢了,接受不了)。



          實驗一的結果表明最佳的喚醒響應時間與喚醒反饋方式有關,不同喚醒反饋方式下,最佳響應時間不同:

          1)當喚醒反饋為"燈光"反饋時,喚醒響應速度越快越好,在200ms時,用戶響應舒適度最高(對響應時間評價為剛剛好的用戶比例),73%的用戶對速度滿意。

          2)當喚醒反饋為"燈光+音效"時,喚醒響應速度的舒適時間為300ms左右,76%的用戶對速度滿意。

          3)當喚醒反饋為"燈光+人聲"時,喚醒響應速度的舒適時間為500ms左右,74%的用戶對速度滿意。

          (注意:本次實驗設置了市面上主流的三種喚醒反饋方式:燈光、燈光+音效、燈光+人聲,以給不同反饋情況的響應時間感受作參考,但對最優反饋方式,除了響應時間還受其他因素影響,將另著篇章探討。)



          實驗二:用戶請求及反饋階段響應時間對等待體驗的影響

           

          由于用戶請求及反饋階段的響應在技術實現和用戶預期上,與喚醒階段的響應存在差異,因此我們通過第二個實驗對用戶請求及反饋階段的最佳響應時間范圍進行研究。在實驗中,我們為用戶提供了不同響應時間設置的智能音箱。



          實驗二的主要研究發現:

          1)1250ms以內是用戶認為響應速度較優的區間,其中650ms為最佳體驗值。在450ms時,少量用戶覺得響應速度太快了,用戶會感覺到緊迫感和壓力,難以接受。

          2)在1450ms時,有53%的用戶開始感覺響應有延時,但仍能夠接受。

          3)從2150ms開始,有20%的用戶認為音箱響應太慢,不能夠接受。我們認為20%的用戶不滿意,已經不足以被稱為一個優秀的產品。



          實驗三:視覺、聲音等不同反饋方式對等待體驗的影響

          由于目前市場上的智能音箱在請求反饋階段的響應時間普遍在1.5秒以上,并沒有達到實驗二研究的理想響應區間。因此,我們通過實驗三進一步研究反饋方式設計對用戶響應速度感知的影響,我們為用戶提供了五組具有不同反饋方式設計的方案。



          在實驗三的五組方案中,每組方案分別進行了不同響應時間設置。



          實驗三的主要研究發現,不同反饋方式設計會影響人們對音箱響應速度的感知



          1)1250ms以內,方案D感受較差,人聲反饋會產生搶話的感受,部分用戶認為音箱響應太快。



          2)1350ms到2150ms,方案D、E感知舒適的用戶比例較高,加入人聲/音效后,如方案D的語音應答“好的”,有助于緩解用戶延遲感受,提升速度感知體驗。



          3)在3150ms及以上的響應時間,響應方式設計對緩解延時的作用已經不明顯,應該盡量避免此類情況發生。


          此外,實驗三還發現響應速度預期與用戶性別、任務類型有關。與男性相比,女性用戶對響應時間容忍度更低,她們最長在音箱無反饋時可以容忍的平均響應時間長度低于男性,即她們希望在更短的時間內得到音箱的響應反饋。



          與音樂類、問答類等任務相比,用戶對控制類任務的響應時間容忍度更低,用戶希望在控制類任務中有更加及時的響應反饋。



          三、小結

          本文針對語音交互中的等待體驗進行了討論,并以智能音箱為例,重點對喚醒階段和請求反饋階段的響應時間和反饋方式進行了人類工效學實驗研究。由于實驗設定的條件和樣本數量等限制因素,實驗研究結論可能不能代表所有智能音箱用戶在家居環境的全部感受,但希望通過我們的研究和探索,可以指導人工智能語音對話產品響應時間和反饋方式的設計,幫助打造自然和的語音對話體驗。

           轉自:站酷-DUBEST

          寫一個腳本,將所有js文件后綴批量改成ts后綴

          seo達人

          做項目的時候準備把js項目重構成ts項目,需要把文件后綴改成ts,一個bat腳本搞定,命令如下:

          @echo off
          
          rem 正在搜索...
          
          for /f "delims=" %%i in ('dir /b /a-d /s "*.js"') do ren "%%i" "%%~ni.ts" rem 搜索完畢 @pause

          把腳本放到根目錄下,雙擊運行完就可以了

          2020年最火的新擬物化設計,需要思考的五個方面

          濤濤

          新擬物化設計只是一種風格嗎?

          最近正火的新擬物化風格(Neumorphism)在 2019 年底,設計師 Alexander Plyuto 所提出的「Skeuomorph Mobile Banking」作品中亮相。之后不僅被選為 2020 年界面趨勢,又稱為 soft UI。但這種風格在真實世界落地時,可視性上受到許多爭議。

          確實,新擬物化風格它算是一種風格,但又不是只有視覺上的風格這么簡單,它延伸出來的議題,其實是扁平化跟擬物化之間的戰爭。

          擬物化與扁平化的瑜亮情結

          擬物化是 Apple 在早期設計中大量使用在界面上呈現對象屬性、材質的方式。然而在 2013 年 ios7 發布時,Apple 開始為了畫面簡潔大量將界面元素扁平化,緊接著 Google 在 2015 年發布了 Material Design,宣示扁平化在 UI 設計中扮演著主導趨勢的角色。2020 年真是百家爭鳴的一年,首先是 BMW 發表的扁平化新 logo,接著是這一波新擬物化的反擊。究竟代表新擬物化可能奪回界面風格主導權?或僅是 2020 年曇花一現的視覺風格呢?

          扁平化VS 擬物化,我們可以思考的五件事

          我認為新擬物化的概念其實是融合扁平化與擬物化的集大成,它建立在扁平化風格之上,又將組件帶入了擬物化的元素,提高用戶的判斷力。不過在糾結于扁平化與擬物化哪個比較好時,有五個議題是可以讓 UI、UX 設計師去思考的。

          1. 多數年長者對于扁平化界面提供的視覺元素暗示無法理解。

          大家身邊一定都有那種已經把 Line 操作得滾瓜爛熟,但是每次要用 Line 加好友時,還是不知道怎么操作的長輩。最早期當人類還沒進入屏幕時代前,我們所使用的界面大多是實體產品上的控制界面,而這些界面上的每個開關、按鈕,都只有一個輸入源,對應到一個功能(一對一),我們因此就這樣與產品進行簡單的交互動作。然而在屏幕上這個簡單的交互模式被改變了,像是用鍵盤跟鼠標可以輔助我們,在系統中進行抽象與復雜的無限多任務(一對多)。

          △ 你偏好用哪個微波爐加熱咖啡呢?Image credit:Bence Mózer

          讓我們再來看看對長輩最重要的 Line 加好友功能,我們先不論這個功能在整個 APP 中被埋得多深,因為找到加好友的入口真的對長輩來說是看緣分~

          在我引導長輩找出二維碼畫面的經驗中,發現他們都是用死記的方式,把下一步要按哪個鍵、在畫面的哪一個角落,記下來。但由于加好友功能并不是每天都會操作的,因此在學習上的效果,就像是高中時沒有把課文理解、吸收就硬死背下來一樣困難。

          我們來看看「顯示行動條碼」在掃描二維碼畫面中,是否真的具有可以被點選的暗示。在掃描畫面背景單純的時候(如下圖情況 1),「顯示行動條碼」的 button 底色是有透明度的黑、扁平化后沒有陰影提供可以按的暗示,不過因為有大圓角的造型,勉強還是可以誘使人點點看;但一般情況下,掃面畫面背景不會那么理想的無其他干擾(如下圖情況2),button 原本的透明黑完全融入了后面的背景,這時候只剩下「顯示行動條碼」的文字,已經不具備可以被點選的提示。

          △ 情況 2 中,顯示行動條碼的 button 看起來可以按嗎?

          掃描畫面中的外框有一定的透明度,在可操作暗示(affordance)上已經不具有實體的特征,如果又放上有透明度的 button 在上面,讓人充滿不確定性,年長者無法將這樣的情況與現實生活中的經驗聯想在一起。

          2.以顏色做區別真的是最好的方法嗎?

          你知道同一個顏色,每個人看起來會不一樣嗎?而不同顏色在不同環境下,卻又能看起來像同一個顏色嗎?

          不同意新擬物化設計的人中,有人主張運用顏色的引導用戶操作界面的色彩元素不能從界面設計中抽離。但事實上,不同年齡、性別,視覺錐細胞中的活躍程度不一樣。同一個顏色,不同人看,明度跟彩度會有差異?;诜N種現實,由色彩的引導是好還是壞呢?

          例子1:關于人類的視覺錐細胞

          同一個顏色,不同人居然會看成不同顏色?

          為什么阿嬤喜歡買大紅大紫的衣服?這個偏好除了受到個人喜好影響外,也關系到阿嬤視覺錐細胞的活躍度。老年人在上了年紀后,部分視覺錐細胞開始退化,因此對于藍色、綠色這類冷色系的顏色,老年人會開始接受不到這個區段的光帶來的刺激。因為視覺錐細胞對冷色系的刺激降低,導致阿嬤在菜市場逛街時會被偏暖色系的物品吸引。所以會買熱情系服飾不是阿嬤本人的意圖,而是老化的錐細胞在作祟。

          例子2:關于學習觀察顏色這件事

          不同顏色居然看成同一個顏色?

          不同顏色卻看起來很像,有可能是光線造成,也有可能是使用者必須學習去觀察才知道的。日本的 JR 跟 Metro 系統,有著完整且細膩的視覺辨識系統。設計師理想中的情況是,我們將每條路線定義成不同顏色,可以讓使用者更容易學習辨識路線。

          但實地走訪過東京的地下鐵跟 JR,常常會發現跟錯指示,才發現是潛意識辨認錯文字或是顏色。我自己遇到過的經驗是,在新宿站想要找都營大江戶線時,因為在改札口看到了同樣粉紅色的標志,原本已經要嗶卡進去,才發現那是京王新線的 IC 入口標志。

          △ 新宿駛的改札口前,有兩個同為粉紅色的引導指標

          所以說,高齡者或是天生視覺錐細胞有缺陷的人對于顏色無法清楚辨認外;大部分人可以借由學習來增強色彩辨識,除了可以對相似顏色進行更細節的判別外,也可以學著辨認不同光線(暖光、冷光)下造成的色彩差異。

          但是,當我們在設計中,迫使用戶學習、習慣我們制定顏色的意義??赡軙谛率?onboarding 時造成適應上的負擔,也有可能讓他們在使用別的系統造成錯亂。

          3. 對于顏色被定義的意義各個文化、區域、種族都相同嗎?

          在不同文化之下,對于色彩的觀察與運用也不一樣,舉個大家可能都有發現的例子,當你在不同城市旅游的時候,有沒有發現不同城市的優先座顏色不一樣?你能猜得出來,哪一個是臺北捷運上優先座的顏色嗎?

          △ Image credit:wikipedia.org

          當顏色在不同約定成俗下,有不一樣的意義,又剛好缺乏文字或圖像引導的時候,可能會讓使用者解讀成不同的意義。例如:紅色具有熱情、喜氣、帶來財運的意涵,但同時又具有危險的警示意義。

          當設計師覺得紅色可以引起使用者的注意,而把 button 設計為紅色時,卻可能讓沒看清楚文字的用戶,認為按下這個 button 是危險的舉動。

          △ Image credit:photoAC

          4. 光與影(明亮面跟陰暗面)給使用者的可操作暗示(affordance)一樣嗎?

          新擬物化設計中假設了人在使用界面時,會運用與生俱來能判斷光影效果的能力。這是真的嗎?讓我們來做個小實驗:

          為什么在臺北車大廳席地而坐的人,會選擇坐在黑色的棋盤格上呢?如果根據人類從大自然中所得到的可操作暗示來說,有陰影的地方可以提供人類休憩的功能,例如樹陰下的陰影處。

          △ Image credit:中央社、wikipedia.org

          如果這樣說得通的話,代表光亮的區域對人來說是可以行走、活動的地方;而陰影處則是休息與暫停處。

          根據以上的推測,我們做個小實驗,把車站中的 2 個不同區域的地面上分別涂上白色與黑色,來讓受測者選出哪些區域可以暫停,哪些區域可以走動:

          問題A:假設你要在車站的大廳等朋友,你會選擇站在哪里等他呢?

          假設:受測者會選 2,因黑色區域(影子)讓人覺得可以暫停、休憩。

          結果:符合假設

          1:白色柱子前的白地面 32.5%; 2:白色柱子前的黑地面 67.5%

          問題B:哪一邊的樓梯是往上的方向呢?

          假設:大家會選 1,因為黑色區域(影子)讓人覺得可以踩上去。

          結果:符合假設

          1:白色立面+黑色地面 61.3%;2:黑色立面+白色地面 37.8%

          由實驗A、B可得證,雖然實驗結果符合先前假設,大多數的受測者可從陰影判斷要走哪條路,但還是有不少(30%以上)的受測者不認同。所以在用使用光亮陰影的設計暗示時,還是會遇到使用者感知的不同的問題。

          5. 深度認知不同是導致判斷物體距離的能力受影響,也就是所謂的視差。

          新擬物化設計中,將界面組件以類 3D 的方式呈現,使用戶在操作界面時必須去感知界面組件的遠近以判斷重要性,而在深度認知上有障礙的用戶此時就會受到挑戰。用戶可能會遇到,不知道哪個組件才是浮在最上面、最重要的;若界面中的組件有三種以上的陰影深淺,會讓用戶在判斷時要更花腦力判定物件在立體空間中的深淺。

          總結

          新擬物化風格中的光影表現提供了使用者人類最原始的操作意圖:可操作暗示,是一個好的出發點,然而必須針對 APP 性質的不同而有所改良。在設計較走生活風格理念,而操作界面不復雜的 APP 時,非常適合用新擬物化風格來詮釋:例如電子書服務、音樂軟件;但在設計功能導向,且有大量信息化圖表的界面,例如:移動網銀,還是需要以扁平化的界面為主要信息架構,新擬物風格可能會是極少量界面元素中,拿來呈現生活中真實物的質感(例如:用戶的信用卡)、或是作為亮點(例如:優惠卡片)的呈現方式,此類型 APP 中最重要的卡片與圖表對于此種風格,一定要謹慎使用,必定三思三思再三思。

          文章來源:優設    作者:Muse Chang

          前英語流利說設計總監:從民房到納斯達克的理想主義設計路

          濤濤

          可能對于一些人來說,流利說是一份工作,而對于我來說,流利說卻是一段深刻的旅程,改變了我的生活,也塑造了我的性情、人格。從 2013 年作為第 7 號員工加入流利說,為之效力6年,從最早期民房創業,到納斯達克 IPO,這段經歷,我自認為頗具一個理想主義者的傳奇色彩,有些故事,是我愿意,也值得分享的。

          老王(流利說 CEO 王翌)以前總借他恩師的話說,人這一輩子能做一兩件漂亮事就不錯了。我覺得,流利說,算我過去做的一件漂亮事。以前,我也常和同事說,如果你現在一切的經歷,在日后不足以用故事說與人聽,可能你現在經歷的還不夠痛,你還不夠刻苦。所幸,過去的經歷,給我留下了幾個故事。

          這一次,我想分享當初選擇加入流利說的故事,分享這個過程中我的思考、行動。一方面,單純的想記錄這段故事。因為隨著年歲增加,記性卻是退減的。文字是最好的保存記憶的方式;另一方面,常常遇到設計師朋友們聊如何選擇工作機會,遇到創業的邀約機會怎么判斷、決策的問題,我希望這個故事,能給遇到此類問題的朋友一些啟發。

          好,聽故事吧。

          緣起

          2012 年,我退出了聯合創立一年半的公司。而在一年半以前,我從阿里云公司離開,放棄了一筆可觀的 RSU 股票,當時,我是阿里云最早的 28 位設計師之一。結束創業后,2012 年 11 月 14 日 19:17,我發了一條微博,表示想看看新的機會。這條微博,有 16 個轉發。其中有 1 個轉發,被流利說聯合創始人 Ben 看到,他把這條微博轉發給了聯合創始人王翌(流利說 CEO)。

          在此之前,我和 Ben、王翌素不相識,網友都談不上。Ben 之所以看到那條轉發,是因為他關注好友里面,有一位正是我一款瀏覽器插件產品 – 微博急簡 的用戶。

          有一顆創作的心 – 微博急簡

          △ 使用「微博急簡」前后,微博主頁的對比

          容我多說幾句,介紹一下微博急簡這款產品。2011 年左右,新浪微博的使用體驗,非常糟糕,逐步商業化帶來的各種廣告,讓原本不好的體驗,變得更加讓我無法容忍。很快,一個叫 stylish 的 Chrome 插件工具,在微博設計/技術圈子里流傳。用戶安裝 stylish 插件后,通過修改 CSS 來定制自己的微博體驗。同時,你還可以把 CSS 分享給其他用戶。

          這太好玩了!我按自己的使用喜好,給自己訂制了一套極簡體驗的新浪微博。玩了幾天后,我決定做一個改善微博體驗的瀏覽器插件。為什么要重新做一個插件呢?我認為,stylish 的使用門檻、操作成本都太高,僅僅是專業人士的玩具。我希望普通人,也可以通過一鍵安裝瀏覽器插件,獲得舒服的微博體驗。因此,我給插件取名 – 微博急簡。看得出來,我是多么急迫的想簡化微博的體驗。

          兩周后,微博急簡就上線了。幾個版本后,體驗就趨于穩定。高峰的時候,有 10 萬左右的用戶使用,相關微博話題有 600 萬。有很多行業內的大咖成為我的用戶,像馮大輝、少楠、方軍等。獲得了很多用戶的好評,最讓我嘚瑟的是現任丁香園產品總監少楠的評價:用一個插件秒殺了新浪UED團隊。

          通過微博急簡這個產品,我想分享以下幾點:

          • 設計師應該對體驗保持敏感度。不要被體驗糟糕的產品破壞了味蕾;
          • 如果有機會,就要試圖去改變它;
          • 出于興趣,單純的為自己做設計、創作。即使沒有金錢回報;

          這三點,既是我的觀點,也是我的特質。正是因為這樣的特質,才遇到后面加入流利說的契機。

          面對首次邀約

          回到故事主線。

          我發完那條微博后的 1 小時,王翌就給了我微博私信。老實說,今天是我第一次注意到這個「相隔 1 小時」的時間細節。王翌的行動力、執行力,對于人才的執著追求,著實讓我佩服。這不僅僅是對我,對流利說早期的員工,以及后面的核心員工,都是如此。

          他的消息里,有三個關鍵詞:exciting、團隊成立 2 個月、移動教育。對于這條消息,我禮貌的回應,但內心其實是「呵呵」的。即使,我看到他 LinkedIn 主頁上 Google PM 的經歷,很亮眼。呵呵的原因是,這個公司太早期了,才兩個月。2013 年,移動教育是啥東西?而且,創始人還這么不務實,動不動就標榜是一個 exciting 的機會。

          雖然,王翌后續一直聯系我,但我基本是忽略的狀態。期間,我短暫的加入了一個朋友的創業公司。2013 年 1 月底,春節前的幾天,我再次收到王翌的私信:流利說 App 即將上架,想約我再聊一聊。于是,我們約在文二西路白鴉(有贊創始人)的貝塔咖啡。

          ?

          △ 貝塔咖啡館

          那天晚上,王翌給我展示了流利說最早的 App,程序其實還不太穩定。但他仍舊極具信心的表達了對于語音互動的看好,以及發出盛情邀請。我對這個 App 的產品與交互的第一印象,是好的,但對于王翌的第一印象卻是復雜的,既覺得這人有激情、有想法,同時又覺得不太靠得住,夸夸其談,他太會說了。

          如何設計深色模式?這3點因素需要考慮

          濤濤

          深色模式該從何處著手設計又要考慮哪些因素?一起來看看~

          其實回顧我們常用的APP,有很多都更新了深色模式,而且每個APP對深色的定義和設計都有差異。

          實際上深色模式已經來臨,而且在很多產品中都能發現它的身影,之后也會愈加流行。那么設計師面對深色模式,該從何處著手設計又要考慮哪些因素呢?

          本文就為大家提供一份全面的總結。文章目錄如下:

          選擇深色模式的原因

          1. 需求趨勢

          過去一年以來,Android 10和iOS 13上都適配了深色模式,而且Apple和Google也一直致力于將資源和注意力投入到深色模式中,這也讓深色模式備受用戶的關注。

          2. 專注內容

          深色模式在弱光環境下具有更好的可讀性,讓我們更專注于眼前的屏幕。同時深色的背景會降低內容周圍元素的影響,特別是以圖片和視頻為主的應用,讓用戶更專注于內容。

          作為內容消費型應用的Netflix ,把深色背景作為默認設計樣式,深色的設計讓用戶更能集中注意力,延長使用時間。

          3. 減輕刺激

          相對于其他顏色,深色系的設計在夜晚看著最舒服??赡芡砩贤媸謾C不用擔心光線太刺眼,但是深色模式對護眼并沒有什么幫助,只能說可以減少對眼睛的刺激。

          4. 提高續航

          深色模式更省電只適用于OLED屏幕。OLED面板的每個像素點可以單獨發光,當使用深色模式時,部分像素點被熄滅,只點亮部分像素,屏幕的一部分相當于處在休眠狀態,所以會更加省電。

          平臺設計指南

          1. iOS平臺深色模式設計

          在深色模式下,Apple重新審視了iOS中UI樣式和顏色的含義,讓我們來看看在iOS上設計深色模式帶來的變化。

          語義化顏色(Semantic Colors)

          所謂語義化顏色,就是不再通過某一固定的RGB色值來描述顏色,而是根據用途來描述,讓界面元素可以自動適配當前的外觀模式。

          淘寶團隊就參考了蘋果官方的適配建議,通過語義化顏色的方式進行適配,使適配成本大幅降低。設計師根據不同UI元素的特性先期制定顏色語義化規則,進而技術在框架層面通過「顏色自動反轉」技術實現顏色反轉。

          系統顏色

          除了語義化顏色,Apple還提供了9種預定義的系統顏色,在淺色和深色模式中,這些顏色會動態變化,支持整個系統的外觀,同樣也可以自適應選定的界面樣式。

          模糊與動態效果

          在iOS13上,蘋果引入了4種模糊效果和8種動態效果,它們自動適應iOS界面樣式。這是在淺色和深色模式下不同的模糊效果。

          蘋果還在iOS深色模式排版套件中引入4種動態效果,其中3種為疊加效果,1種分隔效果。

          2. Android平臺深色模式設計

          谷歌提供了廣泛的文檔支持,幫助設計師了解深色主題如何在Android生態系統中運行。

          Elevation(陰影)

          UI界面元素間的投影最能讓用戶清晰地感知用戶界面的深度。在設計深色主題時,組件將保留與淺色主題相同的默認陰影組件。Elevation越靠上, 顏色就會越淺。

          無障礙性與對比

          深色UI設計中的背景應足夠暗以顯示白色文本。設計師要注意背景和文字之間至少使用15.8:1的對比度。這樣可以確保將正文放在最前面時,能通過WCAG(Web內容無障礙指南,使網站內容更容易訪問)的AA標準。

          顏色

          深色模式必須避免飽和的顏色,以免引起眼睛疲勞。相反,設計師應專注于使用不飽和的顏色,以增加清晰度。主色和輔色的選擇還取決于對淺色和深色UI主題的考慮。

          文字不透明度

          在深色背景上設計淺色文字時,高度強調的文字不透明度為87%;一般提示文字的不透明度為60%;禁用文字的不透明度為38%。

          深色模式的設計要點

          蘋果和谷歌都利用各自的設計原則,為深色模式設計做準備工作。在實際設計過程中,不單需要這些基本原則,更重要的是要注意設計深色模式的實用要點。

          1. 背景灰度

          設計深色背景時不是簡單的把白變成黑,而是對背景使用比較暗的色調,以減少眼睛疲勞。

          在淺色模式中,我們傾向于用細微的陰影來傳達界面深度,使用起來更加自然。但是在大多數深色模式下,陰影的效果并不明顯,通常用顏色的深淺來傳達界面的層級關系。

          關鍵點:注意應用場景

          在知乎的深色模式中,背景的設計從深到淺使用了三級灰度,讓頁面的層級更分明。

          一級灰度的應用場景主要是大的背景色,使用面積相對比較大顏色最深;二級灰度的應用場景是選項的背景色,根據選項的數量設置使用面積,位置排布比較靈活;三級灰度的顏色最淺,使用面積最小,通常用在分割線中。

          2. 文字對比

          白底黑字和黑底白字帶給我們的用眼體驗是不一樣的。設計不當的深色模式常常因為強對比而變得很刺眼,同時為了提高對光線的吸收虹膜會張得更開,更容易造成眼部疲勞。

          關鍵點:文字間的對比

          深色模式中,文字的用色通常是純灰色,不同位置的文字例如標題、正文和注釋使用深淺不同的顏色作對比。上圖是深色的微信,就利用這種方法來區分不同文字內容,展示文字層次關系。

          另外每個應用的定位都不一樣,界面中想傳達的信息也有差異,所以要注意不同的設計思路。

          關鍵點:文字與背景的對比

          已經更新深色模式的應用主要分為兩大類,一類屬于工具型應用例如QQ、微信、百度網盤等,這類應用追求的是信息的有效傳達,在設計時文字內容和背景色的區分比較明顯。

          上圖是百度網盤的深色模式,可以看出來標題文字與背景有很明顯的對比,保障了用戶使用時的可操作性和易讀性。

          這樣的設計不需要用戶過于沉浸式的閱讀,只需要幫助用戶快速找到有用的信息并方便使用,這是工具型應用在設計深色模式時必備的原則。

          另一類屬于內容型應用例如知乎、簡書等,這些應用更注重沉浸式的閱讀體驗,因為用戶通常會在某個界面中停留很久來查看內容,所以需要文字與背景的低對比度為閱讀營造柔和的氛圍。

          簡書的深色模式中,文字與背景的對比關系就設計得很弱,整個界面呈現出灰色調,這樣的設計有助于在弱光環境下的長時間閱讀和瀏覽。

          3. 圖標/按鈕

          深色模式應該避免使用特別鮮艷的顏色,較高的明度和飽和度會與深色背景形成強烈的對比,讓頁面的可讀性變差并加深刺激。

          關鍵點:降低色彩明度

          在由淺變深的過程中,知乎對改變了界面中所有圖標的顏色。界面里面的圖標和主題按鈕的色彩,在色相、飽和度上都沒有變化,但是明度被不同程度的降低,保證了在不同光照條件下的內容的可讀性。

          這是深色模式中處理色彩的一種方法,雖然在淺色界面中,我們更喜歡鮮艷的顏色,但明度低的顏色更適合深色主題。匹配這兩個模式另一個比較好的方法是創建互補的色板。

          結論

          無論深色或者淺色,都只是產品向用戶呈現的一種界面狀態,最終的目的是為了更良好的使用體驗。

          不管選擇什么樣的模式,都要記得從產品自身出發,并牢記這幾點:

          • 了解趨勢:熟悉深色模式流行起來的原因,以及蘋果和谷歌對此的相關研究。
          • 找對方向:在準備設計深色模式前,要先了解清楚產品對應的平臺、滿足的標準。

          • 掌握要點:設計深色模式更多要求的是顏色上的變化,利用灰度色階拉開背景顏色,把握文字與背景間的強弱關系,適當降低圖標的明度和飽和度。

          文章來源:優設    作者:Clip設計夾

          設計手記:給設計師參考會不會限制設計師的思維呢?

          藍藍設計的小編

          藍藍設計 魏華寫

               在承擔ui設計項目中,常常碰到一些客戶不給設計師看己往的軟件或本公司設計師設計但沒有被客戶認可的設計方案,怕限制設計師的思路。那究竟給設計師參考會不會限制設計師的思維呢?


               實際上不會的,這是更多維度了解客戶的思考和角度,排除己被嘗試過的選項。


               在進行一個ui 設計前,深度方面應該要了解業務,用戶角色,環境生態,交互流程,關鍵功能,核心價值,用戶體驗的峰值點和難點在哪里…….總之了解的越深越好。


               寬度方面,要看到競品分析,行業趨勢,國內外優秀案例欣賞,專業文章觀點,應該是可以拓展設計師的思維。


               設計最核心的目標應該在于解決問題,而不是單純的讓界面好看。


                優秀的設計師要明確解決問題的目標,博采眾長,獨立思考,看眾多的競品是看眾多的解題思路,多方位角度看問題。各產品資源,核心技術不同,取舍不同,理解信息架框,運營思路,用戶特征,技術實現可能性,不會只照著您給的資料比貓畫虎。


                 因此,我認為,放心的給設計師參考資料吧,互相的了解,溝通越多,越容易出好的作品。



          這五張圖是最近藍藍設計的稿件,展現從一個模糊的概念性需求到一個可視化概念性方案的設計過程。

              點擊查看原圖

          點擊查看原圖


          點擊查看原圖

          2看文章.png點擊查看原圖

          循環設計,用戶體驗如何呼喚時代變革

          鶴鶴

          關于循環設計,可持續發展是商業領域非常關注的話題,作為UX需提前轉變思維,給企業帶來更多價值,一線大廠已在運用這種思維


          本文共 3589 字,預計閱讀 10 分鐘

          譯者推薦|本文從“可持續”和“設計”的兩點談起,來論述從線性經濟向可持續經濟的轉變,以及“可持續設計”的四個主要階段:理解、定義、制造、發布。

          “循環設計”不是為了追求時髦或者抬升設計地位,而是將這個已經日益庸俗化的“設計”冠為自己的定語,是設計本身發展所趨,以及可持續發展所需,設計界需要對自己的責任有所承擔,形成一個全局觀、系統性看待設計問題的方式。讓回收利用和可持續發展成為一種規范,從而做到一勞永逸。

          我們生活在一個呼喚變革的世界。在過去的50年中,現代社會所依賴的漫不經心和無休止的消費是不可持續的。我們從小就不關心自己的事情。如果有什么東西壞了,我們也就不修了。產品被設計成用完直接丟棄,而不是去修復。數字產品也不例外。然而,為了解決這些問題,出現了一種新的思維方式:循環設計(可持續設計)①。(益達說:其實這個理念和風格已經存在了很長的時間,大多應用在不為大眾所知的能源、材料再生流程之中,然而隨著時代的發展,循環設計可以變得更加普世。)

          ①注:循環設計是20世紀80-90年代產生的一種設計風格,他又稱回收設計,是指實現廣義收回和利用的方法,即在進行產品設計時,充分考慮產品零部件及材料回收的可能性,回收價值的大致方法,回收處理結構工藝性等于與回收有關的一系列問題,以達到零部件及材料資源和能源的再利用。它旨在通過設計來節約能源和材料,減少對環境的污染,使人類的設計物能多次反復利用,形成產品設計和使用的良性循環。

          那么,循環設計方法意味著什么?在數字產品上要如何使用?在回答這些問題之前,首先,我們需要仔細觀察我們是如何構建我們的世界,為什么這個世界已經不可持續了,并且要理解環保世界的需求是如何改變我們的思維方式,促使我們渴望從線性設計模型轉變為循環設計模型。


          向循環轉變


          我們的經濟主要基于“按需配置”流程之上。在此線性系統中,我們構建了會在一段時間后淘汰的產品,并且將其組件視為垃圾。與此相反,循環設計方法將產品的生命周期視為一個閉環,其中資源不斷地被重新利用。


          在“經典”線性模型中,產品經歷了生產、消費和破壞的各個階段,最終以浪費告終。在設計一款循環產品過程中,我們使用的方法包含四大階段,這四個階段形成了一個閉環,并形成了一個恒定的循環,在這個循環中,不僅僅只有閃閃發亮的、新的,未使用過的材料才被受歡迎。

           

          循環設計方法的四個階段是:

          理解 / 定義 / 制造 / 發布



          當我們同時看線性設計和循環設計模型方法時,有一點吸引人的是,開始設計東西的時候,方法的差異。從只是生產某種東西,到對我們將要生產的產品做出深思熟慮的決定,以及在實施過程中付出的努力和關心,這是一個大轉變。


          看看我們現在的立場


          為什么做出這種轉變如此的重要?我確信每個看新聞的人都聽說過氣候變化。NASA 致力于解決環境問題,因此我們都可以非常詳細地了解人類行為和無限增長對我們生態系統的影響。


          但好消息是我們不必繼續這樣做,因為我們可以很容易從數字世界中“產生”方式中學習事物的產生。電力廢棄物已成為現代世界的主要廢棄物來源之一。大量的手機和電腦被扔掉,隨之經濟是建立在每年都有新東西的基礎上的。


          當您的手機屏幕意外碎裂時,我們該怎么辦?我們知道如何處理它嗎?我們知道如何修理嗎?我們并不知道……但是幸運的是,有些設計師對此問題提出了解決方案。Fairphone② 是一種合乎情理,模塊化的智能手機,其組件數量很少,可以輕松更換和回收。大公司也應朝這個方向邁出一步,讓回收利用和可持續發展成為一種時尚和規范,一勞永逸。

          ② Fairphone:這家公司生產的手機希望實現全球手機供應鏈的公平貿易,具體而言就是不使用“沖突礦物”并且確保生產手機的工人沒有被奴役和壓榨,目前仍然堅持在非洲貧困和戰亂的國家進口材料,已經在剛果和盧旺達境內找到了一些礦山,用更好的商業實踐推動當地經濟更健康地發展。


          設計和設計師的重要性


          設計師,比任何其他專業人士,都更有可能在一轉變中產生巨大的影響的人。我還敢說,我們有責任采用可持續設計的方式行動和思考。因為是我們創造了那些最終出現在傳送帶上的東西。我們也有責任教育我們的用戶。幸運的是,越來越多的人重視具有可持續發展目標的產品或品牌,或者重視起在產品背后有意義的故事。同樣,可持續發展不僅成為流行語,而且成為一種價值觀,被越來越多的人意識到基于有限資源的無限增長是無法實現的目標。但是,要從線性經濟向可持續經濟轉變,我們需要學習不同的思維方式。幸運的是,智能設備和數字產品的時代帶來了一種復雜的設計思維方法,可以作為物理世界中生產鏈的范例。


          用戶體驗必須提供什么


          地球上有一個地方,您不能隨便丟東西:互聯網。這是一個對已有產品進行再構思的地方,您只能去完善它,不能丟棄它,因為如果您一夜之間說:“我不喜歡我的網站,明天我將推出一個全新的網站”,那您便會失去用戶。

          如果我們看一下可持續發展設計方法的四個主要階段,就會發現我們在用戶體驗設計中使用的方法與此很相似。

          讓我們再次看一下四個階段,然后將其更詳細地分解:

          理解

          當我們談論與循環設計相關的理解時,我們談論的是在開始設計一個未來的產品之前就了解它的用戶和環境。研究一直是數字產品設計的基礎。與數字產品的連接比與實體產品的連接要更多的涉及到人類的心理。因此不可避免地要開發出新的研究方法,以幫助我們洞察用戶在使用某種產品時的想法、感受和行為。但這不僅與用戶有關, 研究還必須深入到經濟領域,并研究未來產品的組成部分,同時牢記它們必須可被再次利用。


          定義

          在此階段,將定義(商業)目標,并構建一個商業模型畫布作為生產過程的計劃。用戶體驗使用這種方法已有一段時間了,讓涉眾參與其中,并在設計過程中更多地激活它們。為我們設計的產品設定一個目標是至關重要的,因為有了它,我們可以為用戶創造額外的價值。因此,無論是制作商業模型畫布還是舉辦精彩的價值主張研討會,在生產方式中實施這些方法都會對當前的生產流程產生巨大的影響。


          制造

          這是關鍵部分。現在我們正在做的事情就好像沒有明天一樣。隨著每種無法回收的產品的出現,我們產生的廢料越來越多。但是循環方法是為產品創建一個原型,并定義將需要使用那些材料反映在產品原型上,并在定義階段概述的商業模型上定義材料。原型設計和構思是用戶體驗設計過程中的關鍵要素,這也是為什么需要制作原型。


          發布 

          根據循環設計模型,隨著產品的發布,生產周期進入了第四階段,然同時理解階段又重新開始了。對于數字產品來說,這是自然發生的事前:你發布一個產品,基于該版本收集反饋,然后構思它,周而復始,這個循環再次產生。


          但是,觀察這個循環并建立這些連接僅僅是冰山一角。在數字時代發展起來的設計思維給世界帶來了許多反思。


          變革中的大佬


          幸運的是,已經有許多大品牌意識到轉變的必要性,并采取和提出了數字設計思維方法來支持轉變,并建立循環設計的時代。根據《循環設計指南》,“我們應該把我們設計的所有東西都看作軟件產品和服務——這些產品和服務可以基于我們通過反饋得到的數據而不斷的發。”


          用戶體驗研究和用戶體驗設計一直是在做的一件事是:基于全面的研究和真實的用戶需求來構建產品。上面的設計指南是非常復雜的工具,具有許多可能的方法。它強調了從產品到服務流程轉變的重要性,并展示如何使用敏捷流程并將其實施到構建產品的方法之中。


          IDEO(全球頂尖的設計咨詢公司)與 Ellen Macarthur Foundation(艾倫·麥克阿瑟基金會)合作,試圖“試圖通過設計構建一個具有恢復性和再生性的經濟框架”。在這里,您可以找到幾乎每個生產方面和領域——例如食品、時裝、經濟和設計——并在每個領域中提出解決方案,以打破線性生產系統。


          耐克還宣布了其基于循環設計模型生產高品質運動鞋的新方法原則。正如您已經看到的那樣,無論您身處哪個經濟領域,都可以為循環生產過程的蓬勃發展做貢獻,并成為一支主導力量。


          重要的結論


          我認為,作為設計師,我們始終要為變革而努力,并始終努力與客戶、產品或服務保持緊密的關系,并通過構思使其不斷完善,以實現這一目標。這是因為偉大的事情只有通過時間和不斷的反思才能實現。在離線世界中,數字設計過程也有很多東西可以貢獻。希望通過教育,能有更多的大公司意識到用戶真正想要的產品是具有更多功能并可持續使用的,而不僅僅是將它們當作一次性產品,一旦它們不像最初那樣光鮮就把她扔掉。

          轉自:站酷-大猴兒er 


          六個好用的程序員開發在線工具

          seo達人

          網上可以找到前端開發社區貢獻的大量工具,這篇文章列出了我最喜歡的一些工具,這些工具給我的工作帶來了許多便利。


          1. EnjoyCSS


          老實說,雖然我做過許多前端開發,但我并不擅長 CSS。當我陷入困境時,EnjoyCSS 是我的大救星。EnjoyCSS 提供了一個簡單的交互界面,幫助我設計元素,然后自動輸出相應的 CSS 代碼。




          EnjoyCSS 可以輸出 CSS、LESS、SCSS 代碼,并支持指定需要支持哪些瀏覽器及其版本。開發簡單頁面時用起來比較方便,但不太適合復雜一點的前端項目(這類項目往往需要引入 CSS 框架)。

          2. Prettier Playground


          Prettier 是一個代碼格式化工具,支持格式化 JavaScript 代碼(包括 ES2017、JSX、Angular、Vue、Flow、TypeScript 等)。Prettier 會移除代碼原本的樣式,替換為遵循最佳實踐的標準化、一致的樣式。IDE 大多支持 Prettier 工具,不過 Prettier 也有在線版本,讓你可以在瀏覽器里格式化代碼。




          如果工作電腦不在手邊,使用移動端設備或者臨時借用別人的電腦查看代碼時,Prettier Playground 非常好用。相比在 IDE 或編輯器下使用 Prettier,個人更推薦通過 git pre-commit hook 配置 Prettier:hook 可以保證整個團隊使用統一的配置,免去各自分別配置 IDE 或編輯器的麻煩。如果是老項目,hook 還可以設置只格式化有改動的單個文件甚至有改動的代碼段,避免在 IDE 或編輯器下使用 Prettier 時不小心格式了大量代碼,淹沒了 commit 的主要改動,讓 review 代碼變得十分痛苦。

          3. Postman


          Postman 一直在我的開發工具箱里,測試后端 API 接口時非常好用。GET、POST、DELETE、OPTIONS、PUT 這些方法都支持。毫無疑問,你應該使用這個工具。




          Postman 之外,Insomnia 也是很流行的 REST API 測試工具,亮點是支持 GraphQL。不過 Postman 從 去年夏天發布的 v7.2 起也支持了 GraphQL。

          4. StackBlitz


          Chidume Nnamdi 盛贊這是每個用戶最喜歡的在線 IDE。StackBlitz 將大家最喜歡、最常用的 IDE Visual Studio Code 搬進了瀏覽器。


          StackBlitz 支持一鍵配置 Angular、React、Ionic、TypeScript、RxJS、Svelte 等 JavaScript 框架,也就是說,只需幾秒你就可以開始寫代碼了。


          我覺得這個在線 IDE 很有用,特別是可以在線嘗試一些樣例代碼或者庫,否則僅僅嘗試一些新特性就需要花很多時間在新項目初始化配置上。有了 StackBlitz,無需在本地從頭搭建環境,花上幾分鐘就可以試用一個 NPM 包。很棒,不是嗎?




          微軟官方其實也提供了在線版本的 VSCode,可以在瀏覽器內使用 VSCode,并且支持開發 Node.js 項目(基于 Azure)。不過 StackBlitz 更專注于優化前端開發體驗,界面更加直觀一點,也推出了 beta 版本的 Node.js 支持(基于 GCP,需要填表申請)。

          5. Bit.dev


          軟件開發的基本原則之一就是代碼復用。代碼復用減少了開發量,讓你不用從頭開發組件。


          這正是 Bit.dev 做的事,分享可重用的組件和片段,降低開發量,加速開發進程。


          除了公開分享,它還支持在團隊分享,讓團隊協作更方便。


          正如 Bit.dev 的口號「組件即設計體系。協同開發更好的組件。」所言,Bit.dev 可以用來創建設計體系,允許團隊內的開發者和設計師一起協作,從頭搭建一套設計體系。


          Bit.dev 目前支持 React、Vue、Angular、Node 及其他 JavaScript 框架。




          在 Bit.dev 上不僅可以搜索組件,還可以直接查看組件的依賴,瀏覽組件的代碼,甚至在線編輯代碼并查看預覽效果!選好組件后可以通過 Bit.dev 的命令行工具 bit 在本地項目引入組件,也可以通過 npm、yarn 引入組件。

          6. CanIUse


          CanIUse是非常好用的在線工具,可以方便地查看各大瀏覽器對某個特性的支持程度。


          我過去經常碰到自己開發的應用的一些功能在其他瀏覽器下不支持的情況。比如我的作品集項目使用的某個特性在 Safari 下不支持,直到項目上線幾個月后我才意識到。這些經驗教訓讓我意識到需要檢查瀏覽器兼容性。


          我們來看一個例子吧。哪些瀏覽器支持 WebP 圖像格式?




          如你所見,Safari 和 IE 目前不支持 WebP。這意味著需要為不兼容的瀏覽器提供回退選項,比如:


          <picture>

          CanIUse 還可以在命令行下使用,例如,在命令行下查看 WebP 圖像格式的瀏覽器兼容性:caniuse webp(運行命令前需要事先通過 npm install -g caniuse-cmd安裝命令行工具。


          10 個超有用的 JavaScript 技巧

          seo達人

          方法參數的驗證

          JavaScript 允許你設置參數的默認值。通過這種方法,可以通過一個巧妙的技巧來驗證你的方法參數。


          const isRequired = () => { throw new Error('param is required'); };

          const print = (num = isRequired()) => { console.log(`printing ${num}`) };

          print(2);//printing 2

          print()// error

          print(null)//printing null

          非常整潔,不是嗎?


          格式化 json 代碼

          你可能對 JSON.stringify 非常熟悉。但是你是否知道可以用 stringify 進行格式化輸出?實際上這很簡單。


          stringify 方法需要三個輸入。 value,replacer 和 space。后兩個是可選參數。這就是為什么我們以前沒有注意過它們。要對 json 進行縮進,必須使用 space 參數。


          console.log(JSON.stringify({name:"John",Age:23},null,'\t'));

          >>>

          {

          "name": "John",

          "Age": 23

          }

          從數組中獲取唯一值

          要從數組中獲取唯一值,我們需要使用 filter 方法來過濾出重復值。但是有了新的 Set 對象,事情就變得非常順利和容易了。


          let uniqueArray = [...new Set([1, 2, 3, 3, 3, "school", "school", 'ball', false, false, true, true])];

          >>> [1, 2, 3, "school", "ball", false, true]

          從數組中刪除虛值(Falsy Value)

          在某些情況下,你可能想從數組中刪除虛值。虛值是 JavaScript 的 Boolean 上下文中被認定為為 false 的值。 JavaScript 中只有六個虛值,它們是:


          undefined

          null

          NaN

          0

          "" (空字符串)

          false

          濾除這些虛值的最簡單方法是使用以下函數。


          myArray.filter(Boolean);

          如果要對數組進行一些修改,然后過濾新數組,可以嘗試這樣的操作。請記住,原始的 myArray 會保持不變。


          myArray

             .map(item => {

                 // Do your changes and return the new item

             })

             .filter(Boolean);

          合并多個對象

          假設我有幾個需要合并的對象,那么這是我的首選方法。


          const user = {

              name: 'John Ludwig',

              gender: 'Male'

          };

          const college = {

              primary: 'Mani Primary School',

              secondary: 'Lass Secondary School'

          };

          const skills = {

             programming: 'Extreme',

             swimming: 'Average',

             sleeping: 'Pro'

          };

          const summary = {...user, ...college, ...skills};

          這三個點在 JavaScript 中也稱為展開運算符。你可以在這里學習更多用法。


          對數字數組進行排序

          JavaScript 數組有內置的 sort 方法。默認情況下 sort 方法把數組元素轉換為字符串,并對其進行字典排序。在對數字數組進行排序時,這有可能會導致一些問題。所以下面是解決這類問題的簡單解決方案。


          [0,10,4,9,123,54,1].sort((a,b) => a-b);

          >>> [0, 1, 4, 9, 10, 54, 123]

          這里提供了一個將數字數組中的兩個元素與 sort 方法進行比較的函數。這個函數可幫助我們接收正確的輸出。


          Disable Right Click

          禁用右鍵

          你可能想要阻止用戶在你的網頁上單擊鼠標右鍵。


          <body oncontextmenu="return false">

             <div></div>

          </body>

          這段簡單的代碼將為你的用戶禁用右鍵單擊。


          使用別名進行解構

          解構賦值語法是一種 JavaScript 表達式,可以將數組中的值或對象的值或屬性分配給變量。解構賦值能讓我們用更簡短的語法進行多個變量的賦值。


          const object = { number: 10 };


          // Grabbing number

          const { number } = object;


          // Grabbing number and renaming it as otherNumber

          const { number: otherNumber } = object;

          console.log(otherNumber); //10

          獲取數組中的最后一項

          可以通過對 splice 方法的參數傳入負整數,來數獲取組末尾的元素。


          let array = [0, 1, 2, 3, 4, 5, 6, 7]

          console.log(array.slice(-1));

          >>>[7]

          console.log(array.slice(-2));

          >>>[6, 7]

          console.log(array.slice(-3));

          >>>[5, 6, 7]

          等待 Promise 完成

          在某些情況下,你可能會需要等待多個 promise 結束??梢杂?Promise.all 來并行運行我們的 promise。


          const PromiseArray = [

             Promise.resolve(100),

             Promise.reject(null),

             Promise.resolve("Data release"),

             Promise.reject(new Error('Something went wrong'))];


          Promise.all(PromiseArray)

           .then(data => console.log('all resolved! here are the resolve values:', data))

           .catch(err => console.log('got rejected! reason:', err))

          關于 Promise.all 的主要注意事項是,當一個 Promise 拒絕時,該方法將引發錯誤。這意味著你的代碼不會等到你所有的 promise 都完成。


          如果你想等到所有 promise 都完成后,無論它們被拒絕還是被解決,都可以使用 Promise.allSettled。此方法在 ES2020 的最終版本得到支持。


          const PromiseArray = [

             Promise.resolve(100),

             Promise.reject(null),

             Promise.resolve("Data release"),

             Promise.reject(new Error('Something went wrong'))];


          Promise.allSettled(PromiseArray).then(res =>{

          console.log(res);

          }).catch(err => console.log(err));


          //[

          //{status: "fulfilled", value: 100},

          //{status: "rejected", reason: null},

          //{status: "fulfilled", value: "Data release"},

          //{status: "rejected", reason: Error: Something went wrong ...}

          //]

          即使某些 promise 被拒絕,Promise.allSettled 也會從你所有的 promise 中返回結果。

          你所不知道的XML

          前端達人

          一、XML:

          XML(Extensible Markup Language 可擴展標記語言),XML是一個以文本來描述數據的文檔。

          1. 示例:

          <?xml version="1.0" encoding="UTF-8"?>
          <people>
              <person personid="E01">
                  <name>Tony</name>
                  <address>10 Downing Street, London, UK</address>
                  <tel>(061) 98765</tel>
                  <fax>(061) 98765</fax>
                  <email>tony@everywhere.com</email>
              </person>
              <person personid="E02">
                  <name>Bill</name>
                  <address>White House, USA</address>
                  <tel>(001) 6400 98765</tel>
                  <fax>(001) 6400 98765</fax>
                  <email>bill@everywhere.com</email>
              </person>
          </people>
          

          2. 用途:

          (1)充當顯示數據(以XML充當顯示層)

          (2)存儲數據(存儲層)的功能

          (3)以XML描述數據,并在聯系服務器與系統的其余部分之間傳遞。(傳輸數據的一樣格式)

          從某種角度講,XML是數據封裝和消息傳遞技術。

          3.解析XML:
          3.1 :使用SAX解析XML

          3.1.1 什么是SAX:

          SAX是Simple API for XML的縮寫
          SAX 是讀取和操作 XML 數據更快速、更輕量的方法。SAX 允許您在讀取文檔時處理它,從而不必等待整個文檔被存儲之后才采取操作。它不涉及 DOM 所必需的開銷和概念跳躍。 SAX API是一個基于事件的API ,適用于處理數據流,即隨著數據的流動而依次處理數據。SAX API 在其解析您的文檔時發生一定事件的時候會通知您。在您對其響應時,您不作保存的數據將會被拋棄。

          3.1.2 SAX解析XML方式:

          SAX API中主要有四種處理事件的接口,它們分別是ContentHandler,DTDHandler, EntityResolver 和 ErrorHandler 。實際上只要繼承DefaultHandler 類就可以,DefaultHandler實現了這四個事件處理器接口,然后提供了每個抽象方法的默認實現。
          // 創建SAX解析器工廠對象
          SAXParserFactory spf = SAXParserFactory.newInstance();
          // 使用解析器工廠創建解析器實例
          SAXParser saxParser = spf.newSAXParser();
          // 創建SAX解析器要使用的事件偵聽器對象
          PersonHandler handler = 
                                   new PersonHandler();
          // 開始解析文件
          saxParser.parse(
                      new File(fileName), handler);
          


          3.2. DOM解析XML:

          DOM:Document Object Model(文檔對象模型)
          DOM的特性:
          定義一組 Java 接口,基于對象,與語言和平臺無關將 XML 文檔表示為樹,在內存中解析和存儲 XML 文檔,允許隨機訪問文檔的不同部分。

          DOM解析XML
          DOM的優點,由于樹在內存中是持久的,因此可以修改后更新。它還可以在任何時候在樹中上下導航,API使用起來也較簡單。 

          DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance();
          DocumentBuilder db = builder.newDocumentBuilder();
          db.parse("person.xml");
          NodeList node_person = doc.getElementsByTagName("person");
          

           3.3. JDOM解析XML:

          JDOM是兩位著名的 Java 開發人員兼作者,Brett Mclaughlin 和 Jason Hunter 的創作成果, 2000 年初在類似于Apache協議的許可下,JDOM作為一個開放源代碼項目正式開始研發了。

          JDOM 簡化了與 XML 的交互并且比使用 DOM 實現更快,JDOM 與 DOM 主要有兩方面不同。首先,JDOM 僅使用具體類而不使用接口。這在某些方面簡化了 API,但是也限制了靈活性。第二,API 大量使用了 Collections 類,簡化了那些已經熟悉這些類的 Java 開發者的使用。
           

          解析步驟:
          (1)SAXBuilder sax = new SAXBuilder();
          (2)Document doc = sax.build(….);
          (3)Element el = doc.getRootElement();(4)List list = el.getChildren();
          (5)遍歷內容
          


          3.4. DOM4J解析XML:

          dom4j是一個非常非常優秀的Java XML API,具有性能優異、功能強大和極端易用使用的特點,同時它也是一個開放源代碼的軟件,可以在SourceForge上找到它。在對主流的Java XML API進行的性能、功能和易用性的評測,dom4j無論在那個方面都是非常出色的。如今你可以看到越來越多的Java軟件都在使用dom4j來讀寫XML,特別值得一提的是連Sun的JAXM也在用dom4j。這是必須使用的jar包, Hibernate用它來讀寫配置文件。
          解析步驟:
          (1)SAXReader sax = new SAXReader();
          (2)Document doc = sax.read(Thread.currentThread().getContextClassLoader()
                    .getResourceAsStream("person.xml"));
          (3)Element root = doc.getRootElement();
          (4)Iterator iterator = root.elementIterator();
          (5)遍歷迭代器
          


          4.各種解析方法比較:
          JDOM 和 DOM 在性能測試時表現不佳,在測試 10M 文檔時內存溢出。
          SAX表現較好,這要依賴于它特定的解析方式。一個 SAX 檢測即將到來的XML流,但并沒有載入到內存(當然當XML流被讀入時,會有部分文檔暫時隱藏在內存中。DOM4J是這場測試的獲勝者,目前許多開源項目中大量采用 DOM4J,例如大名鼎鼎的 Hibernate 也用 DOM4J 來讀取 XML 配置文件。
          xstream 實現XML的轉換


          5.案例:

          public class Person {
              private String personid;
              private String name;
              private String address;
              private String tel;
              private String fax;
              private String email;
          
              @Override
              public String toString() {
                  return "Person{" +
                          "personid='" + personid + '\'' +
                          ", name='" + name + '\'' +
                          ", address='" + address + '\'' +
                          ", tel='" + tel + '\'' +
                          ", fax='" + fax + '\'' +
                          ", email='" + email + '\'' +
                          '}';
              }
          
              public String getPersonid() {
                  return personid;
              }
          
              public void setPersonid(String personid) {
                  this.personid = personid;
              }
          
              public String getName() {
                  return name;
              }
          
              public void setName(String name) {
                  this.name = name;
              }
          
              public String getAddress() {
                  return address;
              }
          
              public void setAddress(String address) {
                  this.address = address;
              }
          
              public String getTel() {
                  return tel;
              }
          
              public void setTel(String tel) {
                  this.tel = tel;
              }
          
              public String getFax() {
                  return fax;
              }
          
              public void setFax(String fax) {
                  this.fax = fax;
              }
          
              public String getEmail() {
                  return email;
              }
          
              public void setEmail(String email) {
                  this.email = email;
              }
          }
          



          <?xml version="1.0" encoding="UTF-8"?>
          <people>
              <person personid="E01">
                  <name>Tony Blair</name>
                  <address>10 Downing Street, London, UK</address>
                  <tel>(061) 98765</tel>
                  <fax>(061) 98765</fax>
                  <email>blair@everywhere.com</email>
              </person>
              <person personid="E02">
                  <name>Bill Clinton</name>
                  <address>White House, USA</address>
                  <tel>(001) 6400 98765</tel>
                  <fax>(001) 6400 98765</fax>
                  <email>bill@everywhere.com</email>
              </person>
          </people>
          


          import org.xml.sax.Attributes;
          import org.xml.sax.SAXException;
          import org.xml.sax.helpers.DefaultHandler;
          
          import java.util.ArrayList;
          import java.util.List;
          
          /**
           * Created by Hu Guanzhong
           * SAX解析的特點:
           * 1、基于事件驅動
           * 2、順序讀取,速度快
           * 3、不能任意讀取節點(靈活性差)
           * 4、解析時占用的內存小
           * 5、SAX更適用于在性能要求更高的設備上使用(Android開發中)
           *
           */
          public class PersonHandler extends DefaultHandler{
              private List<Person> persons = null;
              private Person p;//當前正在解析的person
              private String tag;//用于記錄當前正在解析的標簽名
          
              public List<Person> getPersons() {
                  return persons;
              }
          
              //開始解析文檔時調用
              @Override
              public void startDocument() throws SAXException {
                  super.startDocument();
                  persons = new ArrayList<>();
                  System.out.println("開始解析文檔...");
              }
          
              //在XML文檔解析結束時調用
              @Override
              public void endDocument() throws SAXException {
                  super.endDocument();
                  System.out.println("解析文檔結束.");
              }
          
              /**
               * 解析開始元素時調用
               * @param uri 命名空間
               * @param localName 不帶前綴的標簽名
               * @param qName 帶前綴的標簽名
               * @param attributes 當前標簽的屬性集合
               * @throws SAXException
               */
              @Override
              public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                  super.startElement(uri, localName, qName, attributes);
                  if ("person".equals(qName)){
                      p = new Person();
                      String personid = attributes.getValue("personid");
                      p.setPersonid(personid);
                  }
                  tag = qName;
                  System.out.println("startElement--"+qName);
              }
          
              //解析結束元素時調用
              @Override
              public void endElement(String uri, String localName, String qName) throws SAXException {
                  super.endElement(uri, localName, qName);
                  if ("person".equals(qName)) {
                      persons.add(p);
                  }
                  tag = null;
                  System.out.println("endElement--"+qName);
              }
          
              //解析文本內容時調用
              @Override
              public void characters(char[] ch, int start, int length) throws SAXException {
                  super.characters(ch, start, length);
                  if (tag != null) {
                      if ("name".equals(tag)) {
                          p.setName(new String(ch,start,length));
                      }else if("address".equals(tag)){
                          p.setAddress(new String(ch,start,length));
                      }else if("tel".equals(tag)){
                          p.setTel(new String(ch,start,length));
                      }else if("fax".equals(tag)){
                          p.setFax(new String(ch,start,length));
                      }else if("email".equals(tag)){
                          p.setEmail(new String(ch,start,length));
                      }
                      System.out.println(ch);
                  }
              }
          }
          



          public class XMLDemo {
          
              /**
               * 使用第三方xstream組件實現XML的解析與生成
               */
              @Test
              public void xStream(){
                  Person p = new Person();
                  p.setPersonid("1212");
                  p.setAddress("北京");
                  p.setEmail("vince@163.com");
                  p.setFax("6768789798");
                  p.setTel("13838389438");
                  p.setName("38");
          
                  XStream xStream = new XStream(new Xpp3Driver());
                  xStream.alias("person",Person.class);
                  xStream.useAttributeFor(Person.class,"personid");
                  String xml = xStream.toXML(p);
                  System.out.println(xml);
          
                  //解析XML
                  Person person = (Person)xStream.fromXML(xml);
                  System.out.println(person);
              }
          
              /**
               * 從XML文件中讀取對象
               */
              @Test
              public void xmlDecoder() throws FileNotFoundException {
                  BufferedInputStream in = new BufferedInputStream(new FileInputStream("test.xml"));
                  XMLDecoder decoder = new XMLDecoder(in);
                  Person p = (Person)decoder.readObject();
                  System.out.println(p);
              }
              /**
               * 把對象轉成XML文件寫入
               */
              @Test
              public void xmlEncoder() throws FileNotFoundException {
                  BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("test.xml"));
                  XMLEncoder xmlEncoder = new XMLEncoder(bos);
                  Person p = new Person();
                  p.setPersonid("1212");
                  p.setAddress("北京");
                  p.setEmail("vince@163.com");
                  p.setFax("6768789798");
                  p.setTel("13838389438");
                  p.setName("38");
                  xmlEncoder.writeObject(p);
                  xmlEncoder.close();
              }
          
              /**
               * DOM4J解析XML
               * 基于樹型結構,第三方組件
               * 解析速度快,效率更高,使用的JAVA中的迭代器實現數據讀取,在WEB框架中使用較多(Hibernate)
               *
               */
              @Test
              public void dom4jParseXML() throws DocumentException {
                  //1 創建DOM4J的解析器對象
                  SAXReader reader = new SAXReader();
                  InputStream is = Thread.currentThread().getContextClassLoader()
                          .getResourceAsStream("com/vince/xml/person.xml");
                  org.dom4j.Document doc = reader.read(is);
                  org.dom4j.Element rootElement = doc.getRootElement();
                  Iterator<org.dom4j.Element> iterator = rootElement.elementIterator();
                  ArrayList<Person> persons = new ArrayList<>();
                  Person p = null;
                  while(iterator.hasNext()){
                      p = new Person();
                      org.dom4j.Element e = iterator.next();
                      p.setPersonid(e.attributeValue("personid"));
                      Iterator<org.dom4j.Element> iterator1 = e.elementIterator();
                      while(iterator1.hasNext()){
                          org.dom4j.Element next = iterator1.next();
                          String tag = next.getName();
                          if("name".equals(tag)){
                              p.setName(next.getText());
                          }else if("address".equals(tag)){
                              p.setAddress(next.getText());
                          }else if("tel".equals(tag)){
                              p.setTel(next.getText());
                          }else if("fax".equals(tag)){
                              p.setFax(next.getText());
                          }else if("email".equals(tag)){
                              p.setEmail(next.getText());
                          }
                      }
                      persons.add(p);
                  }
                  System.out.println("結果:");
                  System.out.println(Arrays.toString(persons.toArray()));
              }
          
              /**
               * JDOM解析 XML
               * 1、與DOM類似基于樹型結構,
               * 2、與DOM的區別:
               * (1)第三方開源的組件
               * (2)實現使用JAVA的Collection接口
               * (3)效率比DOM更快
               */
              @Test
              public void jdomParseXML() throws JDOMException, IOException {
                  //創建JDOM解析器
                  SAXBuilder builder = new SAXBuilder();
                  InputStream is = Thread.currentThread().getContextClassLoader()
                          .getResourceAsStream("com/vince/xml/person.xml");
                  org.jdom2.Document build = builder.build(is);
                  Element rootElement = build.getRootElement();
                  List<Person> list = new ArrayList<>();
                  Person person = null;
                  List<Element> children = rootElement.getChildren();
                  for(Element element: children){
                      person = new Person();
                      String personid = element.getAttributeValue("personid");
                      person.setPersonid(personid);
                      List<Element> children1 = element.getChildren();
                      for (Element e: children1){
                          String tag = e.getName();
                          if("name".equals(tag)){
                              person.setName(e.getText());
                          }else if("address".equals(tag)){
                              person.setAddress(e.getText());
                          }else if("tel".equals(tag)){
                              person.setTel(e.getText());
                          }else if("fax".equals(tag)){
                              person.setFax(e.getText());
                          }else if("email".equals(tag)){
                              person.setEmail(e.getText());
                          }
                      }
                      list.add(person);
                  }
                  System.out.println("結果:");
                  System.out.println(Arrays.toString(list.toArray()));
              }
          
              /**
               * DOM解析XML
               * 1、基于樹型結構,通過解析器一次性把文檔加載到內存中,所以會比較占用內存,可以隨機訪問
               * 更加靈活,更適合在WEB開發中使用
               */
              @Test
              public void domParseXML() throws ParserConfigurationException, IOException, SAXException {
                  //1、創建一個DOM解析器工廠對象
                  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                  //2、通過工廠對象創建解析器對象
                  DocumentBuilder documentBuilder = factory.newDocumentBuilder();
                  //3、解析文檔
                  InputStream is = Thread.currentThread().getContextClassLoader()
                          .getResourceAsStream("com/vince/xml/person.xml");
                  //此代碼完成后,整個XML文檔已經被加載到內存中,以樹狀形式存儲
                  Document doc = documentBuilder.parse(is);
                  //4、從內存中讀取數據
          
                  //獲取節點名稱為person的所有節點,返回節點集合
                  NodeList personNodeList = doc.getElementsByTagName("person");
                  ArrayList<Person> persons = new ArrayList<>();
                  Person p = null;
                  //此循環會迭代兩次
                  for (int i=0;i<personNodeList.getLength();i++){
                      Node personNode = personNodeList.item(i);
                      p = new Person();
                      //獲取節點的屬性值
                      String personid = personNode.getAttributes().getNamedItem("personid").getNodeValue();
                      p.setPersonid(personid);
                      //獲取當前節點的所有子節點
                      NodeList childNodes = personNode.getChildNodes();
                      for (int j = 0;j<childNodes.getLength();j++){
                          Node item = childNodes.item(j);
                          String nodeName = item.getNodeName();
                          if ("name".equals(nodeName)) {
                              p.setName(item.getFirstChild().getNodeValue());
                          }else if("address".equals(nodeName)){
                              p.setAddress(item.getFirstChild().getNodeValue());
                          }else if("tel".equals(nodeName)){
                              p.setTel(item.getFirstChild().getNodeValue());
                          }else if("fax".equals(nodeName)){
                              p.setFax(item.getFirstChild().getNodeValue());
                          }else if("email".equals(nodeName)){
                              p.setEmail(item.getFirstChild().getNodeValue());
                          }
                      }
                      persons.add(p);
                  }
                  System.out.println("結果:");
                  System.out.println(Arrays.toString(persons.toArray()));
              }
          
              /**
               * SAX解析的特點:
               * 1、基于事件驅動
               * 2、順序讀取,速度快
               * 3、不能任意讀取節點(靈活性差)
               * 4、解析時占用的內存小
               * 5、SAX更適用于在性能要求更高的設備上使用(Android開發中)
               * @throws ParserConfigurationException
               * @throws SAXException
               * @throws IOException
               */
              @Test
              public void saxParseXML() throws ParserConfigurationException, SAXException, IOException {
                  //1、創建一個SAX解析器工廠對象
                  SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
                  //2、通過工廠對象創建SAX解析器
                  SAXParser saxParser = saxParserFactory.newSAXParser();
                  //3、創建一個數據處理器(需要我們自己來編寫)
                  PersonHandler personHandler = new PersonHandler();
                  //4、開始解析
                  InputStream is = Thread.currentThread().getContextClassLoader()
                          .getResourceAsStream("com/vince/xml/person.xml");
                  saxParser.parse(is,personHandler);
                  List<Person> persons = personHandler.getPersons();
                  for (Person p:persons){
                      System.out.println(p);
                  }
              }
          }
          

          日歷

          鏈接

          個人資料

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

          存檔

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