uni-app微信小程序开发自定义select下拉多选内容篇

3 篇文章 0 订阅
2 篇文章 0 订阅

欢迎点击领取 -《前端开发面试题进阶秘籍》:前端登顶之巅-最全面的前端知识点梳理总结

在这里插入图片描述

技术框架公司的选型:uni-app + uni-ui + vue3 + vite4 + ts

需求分析:微信小程序-uni-ui内容
1、创建一个自定义的下拉,支持多个内容的同时多选
2、定义好出入参数,支持回显内容等
3、绑定对应的v-model数据响应

在这里插入图片描述

1、代码信息
<template>
  <view tabindex="1" ref="customSelectRef" class="uni-select" @click.stop="handleClickDiv">
    <view>
      <template v-if="modelLabel.length">
        <span class="custom-tag" :key="index" v-for="(item, index) in modelLabel">
          <span>{{ item }}</span>
        </span>
      </template>
      <span class="custom-tag" v-if="modelLabel.length && checkList.length - maxLength > 0">
        + {{ checkList.length - maxLength }}
      </span>
      <span v-if="!modelLabel.length" class="cus_placeholder">{{ placeholder }}</span>
      <img
        class="icon-delete"
        v-if="modelLabel.length"
        @click.stop="handleRemove"
        :src="'../../static/icons/delete.png'"
      />
    </view>
    <transition>
      <view class="cus_select_background" ref="cusSelectDropdown" v-if="isShowDropdown" @click="handleMemory">
        <view class="cus_tabs" :key="index" v-for="(item, index) in cusDataListChecked">
          <template v-if="item.children">
            <view class="cus_tabs_title">{{ item.text }}</view>
            <view class="cus_tabs_body">
              <uni-data-checkbox
                mode="tag"
                :multiple="multiple"
                v-model="item.checkList"
                :localdata="item.children"
                @change="(val) => handleCheckedChange(val, item)"
              ></uni-data-checkbox>
            </view>
          </template>
        </view>
      </view>
    </transition>
    <view v-if="isShowDropdown" class="custom_mask"></view>
  </view>
</template>

<script setup lang="ts">
import { watch } from "vue";
import { toRaw } from "vue";
import { ref, onMounted, nextTick, onBeforeMount } from "vue";

const props = withDefaults(
  defineProps<{
    dataSource: any;
    modelValue?: any;
    placeholder?: string;
    multiple?: boolean;
    maxLength?: number;
  }>(),
  {
    multiple: true,
    dataSource: [],
    modelValue: [],
    maxLength: 3,
    placeholder: "请选择",
  }
);

const emit = defineEmits(["update:modelValue", 'change']);

const customSelectRef = ref();

const cusSelectDropdown = ref();

const modelLabel = ref<Record<string, any>[]>([]);

const checkList = ref<string[]>([]);

const cusDataListChecked = ref<Record<string, any>[]>([]);

const isShowDropdown = ref<boolean>(false);

const isShowDownMemory = ref<boolean>(false);

const handleClickDiv = () => {
  isShowDropdown.value = isShowDownMemory.value ? true : !isShowDropdown.value;
  isShowDownMemory.value = false;
};

const handleMemory = () => {
  isShowDownMemory.value = true;
};

const handleCheckedChange = (e: Record<string, any>, row: Record<string, any>) => {
  const { data } = e.detail;
  row.checkLabel = data.map((opt) => opt.text);
  getModelVal();
};

const getModelVal = () => {
  const newValue = toRaw(cusDataListChecked.value);
  const newLabel = newValue.map((item) => item.checkLabel);
  const newModelVal = newValue.map((item) => item.checkList);
  const deconstructLabel = newLabel?.flat();
  const deconstructVal = newModelVal?.flat();
  modelLabel.value = deconstructLabel.slice(0, props.maxLength);
  checkList.value = deconstructVal;
  emit("update:modelValue", newModelVal);
};

const handleRemove = (e) => {
  modelLabel.value = [];
  checkList.value = [];
  if (isShowDropdown.value) {
    isShowDropdown.value = false;
  }
  if (props.multiple) {
    cusDataListChecked.value = addCheckProperties(props.dataSource);
  }
  emit("update:modelValue", []);
};

const addCheckProperties = (treeData) => {
  let result = [];
  result = JSON.parse(JSON.stringify(treeData));
  result.forEach((node) => {
    const child = node.children;
    node.checkList = [];
    node.checkLabel = [];
    if (child && child.length > 0) {
      addCheckProperties(child);
    }
  });
  return result;
};

const findTreeChecked = (treeData) => {
  const newLabel = [];
  const val = toRaw(props.modelValue);
  treeData.forEach((node, index) => {
    if (node.children?.length) {
      const child = node.children;
      const bool = child.some((opt) => {
        const isExist = val[index] && val[index].includes(opt.value);
        isExist ? newLabel.push(opt.text) : void null;
        return isExist;
      });
      if (bool) {
        node.checkLabel = newLabel;
        node.checkList = val[index];
      }
    }
  });
  return treeData;
};

watch(isShowDropdown, (newVal) => {
  emit('change', newVal, props.modelValue)
})

onBeforeMount(() => {
  if (props.multiple) {
    cusDataListChecked.value = addCheckProperties(props.dataSource);
  }
});

