Smart-Admin数据选择器:uni-data-picker集成方案

Smart-Admin数据选择器:uni-data-picker集成方案

【免费下载链接】smart-admin 【免费下载链接】smart-admin 项目地址: https://gitcode.com/gh_mirrors/smar/smart-admin

一、痛点解析:移动端数据选择的3大挑战

你是否还在为移动端级联选择组件开发而头疼?在企业级应用开发中,数据选择器需要满足多层级数据加载异步数据联动灵活数据源适配三大核心需求。传统解决方案往往面临以下痛点:

  • 性能瓶颈:一次性加载全量数据导致页面卡顿
  • 代码冗余:重复编写数据转换和事件处理逻辑
  • 扩展性差:难以适配不同业务场景的数据源格式

本文将详解如何基于uni-app生态的uni-data-picker组件,在Smart-Admin项目中构建高效、灵活的数据选择解决方案,彻底解决以上痛点。

二、技术选型:为什么选择uni-data-picker?

2.1 核心优势分析

特性uni-data-picker传统自定义组件
数据加载模式支持分步加载/预加载需手动实现
数据格式兼容性内置数据映射转换需编写适配代码
多端适配全端兼容需单独处理
选中状态管理内置双向绑定需手动维护
搜索功能支持分步搜索需额外集成

2.2 Smart-Admin中的技术定位

mermaid

在Smart-Admin移动应用架构中,uni-data-picker作为基础选择器组件,被封装为DictSelect等业务组件,形成了"基础组件→业务组件→页面应用"的三层架构。

三、实现方案:从基础集成到业务封装

3.1 核心组件解析

3.1.1 uni-data-picker组件结构
<template>
  <uni-data-picker 
    v-model="selectedValue"
    :localdata="options"
    :step-search="true"
    :map="customMap"
    popup-title="请选择"
    @change="handleChange"
  />
</template>

核心属性说明:

  • localdata:本地数据源,格式为数组或对象
  • step-search:启用分步搜索,优化大数据加载性能
  • map:自定义数据映射规则,适配不同数据源格式
3.1.2 组件工作流程图

mermaid

3.2 字典选择器封装实践

在Smart-Admin中,基于uni-data-picker封装的DictSelect组件实现了与后端字典服务的无缝对接:

<template>
  <uni-data-picker 
    v-model="selectValue"
    :localdata="dictValueList"
    :placeholder="placeholder"
    @change="onChange"
  />
</template>

<script setup>
import { onMounted, ref, watch } from 'vue';
import { dictApi } from '@/api/support/dict-api';

const props = defineProps({
  keyCode: String,
  modelValue: String,
  placeholder: {
    type: String,
    default: '请选择'
  }
});

// 字典数据加载
const dictValueList = ref([]);
async function queryDict() {
  const res = await dictApi.valueList(props.keyCode);
  // 数据格式转换适配uni-data-picker要求
  dictValueList.value = res.data.map(e => ({
    text: e.valueName,
    value: e.valueCode
  }));
}
onMounted(queryDict);

// 双向绑定实现
const selectValue = ref(props.modelValue);
watch(() => props.modelValue, (value) => {
  selectValue.value = value;
});

const emit = defineEmits(['update:modelValue', 'change']);
function onChange(e) {
  emit('update:modelValue', e.detail.value);
}
</script>

3.3 高级特性实现

3.3.1 分步加载与数据预处理
// 分步加载实现示例
export const DEPARTMENT_TREE = {
  // 第一级数据
  async level1() {
    const res = await departmentApi.list({ parentId: 0 });
    return res.data.map(item => ({
      text: item.departmentName,
      value: item.id,
      // 标记有子节点
      hasChildren: item.hasChildren
    }));
  },
  // 第二级数据
  async level2(parentValue) {
    const res = await departmentApi.list({ parentId: parentValue });
    return res.data.map(item => ({
      text: item.departmentName,
      value: item.id
    }));
  }
};
3.3.2 数据映射与格式转换

