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

          首頁

          設計師要懂的“產品導流”背后知識點。

          鶴鶴

          設計師不僅要低頭畫圖,也要了解“圖”背后的邏輯和需求本質 。嗯,下面用直白的語言跟大家聊一波相關知識點。




          說到產品導流,大家都不陌生。



          身為設計師,應該經常聽到產品同學提需求:“在這里給XX功能加個入口吧”,“這個宣傳新產品的banner可以再大一些嗎”,“這個場景可以宣傳下我們的新功能誒”…


          很多設計師在不了解背景的情況下往往內心是排斥的,心想怎么老是在犄角旮旯里加這么多小廣告啊,都不關心用戶體驗的嘛,balabala...



          但是有誰在吐槽時,深究其背后的原因呢,舉起小爪子讓大牙康康。比如:什么是產品導流?為什么需要產品導流?它有哪些的形式?如何做效果好又能兼顧產品體驗呢?



          最近正好在搞相關的事情,所以擼一篇文章,分享一波相關思考。





          什么是產品導流? 



          “產品導流”指的是:一款產品采用某種形式,增加對另一款產品/功能的曝光,使自己的用戶群體(流量)去使用或探索另一款產品/功能。



          眉頭一緊,感覺上面的描述有點拗口,善良的牙嘗試著用大白話,把導流和被導流的關系,分為兩種形式解釋下:1.父子關系;2.兄弟關系。

          1.父子關系


          畫風是:“爸爸,大腿借我一抱吧”,比如:“抖音”里增加“多閃”入口,“微信”里增加“微視”入口,通過自家體量大的產品(爸爸)給自己導流。



          2.兄弟關系


          畫風是:“外面環境惡劣,是好兄弟,就互導一下吧”,比如:京東的會員可以享受愛奇藝的會員福利,同輩之間互相導流。



          所以,這么說就好理解什么是產品導流,和它們之間的關系了吧。






          產品為什么需要導流? 


          產品之間導流的目的,大致分為兩種:1.獲得新增;2.企業生態。




          1.獲得新增



          試想你費勁巴拉的搞了個新產品,沒人知道,也沒人來用,就算你產品做的再妖嬈,是不是也白搭,更不用說后續的商業變現之類的。


          所以,這個時候如果你有一個相對成熟的產品(爸爸)大腿,讓它給你導流,實現一波冷啟動,是順利邁過第一個坎兒的手段。


          當然,在目前激烈的競爭環境下,不僅是新產品需要導流,擴大規模和獲得新增流量,是每一個互聯網企業里產品或運營同學OKR中必不可少且另他們頭禿的一項指標。



          所以,不管是新產品,還是相對成熟的產品,都需要通過導流的手段,來獲得新增用戶。





          2.企業生態


          “產品導流”除了為了獲得新增,還有就是為了企業生態的體驗閉環。


          做成一款產品的公司很牛逼,但是如果能夠持續做出一系列牛逼產品的公司,一定有成功的基因,或者有一套做事兒的邏輯。


          比如:亞馬遜的飛輪效應,要想形成飛輪,打造自己的生態,業務上就得有自己的閉環,并且閉環上的每一個步驟都可以為其它步驟助力,其次就是以第一個飛輪作為根據地,拉動周邊其它業務,形成第二個或者更大的飛輪。


          這個時候,就需要各個業務線之間的互通及聯動(互相導流)了。






          比如,阿里也是在打造自己的生態,產品之間相互賦能和聯動,一旦建立起來這些基礎設施后,壁壘和護城河就非常堅固。



          整體來看,“產品導流”不僅有助于新產品獲得冷啟動,還有助于相對成熟的產品擴大規模,同時從整個企業生態來看,矩陣產品的互相導流,協同發揮優勢,也有利于打造體驗閉環,建立企業壁壘。





          產品導流的形式有哪些? 



          目前,市面上導流形式大致有以下幾種:1.場景化導流;2.會員制捆綁;3.固定入口扶持;4.廣告位推薦。


          1.場景化導流


          場景化導流,翻譯成大白話就是,讓導流的過程更加無縫銜接。


          這種做法,能兼顧用戶體驗,同時對導流量也更有利,一般用于“功能”層面的互通。比如,用戶正好需要XX產品或功能,你見縫插針的增加導流入口,同時功能和設計元素也跟母產品保持一致,這樣用戶不會覺得干擾或反感。


          類似這種做法的產品比如:QQ&微云,抖音&剪映;視頻號&公眾號...


          QQ&微云


          我們用QQ聊天時,好友之間總會有一些分享文件的行為,有“分享”就有“接收”,有“接收”就有“保存”的訴求,在這種場景下,QQ聊天頁面里用戶長按當前“文件”,就可以將文件保存到“微云”上。






          除此之外,QQ首頁點擊左上角的側邊欄,能看到一列與“我”相關的功能入口,其中有一項是“我的文件”,點擊進去后就能看到“我”在QQ里消費過的歷史文件。


          同時還有“微云”小程序的入口,點擊直接跳轉至微云小程序(做的很服帖,跟自體脂肪填充似的,導流過程不會讓用戶感到突兀)。




          除此之外,微云作為基礎的云存儲能力,也在跟騰訊系的QQ音樂互通,滿足用戶將下載的歌曲保存到“微云”。





          這么做,不僅滿足了QQ音樂用戶的存儲訴求,還提升了QQ音樂的登錄率(用戶想要使用音樂網盤,必須先登錄),同時增加了QQ音樂用戶粘性(用戶一旦在一款產品上存下自己的東西,就會存在遷移成本),最后還為微云帶來了新增用戶(更多QQ的用戶使用微云進行存儲),擴大其規模。


          這樣的互通/導流手段,就實現了產品間1+1大于2的效果。





          抖音&剪映


          刷抖音的兄弟們應該經常見很多視頻下面有一個小標簽,叫“剪映-抖音出品”(意味著博主的那條短視頻是用剪映做的)。


          很多人看到好玩好看新奇的短視頻,都會覺得真香我也要剪同款,因此抖音就是這種恰到好處的投喂給你,點擊標簽,直接跳轉到下載頁,如果已經安裝了的用戶,可以直接進行剪同款。




          抖音不僅送你出去,還負責接你回來,一條龍服務給你安排(導)的明明白白的。


          比如,當你剪輯完成后,就引導你回抖音里分享,畢竟他們不希望你剪完之后保存到本地然后美滋滋去競品(快手之類的)分享吧。





          他們的目的就是,不管你怎么折騰,也逃不出我大字節的手掌。


          包括,最近的視頻號,發完視頻號還能附帶公眾號的鏈接,高頻帶低頻,通過公域流量,幫助作者往私域導流(順便做個廣告,快去關注我的視頻號:大牙兄,哈哈哈)。





          所以微信現在的導流方式是:視頻號能夠鏈公眾號,公眾號能夠掛小程序,小程序又能開直播,直播又能去變現。


          整體來看,場景化的進行導流,更適合“功能”層面的互通,滿足用戶和企業的訴求,還平衡了產品體驗,相對更加絲滑。





          2.會員制捆綁


          會員制捆綁,已經成為互聯網常見導流+變現的方式了,指的就是用戶在你這買了會員,在別的合作產品里也享有它們的特權福利。利用用戶“愛占小便宜”的心理,產品間互相導流。


          比如我們常見的方式有:88會員、聯合會員...

          88會員


          開過88會員的同學舉個爪!好,放下吧,反正我也看不到。


          88會員算是阿里生態體系的重要布局了,也就是你開通了88會員,阿里系的很多產品你可以劈著叉去用,而且很劃算。


          比如,餓了么會員每年108元,蝦米每年128元,優酷每年也差不多180元,還不算其它的,這些價格在用戶心中已經是錨定價格,加到一起怎么著也大1000了吧,跟88元一比,穩賺不賠?。?






          我們來看看88會員里包含什么,各種阿里系的七大姑八大姨的產品都包含進去了,從吃飯、購物、娛樂、旅行再到看病,生活里的方方面面都包含了。





          所以,我身邊的人開了88會員后,畫風是這樣的:明明想用QQ音樂聽歌呢,不!我是88會員!我要去用蝦米!明明想用美團點個外賣呢,不!我要去餓了么!明明我想去愛奇藝看看視頻呢,不!我要去優酷看!(不過他們如果想看“淡黃色長裙蓬松的頭發”還是得去愛奇藝)。


          可以看出,阿里用這套會員體系,把用戶死死的框在(導流)自己的產品矩陣中了,產品群們被自己爸爸carry的明明白白的。





          聯合會員


          聯合會員跟上面說的88會員有點類似了,只是88是自己企業內產品的互相導流,而很多聯合會員是跨公司,跨界整合資源。 

          比如,京東的PLUS京典卡,就是跨公司跟別人合作,有和騰訊視頻、酷狗音樂、喜馬拉雅、攜程、愛奇藝的聯合會員。 





          其實也能看出,京東和其它產品這么搞,也是對阿里系的反擊,沒有爸爸,只能兄弟之間互相導流,抱團取暖,一致對外了。



          3.固定入口扶持


          固定入口扶持,一般出現在規模較大的平臺級產品上,它們利用自己的流量優勢,在固定位置給自己的子孫/兄弟產品們導流。


          扶持下一代,努力做到子又生孫,孫又生子,子子孫孫無窮盡也。



          比如:淘寶、支付寶、美團,在首頁金剛位給自己企業相關產品導流,同時也補足/豐富自己產品的其它場景。






          比如,各家的小程序,也是相對固定的入口給自己的產品或第三方產品進行導流,完善自己的產品生態。






          4.廣告位推薦


          廣告位推薦的導流方式應該是大家非常熟悉的了,它區別于上面的導流方式的核心點在于一般是產品/活動的介紹,引導安裝之類的,形式大致分為:閃屏、 banner、角標、feed流...




          閃屏

          閃屏指的是用戶在使用產品時,打開的第一個啟動頁。


          用它進行導流的優點就是全屏沉浸展示,用戶的目光就聚焦到這里了,但缺點是:時間短,如果在短時間內傳達不清晰的話,很容易一閃而過,錢就白花了。



          所以,閃屏的導流,最好找重疊用戶較高的產品,比如,在汽車之家閃屏投個刮胡刀啊,在親寶寶閃屏投奶粉啊之類的,用戶在短時間內好接受好理解。


          投放越精準,對產品體驗和對廣告主的導流效果越好。





          角標

          角標導流這種形式,在電商類平臺搞活動的時候經常見,各種小角標紛紛出來拉客,角標的著陸頁一般都是活動H5類型的居多。




          這種形式的優點在于能夠一直常駐,不像閃屏,閃一下就沒了,它只要用戶不手動關閉就一直在這杵著。


          但對于設計師的挑戰就是,如何在小小的區域里,把被導流的產品/活動核心利益點傳遞清楚,吸引用戶點擊。

          而且,這種形式也要謹慎使用,如果亂八七糟的飚小角標也挺傷害體驗的。





          Banner


          Banner位的導流大家更常見了,一般都是自己家產品/業務,夾雜著第三方廣告推廣,無限輪播著進行導流,大家都太熟悉了,我就不啰嗦的說了。





          Feed流


          一般資訊類或者社區類產品,喜歡用這種方式進行導流,因為用戶在其產品上的核心操作就是擼Feed。


          所以,擼著擼著給用戶投喂一個通過算法推薦的廣告,然后再把廣告包裝成跟Feed內容很相近的設計,吸引(pian)用戶點進去,從而進行導流。


          比如: 知乎、最右、百度、頭條 ...




          不得不說第二張“最右”的推薦內容,讓我不禁撫摸了下自己的胡子。

          不過除了最右給我推“大胸妹子”,百度給我推“游戲”,頭條給我推“汽車”,難道在他們的算法中,我是個油膩中年男???


          看來他們的人工還不夠智能,機器還得再學習學習,大牙對你萌hin失望。





          總結  


          總的來說,“產品導流”不僅有助于新產品獲得冷啟動,還有助于相對成熟的產品擴大規模,同時從整個企業生態來看,矩陣產品的互相導流,協同發揮優勢,也有利于打造體驗閉環,建立企業壁壘。


          形式大致分為:1.場景化導流,無縫銜接式的體驗,讓用戶在產品功能間絲滑的流轉;2.會員制捆綁,低價獲得跨產品福利,利用用戶占小便宜的心理跨界導流;3.固定入口扶持,平臺型產品常用手段,豐富自己產品場景又能給自己小弟帶流量;4.廣告位推薦,靈活可配形式多變的導流方式(閃屏、 banner、角標、feed流)但搞不好很傷用戶體驗。



          但是,不管什么導流形式,導進來的用戶,只有看到滿足他們訴求和預期的著陸頁才是最關鍵的,不然就算給你再大的流量入口,用戶搞不明白該走還是會走。


          同時,也不能為了導流而不分場景的尬導,這樣很容易傷害原有產品的用戶體驗,撿了芝麻,丟了西瓜。

          轉自:站酷-蘇大牙


          交互問答 | 產品設計的稀缺性 & 截圖功能 & 分頁與無限滾動加載差異

          鶴鶴

          通過交互思維,從常見功能模式梳理產品設計的底層邏輯。

          通過讀者提出的三個問題,我們從交互設計的角度來聊聊它們的底層邏輯。


          稀缺性的正反價值


          讀者提問:

          呆總,有什么心理學或經濟學的概念是在產品設計上也被沿用的?


          當然有,比如稀缺性。


          讓我們從你的生活小故事開始講起。


          在某個餓著肚子的下午,你走進一家超市,想要買桶泡面充饑,但是各式品牌與類型的泡面讓你應接不暇,于是糾結起來,正猶豫不決中,一款所剩無幾的泡面在茫茫商品中跳進了你的視野,不禁心中竊喜,“沒錯,就是它了!賣得這么好,味道一定不錯~”。


          回到家里,你一邊吃著泡面一邊刷著手機,突然看到了節假日商品促銷的廣告,于是打開了購物車,果然每件商品上都赫然標著今日滿減的紅字,讓你蠢蠢欲動,之前嫌貴的商品突然在今天有了剁手的理由。不僅如此,其中你的最愛竟然顯示庫存緊張,如何能忍,趕緊結賬下單,在付完款的最后一刻,你終于松了口氣并開始暗自慶幸自己的英明決策。


          這時,你的舍友突然推門而入,迫不及待地告訴了你她偶然得知的一個八卦消息,之前從未聽聞的你感到激動不已,能夠獲得鮮見的信息讓你感到無比地滿足,兩人就此事展開了激烈地討論....


          以上。


          就像故事中描繪的那樣,我們的生活就是由這些瑣碎的片段重復構成,在無數個場景中,我們做著自覺或不自覺的思考和判斷,它們影響著我們的感知,主導著我們的行為。其中,稀缺性就是我們估值的必要條件和決策的重要基礎,那些熱銷的商品、限時的促銷和不為人知的秘密喚起了我們內心的需求與渴望,催促著我們去行動。在設計產品功能時,產品人員也總是會刻意營造給用戶一種稀缺的感知來突出其價值,以引導用戶進行點擊、瀏覽、購買等一系列行為。


          稀缺的分類


          總的來說,我們對稀缺性的利用大致體現在三個方面:時間、產品、信息。


          時間的緊迫感。


          這一點經常應用在電商產品中,比如特定節日內的商品限時優惠、搶購活動等等。對時間的限制能夠傳遞給用戶一種緊迫感,暗示他們盡快購買,從而減少他們的決策時間,達到促銷的目的。

          產品的缺失。


          我們經常能在電商產品中看到商品庫存的數量,特別是當庫存較少時,能起到刺激用戶的購買欲望。谷歌早前在發布線上郵箱的時候也充分利用了類似的手段,因為個人測試版的郵箱受技術的限制,不能為每個人開放足夠大的儲藏空間,于是他們采用了「邀請制」來推動這項服務,結果非常有效。


          當你成為了其中一員,就能夠再邀請 2-3 個朋友,這項服務的「供應不足」在推薦系統的支持下得到了病毒式的傳播。類似的,知乎早期也利用了邀請的方式去幫助自己獲得初期的忠實用戶,產品的不易得性反而讓人更看重它,間接提高了產品的價值,達到了意想不到的效果。


          再比如部分商品「限購 2 件」,會讓用戶產生再買一件的念頭 —— 其實原本就只想買一件。


          信息的限制。


          因為我們總是假定少的東西更具價值,所以對于審查和限制我們獲得信息的動作尤為敏感,我們更渴望得到那些被禁的隱秘信息而不是唾手可得的信息。這種稀缺性所起的作用甚至比法律還要強,我們會本能地認為它更有說服力。這也是一些新奇罕見的消息更容易傳播的原因之一,得到不常見的信息能夠使人享受到額外資源的優越感。一些媒體恰恰利用了這一點,常通過夸張的新聞標題去抓住人們的注意,試圖擴大其影響力。


          或者一些特權(虛擬)商品,譬如 VIP。就是提供給用戶部分信息,再告知用戶 VIP 權限更高,能獲得多有「價值」信息,誘導購買。


          稀缺作用的原理


          天然的,出于原始的不斷追逐獵物、獲取資源的本能,我們總是格外珍惜稀缺資源,并認為它們更具價值。稀缺性在一定程度上鼓動了我們內心貪婪的欲望,除此之外,我們還有「喜歡走捷徑」的弱點,同時「厭惡失去」。


          一方面,當事物很難被獲取的時候,我們通過易得性進行快速的價值判斷,遵循這樣的方式我們總能地做出決定。

          另一方面,我們討厭失去選擇的自由,所以常傾向于快速地決策來留住一些東西,甚至想要得更多。

          雖然我們的這些本能,在幫助我們快速行動,但卻不一定會做出最適合自己的選擇。畢竟人的判斷大多偏向于主觀,一些用心不良的企業,可能會利用它讓一些人做出錯誤的決定。


          稀缺作用的條件


          相比于一些錯誤所導致的稀缺,比如最近由于豬瘟造成的豬肉供應量的減少,在有限資源的競爭中由社會需求導致的稀缺能夠發揮更強的效應,零售商早已充分洞悉了我們的這種傾向,所以常告訴我們產品正在熱銷當中,應盡快購買。這不僅是社會認同在發揮作用,即我們認為其他人認同的產品是好的,而且我們正參與到產品的競爭當中。

          稀缺原則的應用焦點在于利用緊張的時間或者強調某些東西未來的不可得性,防止用戶花很多的時間做出決策,推動用戶馬上做出對商家有利的決定。如果給人們這個世界上的所有時間去做出決定,他們要不花上所有的時間,要不根本不做決定。


          通過應用稀缺性的技巧,可以從根本上迫使人們采取對策。人們在稀缺性原則的壓力下反應更快,因為他們害怕永遠失去機會。稀缺性使得他們優先做出決定,所以這些決定相比無限制的決策變得更重要,更緊急,更被需要。


          但是僅僅告訴人們他們將要獲得的利益是不夠的,如果他們選擇你的產品或者服務,你還需要指出其特別之處以及被放棄時的成本。

          月活超10億的微信,是如何做好用戶體驗的

          濤濤

          微信是一種生活方式。作為月活超 10 億的國民級產品,它有著獨特的設計之道。

          同時,微信也是互聯網界的一個異類,張小龍曾在微信公開課上回應道:「我們只是守住了做一個好產品的底線,居然就與眾不同了」。

          好產品自然是體驗和價值至上。下面,我就為大家解讀微信的用戶體驗設計。

          二次確認的微創新

          先從最簡單的二次確認講起。

          微信針對首頁消息和收藏列表的刪除操作,做了二次確認的微創新。像同類 IM 聊天工具,如 iOS 短信、Facebook Messenger、飛聊等等,二次確認都是采用底部系統彈窗。這樣做,從程序架構的角度來看兼容性和通用性更強。

          而從體驗設計的角度來看,則剛好相反,因為從第一次刪除操作,到第二次確認系統彈窗。之間的目標距離太長,耗時也就變長了。根據菲茨定律(Fitts’ Law),獲取目標的時間取決于目標的距離和大小。這意味著提升交互的效率,不僅需要減少距離,同時還要增加目標大小。

          △ 收藏列表

          回過頭看來微信,就是這樣設計的。二次確認是在第一次的基礎上延展,距離幾乎為 0,同時,目標按鈕的寬度也增加了幾倍,大大地提升了交互效率。

          互動體驗廣告

          其實,商業和用戶體驗往往是有沖突的。而微信廣告很好的平衡了這一點。

          通過豐富有趣的互動體驗式創意,或畫圓、或畫方、或畫愛心,吸引大家主動參與互動。

          1. 開放首條評論

          另外,首條評論功能讓品牌像朋友一樣與大家對話,利用明星效應,從而帶動更多人參與評論,有效提升評論區活躍度和廣告點擊率。

          △ 朋友圈劉雯廣告

          以劉雯發布的朋友圈廣告為例,大表姐把款的 vivo X30 系列手機交到你手中,并在首條評論中邀請你幫她拍照。數十萬用戶積極回復劉雯,評論率高于歷史均值 40 倍+,「你這么漂亮怎么拍都好看」、「天天給你拍」,大表姐的魅力折服了眾多用戶,有效提升了品牌的親和力與好感度。

          2. 打開儀式 · 最強震動級別

          在交互方面,如果你是 iPhone 用戶,可以體驗到 Taptic Engine 線性震動馬達,通常力度由輕到重分別是 Light、Medium、Heavy。在打開廣告的那一刻,它給你的是最強震動級別,滿滿的儀式感!整個微信應該找不到第二個這樣級別的震動了。

          提供反饋信息

          再舉一個震動的例子,當你的好友拍攝了時刻視頻后,可以看到 TA 的頭像右上角多了一個藍色的小圈圈,雙擊它就能看到好友的時刻視頻了。

          當然,你雙擊沒有拍攝時刻視頻的好友,TA 的頭像會左右晃動,并且會有 Failure 的震動反饋,動畫和震動節奏完美匹配,這個體驗就像你解鎖 iPhone 輸錯密碼時的震動是一樣的。

          △ 沒有時刻視頻時的反饋

          我們做產品設計時也一樣,對于用戶的操作,應當給予清晰明了的反饋,幫助用戶更好地理解信息。

          跨平臺能力

          微信的起步階段是基于手機來做 App,不基于 PC 來做,PC 端只是輔助,而現在,它的跨平臺能力也逐漸增強。

          一周前,微信 PC 版「微信測試版 for Windows」發布了 2.9.0 的內測,同步了移動端的新功能,主要有兩點:

          支持打開小程序,也可以玩「貪吃蛇」「跳一跳」等小游戲了。

          △ Windows 微信客戶端

          另外,此前的微信 PC 端只支持引用文字消息,也沒有達到手機上引用消息的視覺效果。此次更新中,還新增了很多支持的應用類型,包括但不限于圖片/視頻、表情包、公眾號鏈接、小程序、文件等。

          如此看來,Mac 端的更新也不遠了,可以期待一下。

          語音實時翻譯

          最近的微信更新了,除了引入深色模式之外。值得一提的是,語音消息的交互體驗得到了優化,上滑轉文字更方便了。

          此前的方式是按住說話,滑到轉文字按鈕,說完松開手指后,才把語音解析成文字。

          現在交互則少了一步操作,達到了實時邊說邊轉文字的功能。別小看這一步界面上的優化,它背后代表的是微信語音識別能力上的技術突破。

          △ 語音實時轉文字

          錨點定位

          微信有很多隱性和顯性的錨點,隱性錨點就比如你打開的這篇文章,關閉后,再重新點進來,還是顯示上次閱讀的位置。

          △ 訂閱號列表

          顯性的錨點就比如上面這個:當你刷公眾號列表時候,如果有新文章更新,標題欄會出現一個錨點按鈕,點擊它讓你快速回到頂部,方便查看文章。

          △ 朋友圈「跳到還沒看的位置」

          基于此,在新版微信朋友圈中,增加了一個「跳到還沒看的位置」。很多信息流產品是往下刷內容,直到給你一個分界線提示:下面內容已經看過了。而微信這是一個逆向操作,我認為這個功能還是很有必要的,因為經常會有刷朋友圈刷到一半聊天退出去,當回來查看朋友圈時,需要重新拉到底部,費時費力。

          自然的語音聽筒播放

          《在你身邊,為你設計》一書中有提到語音聽筒播放的優化。大家都知道,手機帶有距離感應器,在感應到耳邊貼近時,屏幕會關閉以節省電力,并且避免由于耳朵與屏幕的觸碰導致的誤操作。

          微信在聊天界面中,也啟用了距離感應,以實現手機貼近耳邊時,自動將語音從揚聲器切換到聽筒進行播放,這樣你可以用最自然的姿勢來聽語音,這是一個很好的體驗。

          但要完美地實現這個體驗,就需要解決距離感應器的時延問題。播放語音時,如果你非常迅速地將手機移至耳邊,這時候距離感應器并不會同樣迅速地對這個動作產生反饋。大約在延遲了 300 毫秒后,感應器發出信號,微信將 iPhone 的屏幕關閉。而在這個時間內,你的耳廓極有可能已經觸碰到了 iPhone 的屏幕上。觸碰的位置大部分時候是左上角的返回按鈕區域。于是很容易出現手機移至耳邊,語音戛然而止。

          △ 延時響應判斷流程圖

          為了解決這個問題,微信設計了一個解決辦法:在響應返回操作時,先等待 500 毫秒,這時候如果偵聽到距離感應器有發出信號,則認為是貼耳的動作,此情況下不執行返回操作,如上圖所示。而 500 毫秒的延時大部分時候你是不會感知到的。這一解決辦法極大降低了貼耳時候的誤操作。

          總結

          在微信的產品設計中,我們看到了交互的細微迭代和背后的技術突破,我們看到了商業創意與用戶體驗的平衡。給用戶帶來希望,讓創造者體現價值,這就是微信的設計之道。

          文章來源:優設    作者:洋爺

          vue + vuex + koa2開發環境搭建及示例開發

          seo達人

          寫在前面

          這篇文章的主要目的是學會使用koa框架搭建web服務,從而提供一些后端接口,供前端調用。
          搭建這個環境的目的是: 前端工程師在跟后臺工程師商定了接口但還未聯調之前,涉及到向后端請求數據的功能能夠走前端工程師自己搭建的http路徑,而不是直接在前端寫幾個死數據。即,模擬后端接口。

          當然在這整個過程(搭建環境 + 開發示例demo)中,涉及到以下幾點知識點。
          包括:

          • koa2的知識點
          • node的知識點
          • 跨域問題
          • fetch的使用
          • axios的使用
          • promise的涉及
          • vuex -> state、mutations、actions的使用

          第一部分:環境搭建

          vue + vuex環境

          首先是vue + vue-router + vuex的環境。我們用vue-cli腳手架生成項目,會用vue的同學對這塊應該很熟了。

          // 全局安裝腳手架工具 npm i vue-cli -g // 驗證腳手架工具安裝成功與否 vue --version // 構建項目 vue init webpack 項目名 // 測試vue項目是否運行成功 npm run dev

          因為腳手架生成的vue項目不包含vuex,所以再安裝vuex。

          // 安裝vuex npm i vuex --save

          koa2環境

          前端項目構建好了,就開始構建我們的后端服務。

          首先在你的開發工具(不管是webstorm還是sublime)里新建一個目錄,用來搭建基于koa的web服務。

          在這里,我們不妨給這個目錄起名為koa-demo。

          然后執行:

          // 進入目錄 cd koa-demo // 生成package.json npm init -y // 安裝以下依賴項 npm i koa npm i koa-router npm i koa-cors

          安裝好koa和兩個中間件,環境就算搭建完成了。

          第二部分:示例開發

          搭建環境是為了使用,所以我們立馬來寫一個demo出來。
          demo開發既是一個練習如何在開發環境中寫代碼的過程,反過來,也是一個驗證環境搭建的對不對、好不好用的過程。

          后端接口開發

          本例中,后端我們只提供一個服務,就是給前端提供一個返回json數據的接口。代碼中包含注釋,所以直接上代碼。

          server.js文件

           // server.js文件 let Koa = require('koa'); let Router = require('koa-router'); let cors = require('koa-cors'); // 引入modejs的文件系統API let fs = require('fs'); const app = new Koa(); const router = new Router(); // 提供一個/getJson接口 router
              .get('/getJson', async ctx => { // 后端允許cors跨域請求 await cors(); // 返回給前端的數據 ctx.body = JSON.parse(fs.readFileSync( './static/material.json'));
          
              }); // 將koa和兩個中間件連起來 app.use(router.routes()).use(router.allowedMethods()); // 監聽3000端口 app.listen(3000);

          這里面用到了一個json文件,在'./static/material.json'路徑,該json文件的代碼是:

          // material.json文件 [{ "id": 1, "date": "2016-05-02", "name": "張三", "address": "北京 清華大學",
          }, { "id": 2, "date": "2016-05-04", "name": "李四", "address": "上海 復旦大學",
          }, { "id": 3, "date": "2016-05-01", "name": "王五", "address": "廣東 中山大學",
          }, { "id": 4, "date": "2016-05-03", "name": "趙六", "address": "廣東 深圳大學",
          }, { "id": 5, "date": "2016-05-05", "name": "韓梅梅", "address": "四川 四川大學",
          }, { "id": 6, "date": "2016-05-11", "name": "劉小律", "address": "湖南 中南大學",
          }, { "id": 7, "date": "2016-04-13", "name": "曾坦", "address": "江蘇 南京大學",
          }] 

          然后我們是用以下命令將服務啟動

          node server.js

          測試接口是否良好

          打開瀏覽器,輸入http://127.0.0.1:3000/getJson??匆豢错撁嫔鲜欠駥son文件中的json數據顯示出來,如果能夠顯示出來,則說明這個提供json數據的服務,我們已經搭建好了。

          前端調用后端接口示例

          為突出重點,排除干擾,方便理解。我們的前端就寫一個組件,組件有兩部分:首先是一個按鈕,用來調用web服務的getJson接口;然后是一個內容展示區域,拿到后端返回的數據以后,將其在組件的這塊區域顯示出來。

          首先我們看組件文件

          <template> <div class="test"> <button type="button" @click="getJson">從后端取json</button> <div class="showJson">{{json}}</div> </div> </template> <script> import {store} from '../vuex' export default { computed: {
                    json(){ return store.state.json;
                    }
                  }, methods: {
                    getJson(){
                        store.dispatch("getJson");
                    }
                  }
              } </script> <style scoped> .showJson{ width:500px; margin:10px auto; min-height:500px; background-color: palegreen;
            } </style> 

          非常簡單,就不多解釋了。
          然后看我們的vuex文件

          import Vue from 'vue' import Vuex from 'vuex';
          
          Vue.use(Vuex) const state = { json: [],
          }; const mutations = {
            setJson(state, db){
              state.json = db;
            }
          } const actions = {
            getJson(context){ // 調用我們的后端getJson接口 fetch('http://127.0.0.1:3000/json', { method: 'GET', // mode:'cors', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json',
                },
              }).then(function (res) { if(res.status === 200){ return res.json()
                }
              }).then(function (json) { //console.log(typeof Array.from(json), Array.from(json)); context.commit('setJson', Array.from(json));
              })
            }
          }; export const store = new Vuex.Store({ state: state, mutations: mutations, actions: actions,
          })

          ok, 代碼擼完了,獲取后端數據之前是這樣的。

          獲取后端數據之后是這樣的。

          說說axios

          想要把本demo的fetch改為axios方式,要做的工作有以下幾處:
          1、安裝axios、在vuex文件引用axios

          npm i axios import axios from 'axios'

          2、將fetch部分代碼替換為:

          const actions = {
            getJson(context){
              axios.get('/json', { method: 'GET', // mode:'cors', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json',
                },
              }).then(function (res) { if(res.status === 200){ return res.data
                }
              }).then(function (json) { //console.log(typeof Array.from(json), Array.from(json)); context.commit('setJson', Array.from(json));
              })
            }
          };

          3、又會遇到跨域,在webpack中修改,路徑config/index.js文件中添加proxyTable項的配置:

          proxyTable: { '/json': { target: 'http://127.0.0.1:3000', changeOrigin: true, pathRewrite: { '^/json': '/json' }
                }
              },

          后記

          基于vue腳手架搭建的項目,模擬異步取數據,也可以直接在腳手架生成的static文件夾下放置數據,假裝是后臺拿過來的數據。

          不過搭建一個基于express或者koa的web服務,確實也該是一個前端工程師應該掌握的。

          OK,以上就是全文了。
          如果這篇文章使你有所收獲,不勝榮幸。
          歡迎點贊,以期能幫助更多同學!

          GitHub如何配置SSH Key

          前端達人

          文章目錄

            • 步驟


            • https://github.com/xiangshuo1992/preload.git
              git@github.com:xiangshuo1992/preload.git
              這兩個地址展示的是同一個項目,但是這兩個地址之間有什么聯系呢?
              前者是https url 直接有效網址打開,但是用戶每次通過git提交的時候都要輸入用戶名和密碼,有沒有簡單的一點的辦法,一次配置,永久使用呢?當然,所以有了第二種地址,也就是SSH URL,那如何配置就是本文要分享的內容。
              GitHub配置SSH Key的目的是為了幫助我們在通過git提交代碼是,不需要繁瑣的驗證過程,簡化操作流程。
              
              步驟
                      

              一、設置git的user name和email

              如果你是第一次使用,或者還沒有配置過的話需要操作一下命令,自行替換相應字段。
              git config --global user.name "Luke.Deng"
              git config --global user.email  "xiangshuo1992@gmail.com"
                    
                      

              二、檢查是否存在SSH Key

              cd ~/.ssh
              ls
              或者
              ll
              //看是否存在 id_rsa 和 id_rsa.pub文件,如果存在,說明已經有SSH Key
              如果沒有SSH Key,則需要先生成一下
              
              
              ssh-keygen -t rsa -C "xiangshuo1992@gmail.com"
                    
                      

              三、獲取SSH Key

              cat id_rsa.pub
              //拷貝秘鑰 ssh-rsa開頭
                    
                      

              四、GitHub添加SSH Key

              GitHub點擊用戶頭像,選擇setting
               
              新建一個SSH Key 
              取個名字,把之前拷貝的秘鑰復制進去,添加就好啦。
                    
                      

              五、驗證和修改

              測試是否成功配置SSH Key
              
              
              ssh -T git@github.com
              //運行結果出現類似如下
              Hi xiangshuo1992! You've successfully authenticated, but GitHub does not provide shell access.
              之前已經是https的鏈接,現在想要用SSH提交怎么辦?
              直接修改項目目錄下 .git文件夾下的config文件,將地址修改一下就好了。
                    
                      


              ———————————————— 版權聲明:本文為CSDN博主「前端向朔」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。 原文鏈接:https://blog.csdn.net/u013778905/java/article/details/83501204



          深入理解vue中的slot與slot-scope

          seo達人

          寫在前面

          vue中關于插槽的文檔說明很短,語言又寫的很凝練,再加上其和methods,data,computed等常用選項使用頻率、使用先后上的差別,這就有可能造成初次接觸插槽的開發者容易產生“算了吧,回頭再學,反正已經可以寫基礎組件了”,于是就關閉了vue說明文檔。

          實際上,插槽的概念很簡單,下面通過分三部分來講。這個部分也是按照vue說明文檔的順序來寫的。

          進入三部分之前,先讓還沒接觸過插槽的同學對什么是插槽有一個簡單的概念:插槽,也就是slot,是組件的一塊HTML模板,這塊模板顯示不顯示、以及怎樣顯示由父組件來決定。 實際上,一個slot最核心的兩個問題這里就點出來了,是顯示不顯示怎樣顯示

          由于插槽是一塊模板,所以,對于任何一個組件,從模板種類的角度來分,其實都可以分為非插槽模板插槽模板兩大類。
          非插槽模板指的是html模板,指的是‘div、span、ul、table’這些,非插槽模板的顯示與隱藏以及怎樣顯示由插件自身控制;插槽模板是slot,它是一個空殼子,因為它顯示與隱藏以及最后用什么樣的html模板顯示由父組件控制。但是插槽顯示的位置確由子組件自身決定,slot寫在組件template的哪塊,父組件傳過來的模板將來就顯示在哪塊。

          單個插槽 | 默認插槽 | 匿名插槽

          首先是單個插槽,單個插槽是vue的官方叫法,但是其實也可以叫它默認插槽,或者與具名插槽相對,我們可以叫它匿名插槽。因為它不用設置name屬性。

          單個插槽可以放置在組件的任意位置,但是就像它的名字一樣,一個組件中只能有一個該類插槽。相對應的,具名插槽就可以有很多個,只要名字(name屬性)不同就可以了。

          下面通過一個例子來展示。

          父組件:

          
              
          1. <template>
          2. <div class="father">
          3. <h3>這里是父組件</h3>
          4. <child>
          5. <div class="tmpl">
          6. <span>菜單1</span>
          7. <span>菜單2</span>
          8. <span>菜單3</span>
          9. <span>菜單4</span>
          10. <span>菜單5</span>
          11. <span>菜單6</span>
          12. </div>
          13. </child>
          14. </div>
          15. </template>

          子組件:

          
              
          1. <template>
          2. <div class="child">
          3. <h3>這里是子組件</h3>
          4. <slot></slot>
          5. </div>
          6. </template>

          在這個例子里,因為父組件在<child></child>里面寫了html模板,那么子組件的匿名插槽這塊模板就是下面這樣。也就是說,子組件的匿名插槽被使用了,是被下面這塊模板使用了。

          
              
          1. <div class="tmpl">
          2. <span>菜單1</span>
          3. <span>菜單2</span>
          4. <span>菜單3</span>
          5. <span>菜單4</span>
          6. <span>菜單5</span>
          7. <span>菜單6</span>
          8. </div>

          最終的渲染結果如圖所示:


          
              
          1. 注:所有demo都加了樣式,以方便觀察。其中,父組件以灰色背景填充,子組件都以淺藍色填充。

          具名插槽

          匿名插槽沒有name屬性,所以是匿名插槽,那么,插槽加了name屬性,就變成了具名插槽。具名插槽可以在一個組件中出現N次。出現在不同的位置。下面的例子,就是一個有兩個具名插槽單個插槽的組件,這三個插槽被父組件用同一套css樣式顯示了出來,不同的是內容上略有區別。

          父組件:

          
              
          1. <template>
          2. <div class="father">
          3. <h3>這里是父組件</h3>
          4. <child>
          5. <div class="tmpl" slot="up">
          6. <span>菜單1</span>
          7. <span>菜單2</span>
          8. <span>菜單3</span>
          9. <span>菜單4</span>
          10. <span>菜單5</span>
          11. <span>菜單6</span>
          12. </div>
          13. <div class="tmpl" slot="down">
          14. <span>菜單-1</span>
          15. <span>菜單-2</span>
          16. <span>菜單-3</span>
          17. <span>菜單-4</span>
          18. <span>菜單-5</span>
          19. <span>菜單-6</span>
          20. </div>
          21. <div class="tmpl">
          22. <span>菜單->1</span>
          23. <span>菜單->2</span>
          24. <span>菜單->3</span>
          25. <span>菜單->4</span>
          26. <span>菜單->5</span>
          27. <span>菜單->6</span>
          28. </div>
          29. </child>
          30. </div>
          31. </template>

          子組件:

          
              
          1. <template>
          2. <div class="child">
          3. // 具名插槽
          4. <slot name="up"></slot>
          5. <h3>這里是子組件</h3>
          6. // 具名插槽
          7. <slot name="down"></slot>
          8. // 匿名插槽
          9. <slot></slot>
          10. </div>
          11. </template>

          顯示結果如圖:


          可以看到,父組件通過html模板上的slot屬性關聯具名插槽。沒有slot屬性的html模板默認關聯匿名插槽。

          作用域插槽 | 帶數據的插槽

          最后,就是我們的作用域插槽。這個稍微難理解一點。官方叫它作用域插槽,實際上,對比前面兩種插槽,我們可以叫它帶數據的插槽。什么意思呢,就是前面兩種,都是在組件的template里面寫

          
              
          1. 匿名插槽
          2. <slot></slot>
          3. 具名插槽
          4. <slot name="up"></slot>

          但是作用域插槽要求,在slot上面綁定數據。也就是你得寫成大概下面這個樣子。

          
              
          1. <slot name="up" :data="data"></slot>
          2. export default {
          3. data: function(){
          4. return {
          5. data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
          6. }
          7. },
          8. }

          我們前面說了,插槽最后顯示不顯示是看父組件有沒有在child下面寫模板,像下面那樣。

          
              
          1. <child>
          2. html模板
          3. </child>

          寫了,插槽就總得在瀏覽器上顯示點東西,東西就是html該有的模樣,沒寫,插槽就是空殼子,啥都沒有。
          OK,我們說有html模板的情況,就是父組件會往子組件插模板的情況,那到底插一套什么樣的樣式呢,這由父組件的html+css共同決定,但是這套樣式里面的內容呢?

          正因為作用域插槽綁定了一套數據,父組件可以拿來用。于是,情況就變成了這樣:樣式父組件說了算,但內容可以顯示子組件插槽綁定的。

          我們再來對比,作用域插槽和單個插槽和具名插槽的區別,因為單個插槽和具名插槽不綁定數據,所以父組件是提供的模板要既包括樣式由包括內容的,上面的例子中,你看到的文字,“菜單1”,“菜單2”都是父組件自己提供的內容;而作用域插槽,父組件只需要提供一套樣式(在確實用作用域插槽綁定的數據的前提下)。

          下面的例子,你就能看到,父組件提供了三種樣式(分別是flex、ul、直接顯示),都沒有提供數據,數據使用的都是子組件插槽自己綁定的那個人名數組。

          父組件:

          
              
          1. <template>
          2. <div class="father">
          3. <h3>這里是父組件</h3>
          4. <!--第一次使用:用flex展示數據-->
          5. <child>
          6. <template slot-scope="user">
          7. <div class="tmpl">
          8. <span v-for="item in user.data">{{item}}</span>
          9. </div>
          10. </template>
          11. </child>
          12. <!--第二次使用:用列表展示數據-->
          13. <child>
          14. <template slot-scope="user">
          15. <ul>
          16. <li v-for="item in user.data">{{item}}</li>
          17. </ul>
          18. </template>
          19. </child>
          20. <!--第三次使用:直接顯示數據-->
          21. <child>
          22. <template slot-scope="user">
          23. {{user.data}}
          24. </template>
          25. </child>
          26. <!--第四次使用:不使用其提供的數據, 作用域插槽退變成匿名插槽-->
          27. <child>
          28. 我就是模板
          29. </child>
          30. </div>
          31. </template>

          子組件:

          
              
          1. <template>
          2. <div class="child">
          3. <h3>這里是子組件</h3>
          4. // 作用域插槽
          5. <slot :data="data"></slot>
          6. </div>
          7. </template>
          8. export default {
          9. data: function(){
          10. return {
          11. data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
          12. }
          13. }
          14. }

          結果如圖所示:

          github

          以上三個demo就放在GitHub了,有需要的可以去取。使用非常方便,是基于vue-cli搭建工程。

          https://github.com/cunzaizhuyi/vue-slot-demo

          你真的了解重排和重繪嗎?

          前端達人

          做過前端開發的小伙伴就算不是非常理解重排與重繪,但是肯定都聽過這兩個詞。那為什么這兩個東西這么重要?因為他與我們的頁面性能息息相關,今天,我們就來好好研究一下這兩個東西。



          瀏覽器的渲染流程

          在講解重排和重繪之前,我們有必要說一下瀏覽器的渲染流程。下面是瀏覽器渲染過程中最關鍵的幾個部分。如果想了解完整的瀏覽器渲染流程,推薦大家去閱讀李兵老師的瀏覽器工作原理實踐,需要付費閱讀。后期我也會整理一下再出一篇博客詳細介紹瀏覽器的渲染過程。


          點擊查看原圖


          JavaScript:一般來說,我們會使用 JavaScript 來實現一些視覺變化的效果。比如用 jQuery 的 animate 函數做一個動畫、對一個數據集進行排序或者往頁面里添加一些 DOM 元素等。當然,除了 JavaScript,還有其他一些常用方法也可以實現視覺變化效果,比如:CSS Animations、Transitions 和 Web Animation API。
          樣式計算:此過程是根據匹配選擇器(例如 .headline 或 .nav > .nav__item)計算出哪些元素應用哪些 CSS 規則的過程。從中知道規則之后,將應用規則并計算每個元素的最終樣式。
          布局:在知道對一個元素應用哪些規則之后,瀏覽器即可開始計算它要占據的空間大小及其在屏幕的位置。網頁的布局模式意味著一個元素可能影響其他元素,例如 元素的寬度一般會影響其子元素的寬度以及樹中各處的節點,因此對于瀏覽器來說,布局過程是經常發生的。
          繪制:繪制是填充像素的過程。它涉及繪出文本、顏色、圖像、邊框和陰影,基本上包括元素的每個可視部分。繪制一般是在多個表面(通常稱為層)上完成的。
          合成:由于頁面的各部分可能被繪制到多層,由此它們需要按正確順序繪制到屏幕上,以便正確渲染頁面。對于與另一元素重疊的元素來說,這點特別重要,因為一個錯誤可能使一個元素錯誤地出現在另一個元素的上層。
          其中,重排和重繪影響的就是其中的布局和繪制過程。

          什么是重排和重繪制
          重排:當DOM的變化引發了元素幾何屬性的變化,比如改變元素的寬高,元素的位置,導致瀏覽器不得不重新計算元素的幾何屬性,并重新構建渲染樹,這個過程稱為“重排”。
          重繪:完成重排后,要將重新構建的渲染樹渲染到屏幕上,這個過程就是“重繪”。
          簡單來說,涉及元素的幾何更新時,叫重排。而只涉及樣式更新而不涉及幾何更新時,叫重繪。對于兩者來說,重排必定引起重繪,但是重繪并不一定引起重排。所以,當涉及重排時,瀏覽器會將上述的步驟再次執行一遍。當只涉及重繪時,瀏覽器會跳過Layout步驟,即:


          點擊查看原圖


          而如果既不需要重排,也不需要重繪,那么就是下面這樣:


          點擊查看原圖



          瀏覽器會直接跳到合成階段。顯然,對于頁面性能來說,不重排也不重繪 > 重繪 > 重排。

          什么操作會引起重排和重繪
          顯然,觸發重排的一般都是幾何因素,這是比較好理解的:

          頁面第一次渲染 在頁面發生首次渲染的時候,所有組件都要進行首次布局,這是開銷最大的一次重排
          瀏覽器窗口尺寸改變
          元素位置和尺寸發生改變的時候
          新增和刪除可見元素
          內容發生改變(文字數量或圖片大小等等)
          元素字體大小變化
          還有其他一些操作也可能引發重排

          查詢某些屬性或調用某些方法
          offset(Top|Left|Width|Height)
          scroll(Top|Left|Width|Height)
          client(Top|Left|Width|Height)
          getComputedStyle()
          我們可能不太理解為什么這些操作也能引起重排,這里我先簡單解釋一下。因為現在的瀏覽器已經非常完善了,會自動幫我們做一些優化。當我們用js操作DOM的時候,瀏覽器并不是立馬執行的,而是將操作存儲在一個隊列中。當達到一定數量或者經過一定時間以后瀏覽器再統一的去執行隊列中的操作。那么回到我們剛才的問題,為什么查詢這些屬性也會導致重排?因為當你查詢這些屬性時,瀏覽器就會強制刷新隊列,因為如果不立馬執行隊列中的操作,有可能得到的結果就是錯誤的。所以相當于你強制打斷了瀏覽器的優化流程,引發了重排。下面我們通過一些小例子來進一步理解這段話:

          首先我們來一個顯然會引發重排的操作

          <!DOCTYPE html>
          <html lang="en">
          <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Document</title>
            <style>
              #test {
                width: 100px;
                height: 100px;
                background-color: red;
                position: relative;
              }
            </style>
          </head>
          <body>
            <div id="test">
          
            </div>
            <button onclick="reflow()">click</button>
            <script>
              function reflow() {
                var div = document.querySelector("#test");
                div.style.left = '200px';
              }
            </script>
          </body>
          </html>
          



          把時間軸往后拉,可以看到這幾個過程,先簡單介紹一些這些名詞代表的含義:

          Recalculate Style:這個過程就是生成CSSOM的過程
          Layout:這就是布局階段,即重排的過程
          Update Layer Tree:這個階段是更新層樹的過程
          Paint:該階段是為每一層準備繪制列表的過程
          Composite Layers:該階段是利用繪制列表來生成相應圖層的位圖了,還涉及到合成線程和光柵化,performence面板中的Raster就是光柵化線程池 。
          這里只做一個簡單的介紹,對其中內容不太明白的同學可以參考李兵老師的文章或者在我的下一篇介紹瀏覽器渲染過程的文章中會詳細解釋。

          那通過這個圖我們可以看到,我們改變了div的left之后就觸發了Layout,即重排的過程。下面我們僅改變div的背景顏色,給大家一個對比。


          即不重排也不重繪
          說完了重排和重繪,不要忘記我們最開始提到的,最的方式就是跳過重排和重繪階段。你可能會想,什么情況下可以做到這一點?其實這就是我們平時說的GPU加速,具體是如何實現呢?在開發過程中,如果我們使用了某些屬性,瀏覽器會幫助我們將使用了該屬性的div提升到一個單獨的合成層,而在后面的渲染中,提升到該層的div將跳過重排和重繪的操作,直接到合成階段。在stack overflow上有問題提到了這塊內容。我們翻譯一下就是:
          下面幾個屬性能讓瀏覽器幫助我們將div提升到一個單獨的合成層:

          圖層具有3D或透視變換CSS屬性
          使用加速視頻解碼的 video 元素
          擁有 3D(WebGL) 上下文或者加速 2D 上下文的 canvas 元素
          混合插件(Flash)
          對自己的 opacity 做 CSS 動畫或使用一個動畫 webkit 變換的元素
          圖層使用加速的CSS過濾器
          層具有作為合成層的后代
          圖層具有較低z索引的同級元素,該同級元素具有合成層(換句話說,該層在合成層的頂部渲染)
          css will-change屬性
          最后一點是我加上去的,同時根據文中的內容我們可以知道,css3硬件加速是瀏覽器的行為,所以在不同瀏覽器下可能會有不同的表現形式。下面我們用一個例子來理解一下。這是李兵老師在他的專欄中提出的一個例子,我拿過來借用一下,注意box中的will-change屬性:

          <html>
          
            <head>
                <title>觀察will-change</title>
                <style>
                    .box {
                        will-change: transform, opacity;
                        display: block;
                        float: left;
                        width: 40px;
                        height: 40px;
                        margin: 15px;
                        padding: 10px;
                        border: 1px solid rgb(136, 136, 136);
                        background: rgb(187, 177, 37);
                        border-radius: 30px;
                        transition: border-radius 1s ease-out;
                    }
          
                    body {
                        font-family: Arial;
                    }
                </style>
            </head>
          
            <body>
                <div id="controls">
                    <button id="start">start</button>
                    <button id="stop">stop</button>
                </div>
                <div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                    <div class="box">旋轉盒子</div>
                </div>
                <script>
          
                    let boxes = document.querySelectorAll('.box');
                    let boxes1 = document.querySelectorAll('.box1');
                    let start = document.getElementById('start');
                    let stop = document.getElementById('stop');
                    let stop_flag = false
          
                    start.addEventListener('click', function () {
                        stop_flag = false
                        requestAnimationFrame(render);
                    })
          
                    stop.addEventListener('click', function () {
                        stop_flag = true
                    })
          
                    let rotate_ = 0
                    let opacity_ = 0
                    function render() {
                        if (stop_flag)
                            return 0
                        rotate_ = rotate_ + 6
                        if (opacity_ > 1)
                            opacity_ = 0
                        opacity_ = opacity_ + 0.01
                        let command = 'rotate(' + rotate_ + 'deg)';
                        for (let index = 0; index < boxes.length; index++) {
                            boxes[index].style.transform = command
                            boxes[index].style.opacity = opacity_
                        }
                        requestAnimationFrame(render);
                    }
                </script>
            </body>
          
            </html>
          



          ————————————————
          版權聲明:本文為CSDN博主「溪寧」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
          原文鏈接:https://blog.csdn.net/qq_38164763/article/details/105406580

          【CSS基礎學習】復雜選擇器

          前端達人

          文章目錄

            • CSS第二課-復雜選擇器
              • 群組選擇器
              • 屬性選擇器
              • 派生選擇器
              • CSS第二課-復雜選擇器

                群組選擇器

                格式

                選擇器1,選擇器2,,,選擇器n{聲明的屬性和屬性值}

                p,h1{
                    color: blue;
                }


                用于對于多個選擇器進行樣式修改,由簡單選擇器組合而成的選擇器,可以是簡單選擇器中的任意組合,如上面代碼例,就是修改了p標簽和h1標簽的字體顏色。

                屬性選擇器

                根據屬性名查找元素

                格式

                元素[屬性名]{
                    聲明的屬性和屬性值;
                }


                p[id]{
                    color: blue;
                }


                前面添加元素的名字,然后后面加上屬性名,比如上例,就是p標簽,其中帶有id的元素,然后把字體顏色設置為藍色。

                根據屬性值查找

                格式

                元素[屬性名=屬性值]{
                    聲明的屬性和屬性值;
                }


                p[class = 'p2']{
                    color: blue;
                }


                和上面的根據屬性名查找差不多,只不過更加了,到了屬性名后面的屬性值,上例就是作用于p標簽,只不過條件是為帶有class屬性,并且屬性值為p2的p標簽。

                多屬性選擇器

                格式


                元素[屬性名或屬性表達式][屬性名或屬性表達式]..{
                    聲明的屬性和屬性值;
                }
                p[title][class]{
                    color: blue;
                }



                元素后面加。屬性名或屬性表達式,可以加+∞個,但是沒必要。上例為:設置title屬性和class屬性的段落p標簽的樣式

                根據屬性值近似查找

                格式


                元素[元素名~=屬性值]{
                    聲明的屬性和屬性值;
                }


                元素[屬性名|=值]{
                    聲名的屬性和屬性值;
                }


                p[class~='red']{
                    color: blue;
                }



                注意,這里是~=,為約等于,就是找滿足符合約等于條件的標簽,上例為:設置class屬性的值,包含red屬性名的標簽

                根據標簽查找

                格式


                元素名1~元素名2{
                    聲名的屬性和屬性值;
                }


                a~p{
                    color: blue;
                }


                a標簽后面的每一個p標簽,都進行了樣式的修改。

                派生選擇器

                后代選擇器

                格式


                父類標簽 子類標簽{ /*注意倆標簽中間有空格*/
                    聲名的屬性和屬性值;
                }


                div strong{
                    color: blue;
                }


                相鄰兄弟選擇器

                格式


                父標簽+子標簽{
                    聲名的屬性和屬性值;
                }


                #div1 + p{
                    color: blue;
                }


                相鄰兄弟選擇器可選擇緊接在另一個元素后的元素,且二者具有相同的父親元素。注釋:與子結合符一樣,相鄰兄弟結合符旁邊可以有空白符。




                ————————————————
                版權聲明:本文為CSDN博主「董小宇」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
                原文鏈接:https://blog.csdn.net/lolly1023/article/details/105413125

          B端系統設計全方位指南

          濤濤

          什么是B端產品?

          B 端產品也叫 2B(to Business)產品,使用對象一般為企業客戶或組織。B 端產品幫助企業或組織通過協同辦公,解決某類管理問題,承擔著為企業或組織提升效率、降低成本、控制風險從而提高企業收入,減少企業內部損耗的重要職責。B 端產品的工作是合理實現企業需求,提高產品核心競爭力,并提升市場價值。在國內互聯網語境中,B 端產品的狹義解釋也基本可以和面向企業的 「網頁程序」 等同,用更接地氣的稱呼可以叫「管理平臺」、「管理端」 。

          B 端產品大致分為兩類,一種是支撐前臺產品的,一種是管理各種資源的,前者就是我們熟悉的后臺產品,后者就是給各個企業服務,提高各個企業工作效率的 B 端產品。

          1. 支撐前臺產品的:

          C 端產品線的后臺產品,比如我們常用的淘寶、微信、餓了么、美團這種 C 端產品,他都需要有個后臺進行各種前端信息的管理。

          平臺級工具產品,比如微信公眾號、頭條號等對用戶和文章的數據實時統計,可編輯文章,回復消息等

          2. 管理各種資源的:

          • OA 辦公系統(OA 系統是通過程序的形式使辦公流程自動化的解決方案)
          • CRM 系統 (CRM 是企業專門用來管理客戶的工具)
          • SaaS 系統(SAAS 通常它指第三方提供給企業的線上軟件服務,它既可以包含前面幾種服務類型,也可以是一些更細化的需求。)
          • ERP 系統(ERP 是對企業所擁有、調動的資源進行統一管理的平臺)
          • WMS 系統(WMS 是倉庫管理系統的縮寫,通過入庫業務、出庫業務、倉庫調撥、庫存調撥和虛倉管理等功能,綜合批次管理、物料對應、庫存盤點、質檢管理、虛倉管理和即時庫存管理等功能綜合運用的管理系統)
          • TMS 系統(TMS 是運輸管理系統能夠對物流公司的所有車輛進行實時跟蹤(結合 GPS 系統),保持信息流和物流的暢通。)
          • 呼叫中心客服系統
          • FMS 財務管理系統

          B端和C端的區別

          1. 從定義上:

          • B 端:To B 就是 To business,面向企業或者特定用戶群體的企業級別產品;
          • C 端:To C 就是 To customer,產品面向普通大眾消費者。

          2. 從用戶群體上:

          • B 端:產品一般是多種角色,有決策者、管理者和執行者,B 端往往是基于公司層面多人對某一問題解決方案進行整體評估。
          • C 端:用戶群體較單一,或者是專注于某一領域群體,可根據性別,職業或行為偏好等關鍵屬性進行分類。

          3. 業務場景

          • B 端:業務場景多、邏輯復雜,根據每個人角色需要有不同的解決方案
          • C 端:業務場景較單一,或者專注于某個垂直的使用場景。

          4. 用戶的訴求:

          • B 端:控制成本、提率,注重安全和穩定
          • C 端:重視人性和用戶體驗

          5. 盈利模式:

          • B 端:有明確的盈利模式和用戶群體。
          • C 端:大部份 C 端產品都是使用免費,以此吸引用戶使用,等積累到一定數量需要探索變現的路徑,或者尋找其他變現的路徑。

          B端產品該如何設計?

          了解了 B 端和 C 端的區別,B 端產品的實用性大于美觀性,能切實解決問題、配置資源的 B 端產品才是一個好的 B 端產品。在設計上對于操作和展示內容無關的元素,越少越好。很多人剛開始接觸 B 端,會熱衷于以 C 端視覺標準進行設計,對于真實的使用體驗來說顯得過于冗余、炫技。那么在 B 端設計中該如何思考去設計呢?下面我以設計前、中、后的三個方向去闡述我在做 B 端設計中的一些思考:

          1. 設計前:

          需求分析

          • 分析產品的背景是什么,要做什么,要給用戶怎樣的視覺感受?他的競品狀況是怎樣的進行一些分析(一般 b 端的產品競品是極少的),了解一些行業內的資料。
          • 目標用戶群有哪些?不同角色的用戶有哪些具體的權限?(這里簡要了解下大概的人群,沒必要像 c 端產品那種那么明確)
          • 設計的產品主要解決用戶或者業務上的哪些具體痛點,復現分析下使用場景,在需求分析階段,要對產品本身和行業本身有一些基本的認知。

          使用場景、硬件情況

          • 了解用戶的使用場景,可以有助于我們復現分析用戶是如何使用我們設計的界面的。
          • 用戶的硬件情況,了解主流用戶的屏幕分辨率是多少,根據主流分辨率做設計稿。現在 PC 主流的分辨率占比排名前三的是 1920*1080、1366*768、1440*900,以 1440 來設計的話,向上適配或者向下適配誤差會比較小。這里也不是必需,如果用戶全部都是用小屏筆記本辦公,在 1920 設計稿上做適配可能小屏幕上展示會出現滾動條,會比較擁擠。

          梳理交互流程:拿到需求后切勿打開花瓣站酷一陣擼,一定要對需求進行梳理(有的公司有專門的交互設計來做)做 B 端產品最重要的是對業務的理解,在梳理過程中一定要跟產品隨時溝通,產品的業務流程是怎樣的?有哪些同類型的產品?和他們相比我們的產品有什么特色和特點?充分理解了業務再去做設計就會有事半功倍的效果。

          情緒版,定義風格:梳理完需求就可以定義設計風格了,在設計風格上盡量做到簡潔,B 端產品實用性大于美觀性,減少不必要的裝飾元素給用戶操作上帶來干擾。這里可以運用情緒版去定義設計風格,大概的流程就是,根據產品業務背景定義設計關鍵詞、根據關鍵詞去找參考圖片定義設計風格,產品的主題色也可以根據情緒版來去定義。

          2. 設計中:

          布局上根據導航可分為以下三種:

          水平導航布局:類似于普通網頁的布局樣式導航,順應了從上至下的正常瀏覽 順序,方便瀏覽信息;頂部寬度限制了導航的數量和文本長度。適用于導航較少,頁面篇幅較長的產品。

          垂直導航布局:可將導航欄固定在左側,提高導航可見性,方便頁面之間切換;頂部可放置常用工具,如搜索條、幫助按鈕、通知按鈕等。菜單欄還可以展開收起,適用于結構簡單的產品。

          混合導航布局:結合了水平導航和垂直導航的特點,層級可以擴展到二、三級菜單,且能夠更加清晰地區分常用業務功能操作和輔助操作。適用于功能模塊較多、較復雜的工具類型后臺。

          不同形態的布局,適配方式也不同。在做設計之前了解下適配的原理,避免在不同設備上出現視覺上的誤差。水平導航布局,在適配方案中做法是對兩邊留白區域進行最小值的定義,當留白區域到達限定值之后再對中間的主內容區域進行動態縮放。如圖:

          垂直導航布局和混合型導航布局,在適配方案中常見的做法是將左邊的導航欄固定,對右邊的工作區域進行動態縮放。如圖:

          最后說一下布局上的柵格,柵格會使整體頁面更加工整簡潔,內容區域采用 24 柵格(并非固定數值,參照案例 24 柵格布局),就不一一敘述柵格的定義與運用了,大家可以參考下網上有好多關于柵格的文章,如圖:

          顏色

          顏色上大致分為品牌色(可以結合業務屬性)、功能色(比如紅黃綠藍燈成功、出錯、失敗、提醒、鏈接等。功能色的選取需要遵循用戶對色彩的基本認知)、 中性色(如深灰中灰淺灰,文字部分應用居多,此外背景、邊框、分割線、等場景中也非常常見) 其他色如統計圖、數據可視化、多個標簽的不同配色方案根據項目情況單獨設定。

          字體

          在 B 端系統中優先使用系統默認的界面字體,常用中文字體有微軟雅黑、蘋方、思源黑體,英文字體有 Arial、Helvetica 系統不同展示的字體也不相同。

          字體大小常見的有 12px、13px、14px、16px、20px、24px、30px 等。

          規范

          一份好的規范能夠讓設計和開發更加的工作,并且能夠指引一些設計的細節,通過對大小、顏色、邊距等、呼吸感等一些細節點的標注,可以讓新加入的設計師快速上手設計。一個項目會有多個設計師的參與,規范化的設計語言,避免因設計控件混亂而影響設計輸出。好的設計規范還能統一在產品中不同頁面的相同板塊的樣式問題,為開發組件庫奠定基礎。

          如何建立一份規范呢?大概總結以下幾點:

          • 首先是要梳理產品中不同板塊所出現的場景進程收集(收集產品所有出現過的場景進行整理)
          • 其次是把收集完的板塊歸納分類(不同的樣式、狀態等可以分成不同的種類)
          • 最后就可以定義規范了。

          定義好設計規范能大大提高設計師的工作效率,在同一個項目中也能更好的把控項目的視覺規范,幫助設計師復用及設計延展。

          組件

          B 端產品的決策方是老板和管理層,在設計 B 端產品中往往也是大多數情況下會有接到比較緊急的需求的情況,所以在設計過程中就需要我們設計師更加去注重效率,提高產能。做東西時要有組件化思維,去總結分析頁面模塊中的一些共性,跟開發共同完成產品的組件庫。

          如果沒有前端工程師,我們的設計組件庫就是 PNG。所以,在開工前,一定要和那個技術不錯的前端工程師聊聊做設計組件庫的事情,其中最重要的是確定好:選擇什么樣的前端框架。

          如果組件庫服務的是 B 端或者中后臺系統,那其實有很多可參考的開源組件框架:Ant Design、ElemetUI、Layui 等,注意不同的框架用到的前端技術不一樣,兼容的瀏覽器版本也不一樣,這要根據你們技術情況做選擇。如果覺得開源框架的風格和你們的產品不統一,那就需要二次設計和開發封裝。

          下面是螞蟻金服組件庫,如圖根據組件的功能特點做出了分類:通用、布局、導航、數據錄入、數據展示、反饋、其他等。大家可以去官網查看,這里就不再一一做闡述了。

          這個是餓了么的組件庫:

          推薦幾個官方組件庫:

          做之前大家一定要去多去查看這些大廠做的已成型的開源組件庫,然后再結合工作業務特色做出自己公司特有的定制化組件庫。有了組件庫之后,再接到緊急需求,我們就可以做到事半功倍的效果。先去分析頁面的構成,然后花費 80% 的時間去設計需求中 20% 的頁面,剩下的通用型頁面就可以直接用組件庫堆出來了。

          3. 設計后:

          設計走查

          在完成設計后,要整體對設計頁面進行走查。從信息層級、文字、圖標、圖片等方面進行多次設計驗證與測試。

          高質量設計交付

          設計稿命名一定要清晰規范,現在好多切圖標注的插件,一鍵生成切圖標注。現在就沒有必要單獨整理切圖標注了,但是設計稿在交付前切圖的命名一定要在設計稿里整理清楚,規范命名方便開發查閱。

          推薦幾款比較常用的切圖標注的插件:

          設計追蹤、校驗

          設計稿給到開發在設計過程中,要隨時跟開發溝通。項目上線后要對線上效果進行實時 UI 校驗,保證開發同學對設計稿的高度還原。還有就是對設計上線后的驗證工作,用戶使用和反饋是優化產品的重要途徑,針對性地在一些主流的頁面模塊按鈕進行一些數據的埋點,統計下用戶的點擊狀況,實時對數據進行一些跟進,為下次頁面改版優化,提供有力的數據支撐,提升產品的用戶體驗。

          總結

          不管 B 端還是 C 端,設計的價值在于通過視覺表現的方式去助力公司、助力產品實現用戶的需求、幫助用戶解決問題。B 端產品相對而言,場景、功能、業務流程、信息架構要比 C 端更復雜,面對的異常情況也比較多,所以 B 端在設計風格上盡量做到簡潔,B 端產品實用性大于美觀性,在每一個功能的設計都需要你去思考很多方面:用戶易用、信息層級、未來擴展,你都要做出取舍,而對于每個模塊都需要你思考、結合用戶場景。所以想要做好 B 端設計,一定要去了解業務,了解用戶需求。

          文章來源:優設    作者:小六可視化設計

          愛奇藝 VR 設計實戰案例:界面文字篇

          濤濤

          本系列文章旨在由淺入深、由理論到實踐地介紹 VR 設計。無論你在做哪個領域的設計,都能通過這個系列了解 VR 設計的特點。本文是第一集,深入分析 VR 界面的文字設計。


          文章來源:優設    作者:愛奇藝XRD

          日歷

          鏈接

          個人資料

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

          存檔

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