onMounted(async () => {
  await nextTick();
  if (props.multiple && props.modelValue.length) {
    cusDataListChecked.value = findTreeChecked(cusDataListChecked.value);
    getModelVal();
  }
});
</script>

<style lang="scss" scoped>
.uni-select {
  font-size: 14px;
  border: 1px solid #e5e5e5;
  box-sizing: border-box;
  border-radius: 4px;
  padding: 0 5px 0 10px;
  position: relative;
  display: flex;
  user-select: none;
  flex-direction: row;
  align-items: center;
  border-bottom: solid 1px #e5e5e5;
  width: 100%;
  flex: 1;
  height: 35px;
  position: relative;
}

.cus_placeholder {
  color: #6a6a6a;
  font-size: 12px;
}

.icon-delete {
  position: absolute;
  width: 18px;
  height: 18px;
  right: 5px;
  margin-top: 3.5px;
  z-index: 10;
}

.cus_select_background {
  width: 95vw;
  max-height: 260px;
  box-sizing: border-box;
  border-radius: 4px;
  font-size: 13px;
  color: #606266;
  background: #ffffff;
  border: 1px solid #e4e7ed;
  position: absolute;
  top: 40px;
  left: 0px;
  padding: 5px 8px;
  z-index: 10;
}

.cus_tabs {
  margin-bottom: 8px;
  .cus_tabs_title {
    font-weight: 600;
    margin-bottom: 4px;
  }
  .cus_tabs_body {
    margin-left: 12px;
  }
}

.custom-tag {
  color: #909399;
  display: inline-flex;
  justify-content: center;
  align-items: center;
  height: 24px;
  padding: 0 9px;
  line-height: 1;
  border-radius: 4px;
  white-space: nowrap;
  font-size: 13px;
  margin-right: 5px;
  background-color: #f0f2f5;
}

.custom_mask {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 1;
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>
2、使用api介绍

1、树形结构入参:dataSource=[{ ext: "服务器状态", children: [{ text: "在线", value: 0}]}]
2、标签引用:<ivuSelect :maxLength="2" ref="ivuSelectRef" v-model="customSelect" :dataSource="deviceDataList" style="width: 100%; margin-left: 5px" />
3、相关api说明文档在文章底部

参数说明类型默认值必填项
dataSource[{}]-label,value;树形结构Array[][]
modelValue当前选中项内容Array[]
placeholder输入框内容String请输入
multiple是否开启多选Booleanfalse
maxLength输入框最大标签长度Number3
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1. 开发准备 在开始开发前,需要先进行一些准备工作: - 安装uni-app开发环境,详见uni-app官方文档; - 创建一个微信小程序开发者账号,获取小程序AppID; - 在小程序管理后台中,开启“获取用户信息”权限和“登录”权限。 2. 登录流程 在uni-app中,可以使用uni.login()方法进行微信登录。该方法返回一个promise对象,表示登录是否成功。在登录成功后,可以使用uni.getUserInfo()方法获取用户信息。 具体的登录流程如下: - 调用uni.login()方法进行微信登录,并获取到code值; - 将code值发送到后端服务器,后端服务器根据code值获取到用户的openid和session_key; - 将openid和session_key存储到本地storage中,用于后续的用户认证; - 根据获取到的用户openid,可以将用户与后端系统中的用户进行关联。 3. 获取用户信息 在登录成功后,可以使用uni.getUserInfo()方法获取用户信息。该方法返回一个promise对象,表示获取用户信息是否成功。在获取成功后,可以将用户信息展示到页面上,或者将用户信息发送到后端服务器。 具体的获取用户信息流程如下: - 调用uni.getUserInfo()方法获取用户信息; - 将获取到的用户信息展示到页面上,或者将用户信息发送到后端服务器。 4. 完整代码示例 下面是一个完整的uni-app微信小程序登录开发示例代码: ``` <template> <view class="container"> <view class="userinfo"> <button @tap="login" v-if="!hasUserInfo">微信登录</button> <image :src="userInfo.avatarUrl" v-if="hasUserInfo" /> <text>{{userInfo.nickName}}</text> </view> </view> </template> <script> export default { data() { return { userInfo: {}, hasUserInfo: false } }, methods: { login() { uni.login({ success: res => { if (res.code) { // 将code发送到后端服务器 uni.request({ url: 'https://example.com/login', data: { code: res.code }, success: res => { // 将openid和session_key存储到本地storage uni.setStorageSync('openid', res.data.openid) uni.setStorageSync('session_key', res.data.session_key) } }) } else { console.log('登录失败:' + res.errMsg) } } }) }, getUserInfo() { uni.getUserInfo({ success: res => { this.userInfo = res.userInfo this.hasUserInfo = true // 将用户信息发送到后端服务器 uni.request({ url: 'https://example.com/userInfo', data: { openid: uni.getStorageSync('openid'), userInfo: res.userInfo } }) } }) } } } </script> <style> .container { display: flex; justify-content: center; align-items: center; height: 100vh; } .userinfo { display: flex; flex-direction: column; align-items: center; } </style> ``` 在上面的代码中,当用户点击“微信登录”按钮时,会调用login()方法进行微信登录,并将获取到的openid和session_key存储到本地storage中。当用户点击“获取用户信息”按钮时,会调用getUserInfo()方法获取用户信息,并将用户信息发送到后端服务器。在页面上,会根据hasUserInfo变量的值来决定是否展示用户信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SunnyRun!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

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

抵扣说明:

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

余额充值