当后端返回格式与组件要求不一致时,通过map属性进行转换:

<uni-data-picker
  :localdata="rawData"
  :map="{
    text: 'label',  // 将label字段映射为显示文本
    value: 'code',  // 将code字段映射为值
    children: 'items' // 将items字段映射为子节点
  }"
/>

四、实战案例:人员选择器开发全流程

4.1 需求分析

实现一个支持部门-人员二级联动选择的组件,需满足:

  • 部门数据异步加载
  • 选择人员后返回完整信息
  • 支持多选功能
  • 已选人员标签化展示

4.2 实现方案

mermaid

4.3 核心代码实现

<template>
  <view class="container">
    <!-- 部门选择器 -->
    <uni-data-picker
      v-model="deptValue"
      :localdata="deptOptions"
      popup-title="选择部门"
      @change="handleDeptChange"
    />
    
    <!-- 人员选择列表 -->
    <view class="employee-list">
      <view class="employee-item" v-for="item in empOptions" :key="item.id">
        <checkbox :value="item.id" @change="handleEmpCheck(item)"/>
        <view class="emp-info">
          <text class="emp-name">{{item.name}}</text>
          <text class="emp-position">{{item.position}}</text>
        </view>
      </view>
    </view>
    
    <!-- 已选标签 -->
    <view class="selected-tags">
      <view class="tag" v-for="item in selectedEmps" :key="item.id">
        {{item.name}}
        <text class="tag-close" @click="removeEmp(item.id)">×</text>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      deptValue: '',
      deptOptions: [],
      empOptions: [],
      selectedEmps: []
    };
  },
  methods: {
    async loadDepartments() {
      const res = await this.$api.department.list();
      this.deptOptions = res.data.map(item => ({
        text: item.name,
        value: item.id
      }));
    },
    
    async handleDeptChange(e) {
      const deptId = e.detail.value;
      const res = await this.$api.employee.list({ deptId });
      this.empOptions = res.data;
    },
    
    handleEmpCheck(emp) {
      const index = this.selectedEmps.findIndex(item => item.id === emp.id);
      if (index === -1) {
        this.selectedEmps.push(emp);
      } else {
        this.selectedEmps.splice(index, 1);
      }
    },
    
    removeEmp(id) {
      this.selectedEmps = this.selectedEmps.filter(item => item.id !== id);
    }
  },
  mounted() {
    this.loadDepartments();
  }
};
</script>

4.4 样式实现

.employee-list {
  padding: 15px;
  
  .employee-item {
    display: flex;
    align-items: center;
    padding: 10px 0;
    border-bottom: 1px solid #eee;
    
    .emp-info {
      margin-left: 10px;
      
      .emp-name {
        font-size: 16px;
        color: #333;
      }
      
      .emp-position {
        font-size: 14px;
        color: #666;
        margin-top: 2px;
      }
    }
  }
}

.selected-tags {
  display: flex;
  flex-wrap: wrap;
  padding: 15px;
  gap: 8px;
  
  .tag {
    background: #e8f3ff;
    color: #1a9aff;
    padding: 4px 10px;
    border-radius: 15px;
    font-size: 14px;
    display: flex;
    align-items: center;
    
    .tag-close {
      margin-left: 5px;
      font-size: 16px;
    }
  }
}

五、性能优化:大数据场景下的加载策略

5.1 数据加载优化对比

加载策略适用场景优点缺点
一次性加载数据量<100条实现简单,无网络延迟大数据时卡顿
分步加载层级明确的数据按需加载,初始加载快需要多层级交互
虚拟滚动平级大量数据流畅滚动,内存占用低实现复杂
预加载+缓存用户频繁访问的数据响应迅速,减少请求次数占用一定存储空间

5.2 分步加载实现代码

