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

          首頁

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

          ui設計分享達人

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

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


          稀缺性的正反價值


          讀者提問:

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


          當然有,比如稀缺性。


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


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


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


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


          以上。


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


          稀缺的分類


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


          時間的緊迫感。


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

          產品的缺失。


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


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


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


          信息的限制。


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


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


          稀缺作用的原理


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


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

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

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


          稀缺作用的條件


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

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


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


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

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

          資深UI設計者

          微信是一種生活方式。作為月活超 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端系統設計全方位指南

          資深UI設計者

          什么是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 端產品那種那么明確)
          • 設計的產品主要解決用戶或者業務上的哪些具體痛點,復現分析下使用場景,在需求分析階段,要對產品本身和行業本身有一些基本的認知。

          使用場景、硬件情況

          • 了解用戶的使用場景,可以有助于我們復現分析用戶是如何使用我們設計的界面的。
          • 用戶的硬件情況,了解主流用戶的屏幕分辨率是多少,根據主流分辨率做設計稿?,F在 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. 設計后:

          設計走查

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

          高質量設計交付

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

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

          設計追蹤、校驗

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

          總結

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

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

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

          資深UI設計者

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


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

          愛奇藝 VR 設計實戰案例:空間布局篇

          資深UI設計者

          本系列文章旨在由淺入深、由理論到實踐系統地介紹了本團隊在近幾年的設計工作中的一些經驗總結和重點思考。本系列面向廣大設計師,不論你目前在做什么領域/哪個端的設計,都可以了解到 VR 端和其他端的異同。希望給正在看文章的你帶來收獲。

          團隊介紹:愛奇藝 XRD——愛奇藝 VR/AR/XR 設計團隊,目前主要負責愛奇藝 VR app 的設計工作(包括各個 VR 設備端和手機端)。

          初步認識:空間里的界面

          1. VR與其他端的區別

          傳統的數字終端(手機、電腦、pad 等),用戶界面存在于二維的物理屏幕里,也就是在一個平面里。而屏幕和界面通常都是長方形的。

          在 VR 中,有空間感的不僅僅是虛擬場景,用戶界面也是布局在三維空間里的?!钙聊贿吔纭沟母拍畋淮蚱屏?,設計師的畫板不再是各類手機不同尺寸的屏幕,而是一個「無限的」空間。界面本身也可以是三維的、打破傳統的,不再必須是一個個的長方形。

          真正的 z 軸

          這不同于在 2D 屏幕終端上,元素只擁有(x、y)坐標點的屬性,而并沒有一個 z 軸的概念。Z 軸,也就是深度概念,是通過設計師利用陰影、動效等視覺效果,「模擬」出來的前后關系。

          在 VR 中看到的內容物(包括 UI 界面、場景、模型、視頻資源等)有真實概念的前后關系,每個物件擺在一個具體的(x、y、z)坐標點上。物件擁有絕對位置,物件和物件之間有相對位置,物件和 camera(指用戶觀測點)之間有一個具體的距離。

          角度和曲面

          除了 z 軸坐標,因為 VR 界面存在在空間里,所以還擁有一個屬性就是角度,這包含了在(x、y、z)三個軸上旋轉的角度。每一個物件也可以不再是一個平面,而是曲面的、三維的。

          角度和位置共同決定了,當用戶看向某個物件時,這個物件的樣子。

          「有多大?」

          一個物件在 VR 中「有多大」很難簡單描述清楚。在傳統端只需標注某個 UI 元素的「大小」「間距」,描述單位是像素。而在設計 VR 時。需要從多個維度定義一個元素:「大小」「(x、y、z)位置」「(x、y、z)角度」。同時,「有多大」還跟用戶觀測點的位置息息相關。

          2. VR基本術語認知

          在介紹下文理論之前,讓我們先認識兩個常見的 VR 術語:

          FOV:Field of View,視場角

          視場角的大小決定了光學儀器的視野范圍。在 VR 中,視場角是 VR 硬件設備的一個屬性,設備 FOV 是一個固定值。

          在我們團隊日常工作用語中,通常也用來指代用戶的視角范圍、界面元素的角度范圍(如,「某面板水平 FOV 是 60°」)

          DOF:Degree of Freedom,自由度

          物體在空間內具有 6 個自由度,即沿 x、y、z 三個直角坐標軸方向的移動自由度和繞這三個坐標軸的轉動自由度 。

          • 3DOF 的手柄/頭顯:只有繞 x、y、z 軸的 3 個轉動自由度,沒有移動自由度,共 3 個自由度。通俗地說,3DOF 手柄可以檢測到手柄在手中轉動,但檢測不到手柄拿在右手還是左手。
          • 6DOF 的手柄/頭顯:同時有繞 x、y、z 軸的 3 個轉動自由度,和三個軸方向的 3 個移動自由度,共 6 個自由度。通俗的說,是完全模擬真實物理世界的,可以看的手柄的實際位置和轉動方向。

          理論:人眼的視野與視角

          雖然說 VR 是一個 360° 全景三維空間,但對于目前大多數 VR 的使用場景來說,可供設計師創作的區域其實已被大大縮小了。

          目前國內市面常見的可移動的 VR 設備(非主機類),如小米 VR 一體機、Pico 小怪獸系列、奇遇 VR、新上市的華為 VR Glass,標配均為 VR 頭顯配合3DOF手柄的硬件模式。對應此類 VR 硬件模式,常見的用戶使用場景為:「坐在椅子上+偶爾頭轉+身體不動」,好比「坐在沙發上看電視」。即使用戶使用一個 6DOF 的 VR 硬件,支持空間定位可以在房間里走動,但對于愛奇藝 VR 這類觀影類 app 來說,「坐在沙發上看電視」仍是主要的使用場景。

          因此, 主要的操作界面還是需要放在「頭部固定情況下的可見范圍內 」。這樣用戶無需費勁轉頭,就可以看到主要內容、操作主要界面。

          那么,什么是「頭部固定情況下的可見范圍 」呢?我們需要先學習一些人機工程學,來了解一些人眼 在不同情況下的可視范圍。

          1. 水平視野(x軸)

          (此圖的中心點 為用戶觀測點。)可以看出,

          頭部固定的情況下,雙眼能看到的最大范圍約為 124°。但還要考慮到一個限制,目前 VR 硬件設備的 FOV 并未達到這個值,通常在 90°~100°。而其中,能看清晰的范圍只有眼前中心處的 60°。這相差的范圍可以理解為「余光」,在人眼中成像是不清晰的,但仍在視野范圍里?!@個范圍極大程度上決定了每一個 UI 面板(包括其中的圖片、文字等)適合占據的空間,也決定了 VR 中視頻播放窗的最小和最大值。

          頭部轉動但身體不動的情況下,脖子舒適轉動能看到的范圍約有 154°,脖子轉動到能看到的范圍約有 204°。一些次要內容可以放在這個區域,用戶需要轉動頭部才能看到,但也不用太費力。

          偏后方的區域范圍,必須移動身體才能看到,因此只能放一些「沒看見也沒關系」的內容。比如環境、彩蛋等。

          2. 垂直視野(y軸)

          在放松狀態下,頭部與眼睛的夾角約為 105°。也就是說,當頭部豎直向前時,眼睛會自然看向水平線下 15° 的位置。頭部固定僅眼球轉動時的最佳視野是(上)25° 和(下)30°。應將操作界面和主要觀看內容放在此范圍內。

          垂直方向最大視野范圍是(上)50° 和(下)70°。這個范圍也是超過了 VR 硬件設備的 FOV。

          另外,點頭比抬頭舒適?,F實世界中,我們通常都是低頭狀態比抬頭多,比如玩手機、看書或看筆記本電腦時。所以在 VR 中,比起偏上方區域,應考慮更多利用起偏下方的區域。

          3. 深度感知(z軸)

          (見本章圖1)

          0.5m 之內的物件,雙眼很難對焦,因此不要出現任何物體。(這個值對于全景 3D 視頻的拍攝 意義較大,應該盡量規避離鏡頭過近的物體出現)

          有立體感的范圍在 0.5m~10m,這里應該放置主要內容,尤其是可操作的內容。

          10m~20m 之間,人眼仍能感覺出立體感,但有限。此范圍仍適合放置可以體現沉浸感的 3D 場景/模型。

          超過 20m 的距離,人眼很難看出立體感了,物體和物體的前后關系不再明顯。因此適合放置「僅僅作為背景」存在的內容,也就是環境。(值得注意的是,因為反正也感知不出立體感,所以此范圍的環境可以處理為全景球(即一個球面),來代替 3D 模型,這大大降低了功效。)

          4. 視角和視距

          在現實世界中,每個信息媒介都有一個預設好的觀測距離。例如,握在手中的手機,距人眼大約 20cm。放在桌面上的電腦主機顯示屏,距人眼大約60cm??蛷d墻上的電視,距人眼大約 5m。在馬路另一頭的廣告牌,距人眼可達幾十米。

          內容在預設好的觀測距離上,對應預設好的大小。例如,手機上的正文文字只有幾毫米大,而廣告牌上的文字需要好幾米大。

          而在我們(觀測者)看來,這些文字都閱讀舒適。甚至其實看起來是「一樣大」的。

          這是因為它們擁有同樣的視角——被視對象兩端點到眼球中心的兩條視線間的夾角。具體舉例來說,在 1m 處看一個 10cm 的物體,和 在 2m 處看一個20cm 的物體,在 3m 處看一個 30cm 的物體,這 3 個物體「看起來是一樣大的」,他們具有相同的視角。但我們仍然清楚地知曉誰近誰遠,是因為眼睛對焦在不同的距離上,也就是視距不一樣。

          在 VR 中,不能再像移動端那樣用「像素」來度量一個物件的大小,而是通過「視角」。而視角是由物件的「大小」、「位置」、「旋轉角度」共同決定的。在「用戶觀測點不動」的使用場景下,「位置」實際上就是與觀測點的「視距」。

          界面的「旋轉角度」應遵守一個原則——一個便于觀看和操作的界面,應該盡量垂直于視線、面向用戶觀測點。也就是說,當你確定好一個界面的「位置」后,就自然會有一個對其來說的「最佳旋轉角度」。

          在 VR 中,一個物件的視角由其「大小」和「視距」兩個變量影響。當確定了「最佳視角」、「最小可閱讀視角」時,這就決定了「需要在不同距離上放置的信息內容,各自應該放多大」。

          實踐:愛奇藝VR app 的假面布局

          有了理論基礎后,接下來就是不斷實踐。

          首先需要讀者了解的是,我們團隊設計的對象是愛奇藝 VR app——是在 VR 設備上的愛奇藝,是愛奇藝的第四個端。不僅包含愛奇藝全網 2D 內容,還擁有海量 VR 全景視頻、3D 大片。選片和觀影相關功能齊全。在體驗上主要打造有沉浸感的 VR 影院觀影,并突出 VR 特色內容。

          本文章針對于 VR 一體機內的愛奇藝 VR app 設計展開討論,但我們同時也支持手機端 app,若感興趣可以在各大應用商店搜索下載。

          我們學習的大量二手資料,給開展實際工作創造了基礎。然而最終設計效果其實是在反復驗證、試錯后決定的。

          當根據理論資料開始做實踐,卻發現實際效果差強人意時,我們的建議是——注重實踐。原因之一是,目前 VR 界從技術到產品設計仍舊處在實驗性階段,遠未達到移動端設計規范的成熟性,國內外的相關理論經驗總結,都還沒有絕對定論的程度。Oculus 的設計指南中,都是建議「實驗,實驗,再實驗」。之二是,能搜集到的二手資料,不完全是建立在「人帶著 VR 設備手握手柄」這種使用場景上,所以導致實際結果「不是那么回事」。

          1. 模塊化界面布局

          基于「坐著不動+頭部轉動」的使用場景,和「自然視角偏下」、「低頭比抬頭舒適」的理論。

          我們采取「從正視角出發,向左、右、下延伸」的布局思路。正視角放置當前界面的核心內容,左右兩側放置輔助信息內容;在必要時,可加入下部模塊。此類模塊化布局適用于所有界面,只是具體的面板尺寸、旋轉角度可以有所不同。根據每個界面需要承載的內容,因地制宜地合理規劃。

          圖為我們使用的幾種常見 UI 布局。

          2. 界面的FOV

          基于人眼水平和垂直方向的視野范圍的理論,同時參考主要適配的硬件設備屬性(目前 VR 設備的 FOV 都小于人眼的視野范圍),即:

          • 小米 VR 一體機:FOV≈90°(實際)
          • Pico 小怪獸 2:FOV=101°(官方數據)
          • 華為 VR Glass:FOV=90°(官方數據)

          ——我們決定了愛奇藝 VR 中主要界面的 FOV。

          選片主界面 FOV (左-中-右 布局)

          △ 「實際截圖」愛奇藝 VR 選片主界面

          水平方向上:

          • 中部面板:兩邊邊界在「頭部固定時清晰 FOV」內。
          • 兩側面板:近中心的邊界均出現在「頭部固定時可見 FOV」內,即在默認可見的視角范圍內。兩邊邊界在「頭部輕微轉動時清晰 FOV」內,即用戶只需輕微左右轉動頭部便可查看全部內容。

          垂直方向上:

          • 面板在「頭部固定時清晰 FOV」內。用戶無需上下轉頭。
          • 該頁面可左右滑動,用戶可以只關注中部的面板。

          影廳播控頁面 FOV(左-下-右布局)

          在愛奇藝 VR 中,觀看非全景的 2D/3D 視頻,用戶會置身于一個電影院影廳場景中。視頻畫面會出現在影廳屏幕上。

          影廳播控頁面(操控臺頁) 指播放視頻時(包括影廳場景影片和全景影片)的操作界面。

          △ 「實際截圖」愛奇藝 VR 影廳播控頁面

          影廳播控頁面采用「左-下-右」布局。包括 3 個功能區塊:相關推薦(左)、操控臺播控(下)、詳情 & 選集(右)。該頁面在視頻屏幕(或全景視頻)的前方,靠單擊觸摸板來呼出和關閉。

          這 3 個面板的邊界均在正視角「頭部固定時可見 FOV」之內,也就是保證了,當用戶注視影片本身并呼出該面板時,能看到所有面板。而用戶僅需輕微轉動頭部,就可看到完整的面板。

          視頻播放窗的最大/最小值

          視頻播放窗 即「影廳屏幕」,被我們設定了屏幕大小可調的功能,以此來適應不同用戶的觀影習慣。屏幕大小可在指定范圍內平滑調整。

          屏幕最小值(50°):完整的屏幕范圍都在「頭部固定情況下清晰 FOV」。

          屏幕最大值(76°):屏幕范圍在「頭部固定情況下可見 FOV」,即「充滿視野」。此狀態的觀感類似 IMAX 影廳。

          垂直方向上:距水平線偏上而不是偏下。這里其實和理論值發生了沖突。理論資料中,人眼最舒適的對焦點在「水平線向下 15°」。在老版本中,我們曾經將主 UI 和視頻屏幕都按理論值擺在了偏下方,但實際效果并未令人感到舒適,反倒明顯感知到「內容都偏下了」。這就是上文所說,「當理論導致實踐差強人意」時,我們選擇了不斷實驗,以實際效果為準。另外,本場景下方有影廳座椅等實際模型,并且還有操控臺播控的 UI。綜上,影廳屏幕被放在了水平偏上的位置。

          3. 深度距離與層級(z軸)

          根據前文理論提到的,z 軸距離的合適范圍(0.5m~20m)比起水平和垂直 FOV 來說,數值范圍要大得多,也就是說可試驗的范圍很大。因此在界面距離這一點上,我們進行了大量反復的實踐——最終決定了當前版本中各級頁面的深度層級和具體數值,如下圖:

          跟隨式提示:

          • 適合于臨時性的提示內容,幾秒后自動消失。如 toast。
          • 與 camera(用戶觀測點)鎖定,跟隨 camera 移動。不可交互。
          • 保證讓用戶注意到,又不至于遮擋視線。

          阻斷式提示:

          • 適用于必須讓用戶看到且用戶必須對其處理的提示。如彈窗。
          • 正視角區域固定顯示,不跟隨 camera 移動。有按鈕可以交互。
          • 需要在其它操作界面之前。

          輔助操作界面:

          • 適用于重操作的界面,而非重展示的界面。如播控按鈕組、鍵盤,而非視頻列表。
          • 通常在平視視線偏下的位置。(模擬「在手邊」的位置)

          減少眼球調焦,縮小距離差

          值得注意的是,在我們的老版本中,不同層級的界面曾經被擺放的距離差距很大。如,toast 在 1.75m,主 UI 在 3m,而視頻屏幕在 12m。之所以改動至上圖數值,主要是為了達到「在看向不同層級界面時,盡量減少眼球調焦的程度」的目的。

          眼球在看向不同距離上的內容時,需要對焦到不同的平面,距離差距越大,眼球需要調整得越大。如果頻率高的話,容易導致(一部分)人的眼球疲勞。

          Z軸上的獲焦效果

          VR 獨有的「z 軸」,不僅允許了界面可以被放在不同距離上,還支持了利用 z 軸上的位移和旋轉 來表達獲焦效果??丶猾@焦時,只需要在 z 軸上輕微的位移或輕微的角度旋轉,便可體現出與眾不同的有趣效果。

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

          日歷

          鏈接

          個人資料

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

          存檔

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