整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          如何實現一個超絲滑的勾選框組件?

          Zag 和 PandaCSS 都是出自 chakra 團隊之手,Zag 聚焦于處理組件的邏輯,而 PandaCSS 聚焦于通過 ts 來維護樣式,將兩者進行搭配會有怎么樣的使用體驗呢?這篇文章將繼續以 vuesax 中 checkbox 組件的樣式作為參考,結合 Zag 和 PandaCSS 進行 vue3 版本的重構,實現一個超絲滑的勾選框組件。


          使用 Zag 實現核心邏輯

          Zag 中將 Checkbox 分為三個組成部分:

          • root:根元素,用于包裹內部元素
          • control: 控制器
          • label: 標簽內容

          我們首先在 Zag Checkbox 文檔中復制 JSX 的實例代碼:

          import * as checkbox from "@zag-js/checkbox"
          import { normalizeProps, useMachine } from "@zag-js/vue"
          import { defineComponent, h, Fragment, computed } from "vue"
          
          export default defineComponent({
            name: "Checkbox",
            setup() {
              const [state, send] = useMachine(checkbox.machine({ id: "checkbox" }))
          
              const apiRef = computed(() =>
                checkbox.connect(state.value, send, normalizeProps),
              )
          
              return () => {
                const api = apiRef.value
                return (
                  <label {...api.rootProps}>
                    <span {...api.labelProps}>
                      Input is {api.isChecked ? "checked" : "unchecked"}
                    </span>
                    <div {...api.controlProps} />
                    <input {...api.hiddenInputProps} />
                  </label>
                )
              }
            },
          })

          這段代碼使用了 useMachine 函數創建了一個狀態機,并且寫了一個無樣式的基礎 checkbox 結構:

          接下來我們為 checkbox 組件補充樣式.

          實現打勾動畫圖標

          想要實現絲滑的勾選框效果,最直觀的是打勾的動畫。這個效果可以通過 SVG 或者純 css 實現,這里我使用的是 css 來實現的。:

          首先我們要想想如何實現一個勾勾的效果,??由一長一短兩個斜邊組成,那么我們只需要放置一個矩形,設置一定的旋轉角度,并設置其中的兩個邊框,就能實現一個??的形狀:

          代碼實現如下:


          import { defineComponent } from "vue";
          
          import { css, cx } from "@/styled-system/css";
          
          const IconCheck = defineComponent({
            props: {
              color: {
                type: String,
                default: css({ colorPalette: "gray" }),
              },
              size: {
                type: String,
                default: css({ colorPalette: "gray" }),
              },
              customCSS: {
                type: String,
              },
            },
            setup(props) {
              return () => (
                <i
                  class={cx(
                    css({
                      display: "flex",
                      alignItems: "center",
                      justifyContent: "center",
                    }),
                    props.customCSS,
                  )}
                >
                  <div
                    class={css({
                      position: "relative",
                      width: "80%",
                      height: "40%",
                      transform: "rotate(-45deg)",
                    })}
                  >
                    <div
                      class={css({
                        position: "absolute",
                        left: "0",
                        width: "full",
                        height: "full",
                        borderLeft: "2px solid white",
                        animation: "checkShort 0.15s",
                      })}
                    />
                    <div
                      class={css({
                        position: "absolute",
                        left: "0",
                        width: "full",
                        height: "full",
                        borderBottom: "2px solid white",
                        animation: "checkLong 0.5s",
                      })}
                    />
                  </div>
                </i>
              );
            },
          });
          
          export default IconCheck;

          上面這段代碼中,定義了一個矩形,寬高分別為最外層容器的 80% 和 40%,transform: "rotate(-45deg)", 則設置了矩形的旋轉角度,內部放置兩個與矩形寬高一致的容器,分別設置 borderLeft 和 borderBottom ,這樣就組成了一長一短兩條線。

          這里之所以需要在內部放兩個容器單獨設置邊框,而不是直接在矩形設置邊框,是為了更好的實現動畫效果,長短邊分別設置了兩個持續時間不同的動畫 checkShort 0.15s 和 checkLong 0.5s:

          checkShort: {
            "0%": {
              height:0,
            },
            "100%":{
              height: "full",
            }
          },
          checkLong: {
            "0%": {
              width: 0,
            },
            "30%":{
              width: 0,
            },
            "100%": {
              width: "full",
            }
          }

          短邊從最開始就執行動畫,持續時間為長邊動畫的 30%,長邊則在 0-30% 時不執行,30% 之后開始執行,這樣就能實現短邊動畫執行完成后,長邊動畫再執行的效果。

          之所以不使用 animation-delay 去延遲執行長邊動畫,是因為這種方式會導致動畫延遲執行前,長邊會先展示出來,效果就不對了。如果要使用這種方式還得單獨做一些動畫延遲前的隱藏處理,會比較麻煩:

          實現 Hover 效果

          為了讓用戶更容易感知勾選框是可以交互的,我們為勾選框增加未勾選和關狀態的 hover 效果。

          未勾選狀態

          未勾選狀態的 hover 效果,默認只有灰色邊框,鼠標懸浮后變為灰色背景:

          這里有個注意點,我們鼠標懸浮在勾選框的最外層,也可以觸發內層的 hover 樣式,如果直接使用 hover 效果是沒法做到的,這樣只能鼠標懸浮在邊框內才能觸發。

          如果我們沒有使用任何樣式庫,實現這個效果可以通過維護一個 鼠標是否 hover 的狀態,并通過 onMouseEnter 和 onMouseLeave 來更新這個狀態,再在內層根據這個狀態動態渲染樣式。

          但這里我們可以使用 pandaCSS 的 group 選擇器來實現。

          首先在勾選框最外層元素增加 group 類名:

          <label
            {...api.rootProps}
            class={[
              css({
                display: "flex",
                alignItems: "center",
                cursor: "pointer",
              }),
          +    "group",
            ]}
          >

          然后在內層的 control 元素增加基礎樣式:

          <div
              {...api.controlProps}
              class={css({
                width: "24px",
                height: "24px",
                borderRadius: "8px",
                border: api.isChecked
                  ? "none"
                  : "token(colors.gray.200) solid 2px",
                transition: "all 0.3s",
                marginRight: "4px",
                flexShrink: "0",
                _groupHover: {
                  background: "gray.200",
                },
              })}
            >
            // ...
            </div>

          這里的 _groupHover 即為 group 選擇器,當帶有 group 類名的元素觸發 hover 時,內部的元素都可以使用 _groupHover 設置特定樣式。這樣我們就實現了前文圖中的效果。

          勾選狀態

          在勾選時,會有一個藍色色塊放大漸出的效果,我們先來實現這個樣式。

          <Transition
            enterFromClass={css({
              transition: "all 0.2s",
              transform: "scale(0.5)",
              opacity: "0",
            })}
            enterToClass={css({
              transition: "all 0.2s",
              transform: "scale(1)",
              opacity: "1",
            })}
            leaveToClass={css({
              transition: "all 0.2s",
              transform: "scale(0.5)",
              opacity: "0",
            })}
          >
            {api.isChecked && (
              <div
                class={cx(
                  props.color,
                  css({
                    width: "full",
                    height: "full",
                    background: "colorPalette.600",
                    borderRadius: "inherit",
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "center",
                    transition: "all 0.3s",
                  }),
                )}
              >
                <IconCheck
                  customCSS={css({
                    width: "18px",
                    height: "18px",
                  })}
                />
              </div>
            )}
          </Transition>

          這里我們使用 vue 中的 Transition 組件來實現動畫效果,通過改變scale 和 opacity 實現元素大小和透明度的過渡動畫,內部包裹著勾選的圖標。

          實現了勾選的效果,繼續實現勾選后的 hover 樣式。勾選后在 hover 時,勾選框的外層有一個與主題色相同的外層陰影效果:

          這里我們依然使用 group 選擇器來設置 hover 樣式:

          <div
            class={cx(
              props.color,
              css({
                width: "full",
                height: "full",
                background: "colorPalette.600",
                borderRadius: "inherit",
                display: "flex",
                alignItems: "center",
                justifyContent: "center",
                transition: "all 0.3s",
          +      _groupHover: {
          +        boxShadow:
          +          "0px 3px 15px 0px color-mix(in srgb, token(colors.colorPalette.600) 40%, transparent)",
          +      },
              }),
            )}
          >
            <IconCheck
              customCSS={css({
                width: "18px",
                height: "18px",
              })}
            ></IconCheck>
          </div>

          在陰影效果的代碼中 0px 3px 15px 0px color-mix(in srgb, token(colors.colorPalette.600) 40%, transparent) ,前面幾個設置陰影大小的參數很容易理解,但是后面陰影顏色的實現大家可能比較陌生,單獨解釋一下:

          • token(colors.colorPalette.600):token 是 pandaCSS 中提供的一種 token 使用方法,用于在 border,boxSahdow 這種組合多個參數的樣式中引用 token 值。相關文檔:panda-css.com/docs/themin…
          • color-mix() : color-mix 則是原生 css 的函數,用于接收兩個顏色值,并返回在指定色彩模式、以指定比例混合后的顏色。相關文檔:developer.mozilla.org/zh-CN/docs/…

          我這里用法的含義是在 srgb 的色彩模式下,將主題色(token(colors.colorPalette.600)) 與透明色(transparent),以 40% 的比例進行混合,最終合成的顏色就是 40% 透明度的主題色。 color-mix() 函數是 pandaCSS 中推薦用戶用于為內置顏色設置透明度的方法,除此以外并沒有發現其他更簡便的方式。

          完成雙向綁定

          最后我們完善一下勾選框的雙向綁定邏輯邏輯,

          • 通過 Zag 中的 onCheckedChange 配合 emit 可以實現 Zag 內部狀態向外傳遞
          • 通過監聽 propmodelValue 的改變,執行 apiRef.value.setChecked 可以實現外部狀態向 Zag 內傳遞

          實現的代碼如下:

          const [state, send] = useMachine(
            checkbox.machine({
              id: useId("checkbox"),
              onCheckedChange(detail) {
                emit("update:modelValue", detail.checked);
              },
            }),
          );
          
          const apiRef = computed(() =>
            checkbox.connect(state.value, send, normalizeProps),
          );
          
          watch(
            () => props.modelValue,
            () => {
              apiRef.value.setChecked(props.modelValue);
            },
          );


          ? 使用 Vue+Zag+PandaCSS 實現一個超絲滑的勾選框組件
          原文鏈接:https://juejin.cn/post/7295954109404463155

          輯導語:如何才能解決原型設計中輸入框校驗的問題?本篇文章里,作者就對如何繪制可以校驗的輸入框的相應流程進行了梳理,一起來看一下吧,也許會對你有所幫助。

          在原型設計中,輸入框校驗效果設計是一件令人頭疼的事情,但是可以通過使用bootstrap元件庫中的輸入框設置,可以輕松解決輸入框校驗的問題。

          一、效果預覽

          預覽地址:http://atomstudio.cn/demos/bootstrap_input

          二、準備工作

          需要安裝XSTAR2022.1.22版(或更高版本)

          三、操作步驟

          1)打開軟件,選擇bootstrap元件庫,在元件列表中將輸入框拖拽到編輯區。

          2)選中編輯區的輸入框組件,右側顯示出輸入框設置面板。

          3)在輸入框設置面板中勾選驗證成功提示和驗證失敗提示。

          4)編輯提示文本內容

          5)設置前綴、后綴

          6)設置提示樣式

          7)設置驗證規則

          可選規則包括:

          • 任意字符
          • 英文字母
          • 大寫英文字母
          • 小寫英文字母
          • 數字、英文字母或者下劃線
          • 漢字
          • 任意數字
          • 英文和數字
          • 中文、英文、數字包括下劃線
          • 域名
          • 網址
          • 郵箱地址
          • http網址
          • https網址
          • 手機號碼
          • 電話號碼
          • 國內電話號碼
          • 身份證號
          • 短身份證號碼
          • 賬號是否合法
          • 密碼
          • 強密碼
          • 日期格式(1900-10-10)
          • 一年的12個月
          • 1個月的31天
          • xml文件
          • 空白行
          • HTML標記
          • 中國郵政編碼
          • IP地址

          8)根據需要設置完成后,進行預覽、導出或者分享。

          本文由 @balabala 原創發布于人人都是產品經理,未經許可,禁止轉載。

          題圖來自Unsplash,基于 CC0 協議。

          心看完你一定有所收獲

          在前兩篇文章中,我們主要講到 B 端產品最為重要的信息展示組件 表格 的設計思路,根據不同的場景對表格進行了答疑,同時部分讀者與我反饋,想讓我聊聊選擇組件的一些內容,今天就來簡單聊聊在「數據錄入場景」中的一個小點:選擇錄入。

          提前說一句:其實這篇文章快寫完時發現已經有類似的文章,由于自己寫文章并不會在乎市面上是否有同類型的文章,文章的靈感也多來源于自己的工作中遇到的實際問題。自己也并不是想重復造輪子,有“內卷”的那味兒,最后發出來的原因主要有兩點:


          1.為了能給大家把 日期選擇、樹形選擇、穿梭框、成員選擇 等業務復雜的控件講懂,沒有基礎的認知進行“憑空建樓”實屬困難。

          2.發現雖然有類似的文章,但大家所講的方向并不相同,對于選擇錄入場景的理解也不太一樣。


          選擇錄入的痛點

          • 選擇類型多:在我們常見的選擇類型中,常使用的有四種:“單選框、多選框、開關、下拉選擇。”這四類便是選擇組件當中的基礎組件。在實際業務的使用中,還會涉及到:“日期選擇、樹形選擇、人員選擇、穿梭框、級聯選擇、評分” 等一些業務層面的組件,類型之多再加上每種組件用法也不盡相同,因此需要在每種組件的區分上多加思考。


          其實我在評審許多設計師的稿件中,經常發現大家對它使用的場景并不了解。比如在一個表單中,讓用戶選擇性別時,是采取下拉選擇、單選框、多選框甚至是開關呢?那如果我們選擇家庭住址又應該如何設計呢?這一系列問題都需要去解決。



          • 細節多:選擇錄入看起來一個小小的按鈕,好像當中的細節不會特別復雜,但當你實踐過后就知道,其背后有著許許多多的潛臺詞以及默認規則。比如在單選框是沒有讓用戶進行取消的操作;開關是不會讓用戶進行提交保存的,默認規則往往是這類交互本身所包含的。因此讀懂組件中的潛臺詞,也就是我們要做的事。


          由于知識點很多,想要把它們完整講清楚需要花大量時間,因此我會在后續的文章中與大家逐一拆解,掰開揉碎慢慢消化,篇幅有限,今天我們先來聊聊前面幾個稍微容易理解的:「單選框、多選框、開關」,究竟應該如何設計~


          零、老規矩


          先科普一個知識點,Tooltip / Popover的區別

          這是來自我 B端交流群的一個討論,起因是有一位同學展示了自己產品的一個截圖



          圖上可以看到,他的 tooltips 巨長無比,并引發了一系列的討論:



          首先再討論過后,有朋友私聊我,咨詢我“這兩個控件誰更加好”,但組件本身就不存在孰優孰劣,更多則是場景不同,使用的控件也會不盡相同。為了更好讓大家的理解兩個控件的區別,這里將它們進行簡單的對比,通過相同點與不同點去分別講解,讓大家有更全面的了解。


          首先,對于 Tooltip 來說,它其實就是一個信息提示的小玩意兒,當用戶對某一未進行文字解釋的圖標進行 :hover 時,便可采用 Tooltip 對該圖標的含義進行解釋,這也是我們日常工作中用到最多的情況。

          而對 Popover 則感覺大家會有些陌生,其實在我們常見的新手引導、確認提示中都會使用這個控件,并且在很多 B端設計場景中,往往都可以通過這個控件進行相應的簡化。



          二者相同點

          相同點我們主要會從 形式、功能、方向 三個方面去思考


          • 形式

          它們兩者在設計的形式上都是非常相似的點,都是采取浮層進行信息的展示,并且通常都會跟著一個小“尾巴”來代表它所來源的方向,此外在窗口大小上也基本相同,因為小窗口也意味著它所承載信息會相對較少,后面會細講內容


          • 方向

          在對其的實際運用中,都會涉及到彈出方向的不同。在實際項目中,彈窗方向一般是以上下左右四個方向進行彈出,而從上方彈窗是一般的默認方向,智慧在外部容器限制的前提下,會對彈出方向進行改變,同時在容器角落時,會延容器反方向的角落進行彈窗即可


          • 功能

          對于使用兩者的功能而言,只能說大致相同,細枝末節上還是會有不小的區別。在功能上,兩者幾乎都是想要提示用戶某些隱藏信息,并且信息的重要程度都不會太高,因此足夠輕量就成為它的關鍵屬性


          二者不同點

          其實兩個除了在外觀上較為接近,其實在很多地方都是不同的地方

          承載內容

          一般 B端的內容共有:圖標、文字、鏈接、按鈕、圖片等,我們首先說說 Tootip ,Tooltip 因其容器的特殊性,只能承載簡單的文本,并且 Tooltip 的提示一般不會多于50個字,只能對當前的內容進行簡單解釋


          比如在常見的輸入框標題提示中,經常會有「問號、嘆號」 圖標的出現,用戶就是通過 :hover 展示 Tooltip 對標題進行解釋



          而在 Popover 中,他所承載的內容要比 Tooltip 更加的多,小到按鈕、鏈接,大到圖片、視頻,都在它的彈窗范圍內

          觸發方式

          我們常見的觸發方式一共有:Hover、Focus、Click 三種方式

          由于承載內容的不同,進而影響觸發方式的不同

          因為 Tooltip 在內容上以純文字為主,并且多是50字以內的輔助信息,所以在觸發方式上,要就 Tooltip 能夠及時觸發,因此當你鼠標 :hover 后,就應該將該內容的解釋信息告知給用戶,方便用戶使用


          而在 Popover 則恰恰相反,因為其內容承載較多(有圖片、按鈕等等…),如果通過 :hover 進行內容的呈現顯然是不太合理,并且通常使用會有確定、是否的對話,讓用戶進行操作,所以使用 :focus、:click 更友好

          閱讀性不同

          由于觸發方式的不同,進而在閱讀性上會有所干擾

          因為 Tooltip 本事是通過 :hover 進行觸發,也就直接造成在設計上,對于Tooptip 會采取對比度更強的黑色底,這樣用戶對于信息提示能吸引更多注意力,而黑色的背景,對于用戶閱讀來說會更加困難,也因此側面反應這里的文字不宜過多

          Popover 則不會有上面的煩惱,因為是通過用戶的明確點擊而來,用戶對彈出內容已經有所預期,因此可使用白色底,閱讀性會稍好于前者

          用法不同

          如果說了那么多,不講怎么用便是在真正的耍流氓,因此最后我們來看看他的實際用法有哪些


          • Tooltip

          其一就是用來幫助用戶了解到某些圖標的含義目的,這已經是桌面端必備的邏輯,比如微信中


          其二為了展示截斷的文本,因為 B端很多長文本的場景,用戶想要提前知道,幫助用戶進行判斷


          • Popover

          其一可以作為警告用戶的一種提示信息,需要用戶再次確認,同時它相比 Dialog 更為輕量



          其二作為新手引導,可以讓用戶進行一步步的確認,它的輕量剛好能夠適合進行新手引導


          OK,了解完兩者的區別后,我們繼續選擇錄入,小本本準備好~


          一、單選框 Radio


          1.1單選框的歷史

          單選框,也常叫做 單選按鈕、單選,它最早來源于收音機上的物理按鈕,當時用于收音調頻之間的相互切換。當一個按鈕被按下時,另一個按鈕將會被彈起,使收音機只能擁有一個“按下狀態的”按鈕。

          而早在計算機用戶界面誕生之初(The Xerox Alto)就已經有了單選框的出現。同時在HTML的底層中,Radio 就作為一個最基礎的標簽,擁有「無法撼動的地位」所以在各大設計系統中一直作為基礎組件被沿用至今。


          但隨著移動互聯網的普及,單選框這一形式在用戶心中被逐漸的弱化,取而代之的是各類功能相同但形式繁多的按鈕,這也是目前很多B端設計師存在的認知誤區之一。


          • 單選按鈕:根據移動移動端的交互形式與「菲茲定律」,單選按鈕主要將自己的熱區擴大,能夠更方便使用鼠標進行點擊操作,可針對特定的B端產品進行優化。但面積增大的同時帶來的是屏效降低,作為B端產品,屏效比也是一個非常重要的因素之一,因此需要權衡兩者的利弊。


          • 單選組:通過上面的單選按鈕,將兩個以上的按鈕進行排布,而形成的單選組,能夠盡可能增加展示效率。單選組的功能與 Tab 非常類似,也因此單選按鈕與單選組是一個相輔相成的過程。



          1.2單選框的定義

          單選框:允許用戶從多個選項中,選擇一個選項,且選項之間存在互斥關系,這也是「單選」名稱的由來。

          單選框的外觀一般是一個空白的圓洞,旁邊則通常有文字標簽;標簽的用途除了描述之外,還可以作為操作熱區,當用戶點擊標簽,所應的單選框就會被選中;已選上的單選按鈕一般會在圓洞內加上一小圓點。


          1.3單選框的交互邏輯


          • 選項數量:使用單選框的選項數量一般為 2-5 個之間,因為在一個正常的表單中,是不允許寬度過寬導致頁面排布困難,同時使用多于5個的單選框,會十分影響閱讀效率,因此超出5個便可采取「下拉菜單」的方式進行展示。在工作中常見的的單選框為性別、是否選擇等…


          • 默認選項:默認值在我們B端的設計中,往往是一把雙刃劍,你運用得好可以為自己的設計增加易用性,因為默認值本身在表單中并不常見(不可能給每一個表單都給上默認值),而在特定的場景中使用默認值會有意想不到的效果。


          說一個我實際工作中遇到的內容,在我之前負責的一個關于醫美客戶系統的的SCRM中,當客戶到店后需要由醫美咨詢師為每一位顧客新建一個客戶資料,而醫美行業的特殊性導致我們的大多數醫美客戶都為女性,因此在設計表單中的性別一欄上便可將默認值選擇為女性,這樣方便醫美咨詢師快速補充用戶信息,可以進行更高效的信息錄入。


          當然,我說了雙刃劍肯定代表它也有弊的一面,我舉一個反例,比如我們在設計一個調查問卷中,去預設一些默認值就不太合理,因為問卷中需要減少對選項值的干預,保證其真實性,才能讓默認選項會導致錄入的數據產生準確,避免為后期的數據分析埋下“深坑。”

          • 清除選擇:不知道大家有沒有發現,單選框在你選擇過后,就不能成為「為空狀態」。因為單選框沒有讓你跳過的回退機制,導致你在設計時就需要格外小心比如在一個表單中出現自己的婚姻狀況的單選框(非必填),里面有未婚、已婚、離異三種選擇,當我選擇未婚后,突然覺得這個信息較為私密,為了保證我自己的信息安全需要清除我剛才的選擇,這時我完全就沒有任何辦法,想要回退就只有一種選擇,刷新這個頁面,進行重新填寫。而我們在設計中不能避免此類方式,這時候就需要選項的 「容錯機制」


          • 容錯機制: 既然單選無法清除選擇,我們就要對單選進行相應的優化,比如在選項中設置一個為「為空選項」對這類情況進行容錯處理,不然用戶就會感受到無法回退的尷尬。這都是單選框所帶來的潛在交互,大家在設計中一定要格外注意。


          二、多選框 Checkbox

          2.1多選框的定義


          多選框,也常叫做復選框、勾選框,它允許用戶選擇一個或多個獨立選項,將自己想要的選項作為值,多個條件間的邏輯關系為并列關系。


          多選框在實際業務中其實也分為兩種不同形態:單個多選框與多選框。


          單個多選框:英文叫做(single checkbox)只出現一個多選框提供給用戶進行選擇,只包含“是”與“否”兩種邏輯,用戶可以選擇其一。它與之后「開關Switch」的邏輯十分接近,但兩者的適用場景也有很大不同。

          比如在我們經常遇到的用戶協議的頁面中,同意協議通常都是采取單個多選框的形式,而開關相比單個多選框,更加強調選中的狀態。之后會與開關進行深度對比,不做延展。



          多選框:是多選框的一種通用樣式,允許用戶選擇多個項,主要用于各類表單設計中,所以用戶對于它的認知、功能以及行為操作有明確的心理預期和感知。


          2.2多選框的特殊狀態


          多選框相比其它控件,增加了兩個較為特殊的狀態 “半選中” “禁用(已選中)” ,因此這里僅僅單獨講解,其他狀態便不做過多贅述。


          • 半選中:

          半選中狀態(Indeterminate)出現的條件必須具備以下兩點:


          1. 擁有「全選」功能,因為半選中狀態是全選狀態的一種特殊狀態形式,它依附于全選。所以是當一個選擇框中有全選狀態才會有幾率出現半選狀態。
          2. 擁有「選中狀態的子項」,如果我們把全選看作是「父」,則其下的子選項看做是「子」,因為交互底層邏輯便是狀態的改變需要隨時體現,因為「子」狀態的變化,作為「父」的狀態也應該隨之改變,這樣的父子聯動才會有半選中狀態的出現。


          上面說到需要父子聯動,全選是選中其下所有的選項,而我只選擇了其下一個選項時,就應該展示半選中狀態。同時,當前多選框正在處于半選中狀態時,點擊多選框會執行全選操作。



          • 禁用-已選中:

          禁用-已選中狀態(Checked-disable)出現多表示該多選框已經被激活,只是在當前情況下不能進行操作。通常不能進行操作的場景有以下兩點:

          1. 登錄賬號權限不足,無法對該條數據進行修改。且在此之前,該條數據已經被激活。
          2. 該操作為系統級別操作,通常展示出來是為了讓用戶了解到有此類操作;同時并不允許用戶操作此權限。因而采取禁用已選中進行表示。


          當然多選框還會有很多不同狀態,會在章節末尾進行表格總結

          2.3多選的交互邏輯


          • 選項數量:與單選基本一致,因為所有選項基本處于外露狀態,因此不建議放5個以上的選項值,超過5個時可考慮采取下拉菜單的形式,避免選項多且復雜,難以把控。
          • 默認值:默認值在多選框中并不常見,在一個多選框中設置默認值一定要思考清楚。當然這里也會存在用戶之前的數據,那就另當別論。
          • 需要提交操作:在多選的場景中,提交是必不可少的一個操作情況,這里先按下不表,會與第三章的「開關」進行一個簡單的對比。


          2.4典型頁面

          在實際工作中,多選框會出現在一些典型的頁面場景中,針對不同的頁面場景,我們來看看究竟應該如何進行處理。


          • 用戶權限管理

          在用戶權限管理頁面中,經常會出現多選框的身影,而在權限這類頁面中,往往是一個不斷重復排列的多選框,針對不同的角色,去選擇不同的權限。且每一個權限都是開啟或關閉狀態,也因此采取多選框也尤為合適。我們來看看不同產品中,都有著哪些權限頁面設置的技巧。

          語雀:

          權限作為語雀的一個亮點功能,便將所有角色分為三類:管理員、成員、只讀成員



          在定義中,因為管理員擁有全部權限,所以不需要用戶單獨進行配置。只讀成員同樣只會擁有單獨的查看權限,而我們需要去對成員進行單獨的配置,然后將成員的權限進行細分,由于權限的數量并不多,因此采取縱向排列,方便用戶對于多個權限進行對比。


          上面語雀的權限配置頁面過于簡單,在真實B端業務時就會顯得有些弱不經風。我們實際工作中面對多維度多層級的權限管理時,又應該如何設計?我們來看看 Coding 它是如何做的。


          因為在一個正常的B端軟件中,權限通常會拆分得特別細,對于不同字段與角色,他們的權限也會不盡相同。



          Coding首先在左側會展示“用戶組”也就是我們上面說到的角色分類,用戶可以去自定義角色類型有哪些,其次在對角色權限的配置中,會展示出用戶可以自定義的所有功能,粗略估算大概會有100+個權限,也就意味著會有100+個多選框需要展示。當100+的多選框放在你面前,最為基礎的對齊則顯得尤為關鍵。通過限制多選框標簽的整體寬度,強制將其縱向對齊,雖然遇到長文本時省略給用戶帶來不太友好的體驗,但對齊所帶來的留白、節奏感是遠比省略帶來的好處要多(當然在對長文本寬度的定義中,需要多考慮下常見字段的長度即可)


          其次,在每一個大功能中,Coding都設置有一個全選功能,目前放置在整個列表的末尾,是一個特別贊的設計,能夠幫助用戶對每一個字段的權限進行統一配置,是一個經常使用的快捷入口。


          • 流程管理頁面


          在流程管理頁面中,多選框也是不可忽略的頁面。因為在整個流程頁面中會對每個狀態執行開啟與關閉操作,因此在這里同樣會重復多選框。



          比如在 ONES 的流程管理頁面中,看起來像是表格,其中縱向代表每個「流程開始狀態」,橫向代表每個流程階段所要去向哪些狀態,每個表格都會展示一個復選框,去配置它是否要流轉到此狀態,從而實現業務流轉的需求。

          而在這里的設計,最令人頭疼的是整體的表現形式,因為目前而言,需要將初始狀態、新增狀態、激活狀態、禁用狀態等在一個表格中進行表示,更重要的是要能夠讓用戶理解整個表格所代表的含義,這也是目前能看到的最好的設計成品,大家有什么更好的建議,歡迎在評論區留言,大家一起討論。


          • 表格頁面

          表格頁面最為復雜多變,也因此在表格中的多選框出現了兩種不同的形式,一種將多選框直接展示,讓用戶更直接選擇。另一種則是Hover到每一行顯示多選框,同時一定要去注意全選與半選中的邏輯,在表格的設計上尤為重要,不能出現邏輯上的漏洞,這里也就不過多贅述。

          最后補充一下多選框的所有狀態的交互邏輯


          三、開關 Switch


          3.1開關的定義

          開關,它是一種特殊的選擇,其含義代表你的選擇非黑即白。它不同于上面的控件,當用戶點擊后,開關需要經歷一個加載狀態,然后「立即執行」。這樣的差別就導致開關的用法與其它控件并不相同,立即執行所帶來的及時性也是設計師最容易與其他組件進行混淆的點。


          3.2 開關的由來

          在開關的早期,為了降低用戶的學習成本,模仿現實生活中的開關進行設計,而隨著扁平風格的到來,開關便得到了精簡,去掉原本產品中的質感、投影,轉向更加明確的「狀態信息」

          轉眼到了 B端產品中,很多設計師都會沿用這一習慣,但是在HTML的代碼邏輯里,并沒有 Switch 的標簽,也就意味著開關并不是網頁本身所支持的形式,在程序員處理上則需要花費更多心思。不過在目前常見的前端框架中,對開關都進行了支持,比如 Element、Antdesign 可以直接引用。


          3.3 開關的交互邏輯

          雖然在組件上可以直接進行引用,但并不代表我們作為設計者,不需要去考慮它基本的交互邏輯以及使用場景。


          • 即時性:開關是一個立即執行的操作,因此它打破了人們對于正常表單的認知(需要有按鈕進行數據提交),因此開關與表單是一個相互排斥的關系,兩者同時出現必然會產生些許矛盾,表單中使用開關切記要慎重。那如何處理開關與表單之間的關系?就需要理解開關與表單間的「權重關系」
          • 權重關系:開關要比表單的權重更高。開關會位于整個表單的頂部,對下面的表單進行整體操作,說起來更點空洞,我們看一個 MacOS 的案例:



          在最新 Big Sur 系統中,設置頁面就采取了類似操作,我們打開設置-通知,發現開關與表單同時存在。這里也可看到,允許通知的開關在最頂層,是控制整個表單權重最高的操作,同時下方單選、多選框、下拉菜單都受到頂部開關控制。

          當然,我們在實際的設計中,同樣會遇到類似的情況,比如在飛書的自建應用免審規則配置中:首先用戶需要去選擇開啟此功能,開啟后下方會展開一個基本表單,用于用戶對應用規則中更為細致的配置,并且要注意,所有的配置都是實時生效,因此在每一次修改配置時,飛書上都會有 Loading 效果。



          當然我們可以將開關換成單一多選框,但切換后用戶就很難理一二級之間的邏輯關系,因此開關更為適合權重更高的操作。



          • 明確性:開關能明確的表示當前的狀態,當開關亮起時,則代表開關進入開啟狀態,當開關置灰時則進行關閉狀態(感覺好像是廢話,但你得需細細的品)并且在開關的使用中,是通過表達當前系統的狀態,因此在開關所配合的文案中需要格外注意。另外還有一個小店


          • 重要提示:因為開關的權重更高,狀態也更為明確,因此它的出現多為一些需要系統校驗的操作,對于用戶不滿足條件時,需要進行禁止的提示。比如在明道云的工作流列表中,用戶便可使用開關對流程進行快速開啟,不滿足條件時,會有提示彈窗進行提示,并能讓用戶快速跳轉進行修改操作。



          • 加載狀態:最后開關作為一個關鍵操作,在 B端系統層面上同樣會有進行加載的情況,這里就提醒一下大家,不做擴展。


          3.4 開關的討論 - 為開關正名

          在互聯網上,時常看到 DISS 開關不應該出現在網頁設計中,這里看到了一篇文章中討論到《為什么在web上使用Switch是愚蠢的設計》,其實我有不同的意見,簡單說一說我對開關的看法:


          因為在 B 端的場景中,會有很多特殊的要求,因此不能一桿子將 Switch 進行一桿子打死,凡事都得辯證看待,需要去看到開關好的一面,并且規避它的一些不足。


          首先,在 Web 端中不能大面積的去使用開關,因為大量的開關導致的就是對頁面設計的褻瀆,當然開關依然有它的獨特之處,在開關的交互邏輯中雖然已經提到了部分特點,但我還是來簡單說說我的理由:


          使用開關主要是想利用開關狀態去“做文章”。使用開關在比起其他條件,會更加強調它的狀態,并能讓用戶通過狀態去控制下層的其他組件(單選框、多選框等…)這就是開關在 B端產品中的實際需求。


          同時因為開關是立即執行的操作,因此需要在每一次變更狀態時進行相應的反饋,比如表單組件狀態上的提示,輔助用戶進行判斷狀態即可。



          回到我們討論的開關在 WEB 中的使用上,并不能因為因為開關不是 HTML 基礎標簽而去否定,并且在我們 B端實際業務中,確實會遇到開關的場景,因此大家在使用開關時還是應該根據情況,進行使用。


          由于選擇錄入場景的內容較多,02篇即將更新,歡迎大家關注


          我是CE青年,一個 2 B 行業的 2B 設計師~


          主站蜘蛛池模板: 国产精品久久久久久一区二区三区| 好吊视频一区二区三区| 中文字幕一区二区精品区| 中文字幕一区二区三区四区| 国产一区二区在线观看app| 久久无码精品一区二区三区| 国产乱码一区二区三区爽爽爽| 国产精品毛片VA一区二区三区| 人妻无码久久一区二区三区免费| 中文字幕人妻第一区| 国产成人免费一区二区三区| 国产午夜精品一区二区三区不卡| 少妇精品久久久一区二区三区| 无码人妻一区二区三区一| 国产视频一区二区| 国产成人AV一区二区三区无码| 中文字幕av一区| 精品视频一区二区三区| 国产精品视频分类一区| 无码精品蜜桃一区二区三区WW| 一区二区三区视频在线观看| 国产日韩综合一区二区性色AV| 亚洲啪啪综合AV一区| 精品国产一区在线观看| 成人免费区一区二区三区| 日本高清一区二区三区| 国产精华液一区二区区别大吗 | 中文字幕精品一区| 久久无码AV一区二区三区| 日韩一区二区在线观看| 97一区二区三区四区久久| 国产精品区AV一区二区| 国产精品第一区揄拍| 波多野结衣免费一区视频| 国产综合精品一区二区| 亚洲国产av一区二区三区丶| 国产精品区AV一区二区| 成人欧美一区二区三区在线视频| 亚洲日韩精品一区二区三区| 日本精品少妇一区二区三区| 中文字幕在线不卡一区二区|