export default {
  data() {
    return {
      treeData: [],
      currentLevel: 1,
      loadedLevels: {}
    };
  },
  methods: {
    async loadLevelData(level, parentValue) {
      // 检查缓存
      if (this.loadedLevels[`${level}-${parentValue}`]) {
        return this.loadedLevels[`${level}-${parentValue}`];
      }
      
      // 根据层级加载不同数据
      let res;
      if (level === 1) {
        res = await this.$api.department.list({ parentId: 0 });
      } else if (level === 2) {
        res = await this.$api.employee.list({ deptId: parentValue });
      }
      
      // 处理数据格式并缓存
      const data = res.data.map(item => ({
        text: item.name,
        value: item.id,
        // 标记是否有子级
        hasChildren: level < 2
      }));
      
      this.loadedLevels[`${level}-${parentValue}`] = data;
      return data;
    }
  }
};

六、最佳实践:Smart-Admin中的封装规范

6.1 组件封装标准

在Smart-Admin项目中,所有基于uni-data-picker的封装组件需遵循以下规范:

  1. 属性标准化

    • 统一使用v-model进行双向绑定
    • 提供placeholderdisabled等基础属性
    • 使用dictCode指定字典类型
  2. 事件标准化

    • @change事件返回{value, label}格式
    • 支持@input实时输入事件
    • 错误处理统一使用@error事件
  3. 样式规范

    • 统一使用smart-前缀的CSS变量
    • 适配主题色变量--smart-primary-color
    • 响应式设计适配不同屏幕

6.2 字典选择器完整封装示例

<template>
  <uni-data-picker
    v-model="currentValue"
    :localdata="dictOptions"
    :placeholder="placeholder"
    :disabled="disabled"
    :clearable="clearable"
    @change="handleChange"
  />
</template>

<script>
import { FLAG_NUMBER_ENUM } from '@/constants/common-const';

export default {
  name: 'SmartDictSelect',
  props: {
    // 字典编码
    dictCode: {
      type: String,
      required: true
    },
    // 绑定值
    modelValue: {
      type: [String, Number],
      default: ''
    },
    // 占位符
    placeholder: {
      type: String,
      default: '请选择'
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false
    },
    // 是否可清除
    clearable: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      currentValue: this.modelValue,
      dictOptions: []
    };
  },
  watch: {
    modelValue(val) {
      this.currentValue = val;
    },
    dictCode() {
      this.loadDictData();
    }
  },
  mounted() {
    this.loadDictData();
  },
  methods: {
    async loadDictData() {
      const res = await this.$api.dict.getValueList(this.dictCode);
      this.dictOptions = res.data.map(item => ({
        text: item.valueName,
        value: item.valueCode
      }));
    },
    handleChange(e) {
      const value = e.detail.value;
      const label = this.dictOptions.find(item => item.value === value)?.text || '';
      this.$emit('update:modelValue', value);
      this.$emit('change', { value, label });
    }
  }
};
</script>

<style scoped>
/* 使用主题变量 */
::v-deep .uni-data-picker {
  --input-border-color: var(--smart-border-color);
  --input-text-color: var(--smart-text-color);
  --input-placeholder-color: var(--smart-placeholder-color);
}
</style>

七、总结与展望

通过本文介绍的uni-data-picker集成方案,Smart-Admin项目成功解决了移动端数据选择的核心痛点。该方案具有以下优势:

  1. 提升开发效率:组件化封装减少80%重复代码
  2. 优化用户体验:分步加载提升页面响应速度
  3. 增强系统稳定性:统一的数据处理逻辑减少异常

未来计划从以下方面进一步优化:

  • 集成虚拟滚动提升大数据渲染性能
  • 增加自定义模板支持复杂展示需求
  • 开发可视化配置工具降低使用门槛

掌握这套集成方案,你将能够快速构建各类复杂数据选择场景,显著提升企业级移动应用的开发效率和用户体验。

点赞+收藏本文,获取后续《Smart-Admin组件封装实战》系列文章更新!

【免费下载链接】smart-admin 【免费下载链接】smart-admin 项目地址: https://gitcode.com/gh_mirrors/smar/smart-admin

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值