Browse Source

feat: `ReSegmented`分段控制器新增`size`属性,以便适配不同的场景 (#1016)

* feat: `ReSegmented`分段控制器新增`size`属性,以便适配不同的场景
Fifteen 1 year ago
parent
commit
f486ba60a0

+ 81 - 20
src/components/ReSegmented/src/index.css

@@ -1,11 +1,20 @@
 .pure-segmented {
+  --pure-control-padding-horizontal: 12px;
+  --pure-control-padding-horizontal-sm: 8px;
+  --pure-segmented-track-padding: 2px;
+  --pure-segmented-line-width: 1px;
+
+  --pure-segmented-border-radius-small: 4px;
+  --pure-segmented-border-radius-base: 6px;
+  --pure-segmented-border-radius-large: 8px;
+
   box-sizing: border-box;
   display: inline-block;
-  padding: 2px;
-  font-size: 14px;
+  padding: var(--pure-segmented-track-padding);
+  font-size: var(--el-font-size-base);
   color: rgba(0, 0, 0, 0.65);
   background-color: rgb(0 0 0 / 4%);
-  border-radius: 2px;
+  border-radius: var(--pure-segmented-border-radius-base);
 }
 
 .pure-segmented-block {
@@ -23,6 +32,75 @@
   text-overflow: ellipsis;
 }
 
+/* small */
+.pure-segmented.pure-segmented--small {
+  border-radius: var(--pure-segmented-border-radius-small);
+}
+.pure-segmented.pure-segmented--small .pure-segmented-item {
+  border-radius: var(--el-border-radius-small);
+}
+.pure-segmented.pure-segmented--small .pure-segmented-item > div {
+  min-height: calc(
+    var(--el-component-size-small) - var(--pure-segmented-track-padding) * 2
+  );
+  line-height: calc(
+    var(--el-component-size-small) - var(--pure-segmented-track-padding) * 2
+  );
+  padding: 0
+    calc(
+      var(--pure-control-padding-horizontal-sm) -
+        var(--pure-segmented-line-width)
+    );
+}
+
+/* large */
+.pure-segmented.pure-segmented--large {
+  border-radius: var(--pure-segmented-border-radius-large);
+}
+.pure-segmented.pure-segmented--large .pure-segmented-item {
+  border-radius: calc(
+    var(--el-border-radius-base) + var(--el-border-radius-small)
+  );
+}
+.pure-segmented.pure-segmented--large .pure-segmented-item > div {
+  min-height: calc(
+    var(--el-component-size-large) - var(--pure-segmented-track-padding) * 2
+  );
+  line-height: calc(
+    var(--el-component-size-large) - var(--pure-segmented-track-padding) * 2
+  );
+  padding: 0
+    calc(
+      var(--pure-control-padding-horizontal) - var(--pure-segmented-line-width)
+    );
+  font-size: var(--el-font-size-medium);
+}
+
+/* default */
+.pure-segmented-item {
+  position: relative;
+  text-align: center;
+  cursor: pointer;
+  border-radius: var(--el-border-radius-base);
+  transition: all 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
+}
+.pure-segmented .pure-segmented-item > div {
+  min-height: calc(
+    var(--el-component-size) - var(--pure-segmented-track-padding) * 2
+  );
+  line-height: calc(
+    var(--el-component-size) - var(--pure-segmented-track-padding) * 2
+  );
+  padding: 0
+    calc(
+      var(--pure-control-padding-horizontal) - var(--pure-segmented-line-width)
+    );
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  transition: 0.1s;
+}
+
 .pure-segmented-group {
   position: relative;
   display: flex;
@@ -52,23 +130,6 @@
   will-change: transform, width;
 }
 
-.pure-segmented-item {
-  position: relative;
-  text-align: center;
-  cursor: pointer;
-  border-radius: 4px;
-  transition: all 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
-}
-
-.pure-segmented-item > div {
-  min-height: 28px;
-  line-height: 28px;
-  padding: 0 11px;
-  overflow: hidden;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-}
-
 .pure-segmented-item > input {
   position: absolute;
   inset-block-start: 0;

+ 25 - 11
src/components/ReSegmented/src/index.tsx

@@ -1,5 +1,14 @@
 import "./index.css";
+import type { OptionsType } from "./type";
+import { useRenderIcon } from "@/components/ReIcon/src/hooks";
+import {
+  useDark,
+  isNumber,
+  isFunction,
+  useResizeObserver
+} from "@pureadmin/utils";
 import {
+  type PropType,
   h,
   ref,
   toRef,
@@ -8,14 +17,6 @@ import {
   defineComponent,
   getCurrentInstance
 } from "vue";
-import type { OptionsType } from "./type";
-import { useRenderIcon } from "@/components/ReIcon/src/hooks";
-import {
-  isFunction,
-  isNumber,
-  useDark,
-  useResizeObserver
-} from "@pureadmin/utils";
 
 const props = {
   options: {
@@ -32,6 +33,10 @@ const props = {
   block: {
     type: Boolean,
     default: false
+  },
+  /** 控件尺寸	 */
+  size: {
+    type: String as PropType<"small" | "default" | "large">
   }
 };
 
@@ -81,13 +86,14 @@ export default defineComponent({
     function handleInit(index = curIndex.value) {
       nextTick(() => {
         const curLabelRef = instance?.proxy?.$refs[`labelRef${index}`] as ElRef;
+        if (!curLabelRef) return;
         width.value = curLabelRef.clientWidth;
         translateX.value = curLabelRef.offsetLeft;
         initStatus.value = true;
       });
     }
 
-    if (props.block) {
+    function handleResizeInit() {
       useResizeObserver(".pure-segmented", () => {
         nextTick(() => {
           handleInit(curIndex.value);
@@ -95,6 +101,8 @@ export default defineComponent({
       });
     }
 
+    props.block && handleResizeInit();
+
     watch(
       () => curIndex.value,
       index => {
@@ -103,11 +111,12 @@ export default defineComponent({
         });
       },
       {
-        deep: true,
         immediate: true
       }
     );
 
+    watch(() => props.size, handleResizeInit);
+
     const rendLabel = () => {
       return props.options.map((option, index) => {
         return (
@@ -167,7 +176,12 @@ export default defineComponent({
 
     return () => (
       <div
-        class={["pure-segmented", props.block ? "pure-segmented-block" : ""]}
+        class={{
+          "pure-segmented": true,
+          "pure-segmented-block": props.block,
+          "pure-segmented--large": props.size === "large",
+          "pure-segmented--small": props.size === "small"
+        }}
       >
         <div class="pure-segmented-group">
           <div

+ 25 - 10
src/views/components/segmented.vue

@@ -1,5 +1,5 @@
 <script setup lang="tsx">
-import { h, ref } from "vue";
+import { h, ref, watch } from "vue";
 import { message } from "@/utils/message";
 import HomeFilled from "@iconify-icons/ep/home-filled";
 import { useRenderIcon } from "@/components/ReIcon/src/hooks";
@@ -11,6 +11,8 @@ defineOptions({
 
 /** 基础用法 */
 const value = ref(4); // 必须为number类型
+const size = ref("default");
+const dynamicSize = ref();
 
 const optionsBasis: Array<OptionsType> = [
   {
@@ -192,13 +194,22 @@ function onChange({ index, option }) {
     type: "success"
   });
 }
+
+watch(size, val => (dynamicSize.value = size.value));
 </script>
 
 <template>
   <el-card shadow="never">
     <template #header>
       <div class="card-header">
-        <span class="font-medium">分段控制器</span>
+        <el-space wrap :size="40">
+          <span style="font-size: 16px; font-weight: 800"> 分段控制器 </span>
+          <el-radio-group v-model="size" size="small">
+            <el-radio value="large">大尺寸</el-radio>
+            <el-radio value="default">默认尺寸</el-radio>
+            <el-radio value="small">小尺寸</el-radio>
+          </el-radio-group>
+        </el-space>
       </div>
     </template>
     <el-scrollbar>
@@ -207,28 +218,32 @@ function onChange({ index, option }) {
           {{ optionsBasis[value].label }}
         </span>
       </p>
-      <Segmented v-model="value" :options="optionsBasis" />
+      <Segmented v-model="value" :options="optionsBasis" :size="dynamicSize" />
       <el-divider />
       <p class="mb-2">tooltip 提示</p>
-      <Segmented :options="optionsTooltip" />
+      <Segmented :options="optionsTooltip" :size="dynamicSize" />
       <el-divider />
       <p class="mb-2">change 事件</p>
-      <Segmented :options="optionsChange" @change="onChange" />
+      <Segmented
+        :options="optionsChange"
+        :size="dynamicSize"
+        @change="onChange"
+      />
       <el-divider />
       <p class="mb-2">禁用</p>
-      <Segmented :options="optionsDisabled" />
+      <Segmented :options="optionsDisabled" :size="dynamicSize" />
       <el-divider />
       <p class="mb-2">block 属性(将宽度调整为父元素宽度)</p>
-      <Segmented :options="optionsBlock" block />
+      <Segmented :options="optionsBlock" block :size="dynamicSize" />
       <el-divider />
       <p class="mb-2">可设置图标</p>
-      <Segmented :options="optionsIcon" />
+      <Segmented :options="optionsIcon" :size="dynamicSize" />
       <el-divider />
       <p class="mb-2">只设置图标</p>
-      <Segmented :options="optionsOnlyIcon" />
+      <Segmented :options="optionsOnlyIcon" :size="dynamicSize" />
       <el-divider />
       <p class="mb-2">自定义渲染</p>
-      <Segmented :options="optionsLabel" />
+      <Segmented :options="optionsLabel" :size="dynamicSize" />
     </el-scrollbar>
   </el-card>
 </template>