首页 > 其他分享 >uniapp+uView纯js手写加搜索的多选框

uniapp+uView纯js手写加搜索的多选框

时间:2024-08-23 13:54:07浏览次数:10  
标签:uniapp color res uView plateID js item num font

父组件代码:

<template>

    <view>

        <view v-for="(item,index) in stockList" :key="index">

            <view class="s-title">{{item.typeName}}</view>

            <view class="s-list">

                <view :class="['s-item', i.isClick?'s-item-active':'']" v-for="(i,idx) in item.childNode" :key="idx" @click="itemClick(i)">

                    {{i.name}}{{item.isClick}}

                    <view class="s-item-close" v-if="i.isClick" @click.stop="cancelSelect(i)">

                        <image src="/static/images/close.png" mode=""></image>

                    </view>

                </view>

            </view>

        </view>

        <view style="height: 150rpx;"></view>

        <view class="footer-bar">

            <view class="b-left">已选择<text>{{total}}</text>个条件</view>

            <view :class="['b-right',total == 0 ?'b-right-active':'']">执行选股</view>

        </view>

        <!-- 弹框组件 -->

        <view>

            <u-popup :show="popupShow" mode="bottom" :round="10" @close="closePopup" class="popup">

                <selection-range ref="selectionRange" :select-item="selectItem" :crArr="crArr" :checkedList="checkedList" :marketCheckedList="marketCheckedList" @cancelPopup="closePopup" @getSelectValue="getSelectValue">

                </selection-range>

            </u-popup>

        </view>

    </view>

</template>

<script>

    import selectionRange from './selection-range.vue'

    import {

        querySelectStockList

    } from '@/api/selectStock.js' // 后端接口

    import {

        signalrsOn,

        signalrInvoke

    } from "@/util/signalR.js"; // 获取订阅接口

    export default {

        components: {

            selectionRange

        },

        data() {

            return {

                stockList: [],

                popupShow: false,

                selectItem: {},

                symbolArr: [], // 市场订阅所需参数数组

                crArr: [], // 涨跌幅

                checkedList: [], //行业选中值

                marketCheckedList: [], // 市场选中值

                total:0, // 选中条件个数

            };

        },

        onShow() {

            this.total = 0

            this.marketCheckedList = []

            this.checkedList= []

            this.getSelectStockList() // 获取按钮列表

        },

        methods: {

            // 按钮点击事件

            itemClick(item) {

                this.popupShow = true

                this.selectItem = item

                if (item.plateTreeID == 10) {

                    this.symbolArr = []

                    if (item.plateId != 1001) {

                        item.childNode.forEach(res => {

                            this.symbolArr.push(res.code)

                        })

                        signalrInvoke("Quotation", "Subscribe", { // 订阅行情

                            QuotationType: "PlateIndexQuotationInfo",

                            SearchParamData: {

                                Symbols: this.symbolArr.join(','),

                            },

                        });

                        this.crArr = []

                        signalrsOn('SubscribeReturn', (res) => { // 接收行情数据

                            let obj = {

                                cr: res.data.cr,

                                plateId: res.data.plateid

                            }

                            this.crArr.push(obj)

                        })

                    }

                }

            },

            // 获取选股列表

            getSelectStockList() {

                querySelectStockList().then(res => {

                    if (res.isSuccess == true) {

                        this.stockList = res.resultData

                    }

                })

            },

            // 获取行业与市场选中值

            getSelectValue(value) {

                if(value == 2) {

                    //不用执行

                } else if(value.length > 0) {

                    if (this.selectItem.plateID != 1001) {

                        this.checkedList = value

                    } else {

                        this.marketCheckedList = value

                    }

                    this.popupShow = false

                } else {

                    this.popupShow = true

                }

                // 计算总数

                this.total = 0

                this.stockList.forEach(item=>{

                    item.childNode.forEach(i=>{

                        if(i.isClick) {

                            this.total++

                        }

                    })

                })

            },

            // 关闭弹框

            closePopup() {

                this.popupShow = false

            },

            // 点击按钮取消选中

            cancelSelect(item) {

                item.isClick = false

                this.getSelectValue(2)//计算数量

                if(item.typeCode == 4) {

                    item.childNode.forEach(item =>{

                        item.isChecked = false

                    })

                } else if(item.typeCode == 3) {

                    item.selectMinValue = 0

                    item.selectMaxValue = 0

                } else if(item.typeCode == 7) {

                    this.marketCheckedList = [] // 市场选中值

                } else if(item.typeCode == 8) {

                    this.checkedList= [] //行业选中值

                }

                this.$forceUpdate() // 更新

            }

        }

    }

</script>

<style lang="less">

    page {

        padding-left: 30rpx;

        line-height: 1;

    }

    .s-title {

        font-size: 30rpx;

        font-weight: bold;

        color: #333333;

        margin-top: 44rpx;

    }

    .s-list {

        display: flex;

        flex-wrap: wrap;

        margin-top: 6rpx;

        .s-item {

            position: relative;

            display: flex;

            align-items: center;

            justify-content: center;

            font-size: 24rpx;

            color: #333333;

            width: 216rpx;

            height: 78rpx;

            background: #EEEEEE;

            border-radius: 4rpx;

            margin: 24rpx 22rpx 0 0;

            padding: 10rpx;

            .s-item-close {

                position: absolute;

                right: 0;

                top: 0;

                width: 32rpx;

                height: 26rpx;

                background: #2F569E;

                border-radius: 0 0 0 10rpx;

                display: flex;

                align-items: center;

                justify-content: center;

                image {

                    width: 16rpx;

                    height: 16rpx;

                }

            }

        }

        .s-item-active {

            background: rgba(47, 86, 158, 0.16);

            border: 1rpx solid #2F569E;

        }

    }

    .footer-bar {

        display: flex;

        position: fixed;

        bottom: 0;

        left: 0;

        width: 750rpx;

        height: 102rpx;

        padding-bottom: constant(safe-area-inset-bottom);

        padding-bottom: env(safe-area-inset-bottom);

        box-sizing: content-box;

        background-color: #ffffff;

        .b-left {

            width: 420rpx;

            display: flex;

            align-items: center;

            justify-content: center;

            font-size: 30rpx;

            color: #333333;

            background-color: #ffffff;

            text {

                color: #FF2536;

            }

        }

        .b-right {

            display: flex;

            align-items: center;

            justify-content: center;

            width: 330rpx;

            background: #2F569E;

            font-size: 36rpx;

            color: #FFFFFF;

        }

        .b-right-active {

            opacity: .5;

        }

    }

    /deep/ .u-popup__content {

        border-radius: 10rpx 10rpx 0px 0px;

        background-color: #FBFAFA;

    }

</style>

子组件selectionRange代码:

<template>

  <view class="rangeBox" ref="selection">

    <view class="titleBox">

      <text class="title">{{ selectItem.name }}</text>

      <text class="title1">(可多选)</text>

    </view>

    <view class="secondTitle">

      {{ selectItem.desc }}

    </view>

    <!-- 市场板块 -->

    <view v-if="selectItem.plateID == 1001">

      <view class="checkList">

        <view

          v-for="(i, dex) in marketValueList"

          :key="dex"

          :class="i.isChecked ? 'active' : 'checkItem'"

          @click="selectMarket(i)"

        >

          {{ i.name }}

        </view>

      </view>

    </view>

    <!-- 行业板块 -->

    <view v-else>

      <view class="selectBox">

        <text class="title">已选</text>

        <text class="title1">({{ checkboxValue.length }})</text>

      </view>

      <!-- 搜索框 -->

      <u--input

        placeholder="搜索"

        border="surround"

        prefixIcon="search"

        prefixIconStyle="font-size: 50rpx;color: #a8a9a9"

        v-model="keyword"

        clearable

        @change="searchContent"

        class="search"

      ></u--input>

      <!-- 多选框 -->

      <scroll-view

        scroll-y="true"

        scroll-x="false"

        class="cateCheckbox"

        v-if="checkboxListCopy && checkboxListCopy.length > 0"

      >

        <view

          class="checkBox"

          v-for="(item, index) in checkboxListCopy"

          :key="index"

        >

          <view class="leftBox" @click="checkboxChange(item)">

            <view

              class="circle"

              :style="

                item.isCheck

                  ? { 'background-color': '#FF0000', 'border-color': '#FF0000' }

                  : {}

              "

            >

              <i class="iconfont icon-gouxuan1" v-if="item.isCheck"></i>

            </view>

            <view class="text">{{ item.name }}</view>

          </view>

          <text

            class="rightBox"

            :style="{

              color:

                toRatio(item.cr) > 0

                  ? colorStyle[1]

                  : toRatio(item.cr) == 0

                  ? colorStyle[0]

                  : colorStyle[2],

            }"

            >{{ item.cr > 0 ? "+" : ""

            }}{{

              toRatio(item.cr == null || item.cr == 0 ? 0.0 : item.cr)

            }}%</text

          >

        </view>

      </scroll-view>

      <view v-else class="noData">暂无数据</view>

    </view>

    <view class="btnOptions">

      <view class="leftBtn btn" @click="cancelPopup(selectItem.plateID)">

        取消

      </view>

      <view

        class="btn rightBtn"

        @click="comfirmSelect(selectItem.plateID)"

        :class="checkboxValue.length > 0 ? 'checkedBtn' : 'unCheckedBtn'"

      >

        确定

      </view>

    </view>

  </view>

</template>

<script>

import { toDecimal } from "@/common/numberFormat.js";

import { signalrInvoke } from "@/util/signalR.js"; // 行情订阅接口

export default {

  props: {

    selectItem: {

      type: Object,

      default: {},

    },

    crArr: {

      type: Array,

      default: [],

    },

    checkedList: {

      type: Array,

      default: [],

    },

    marketCheckedList: {

      type: Array,

      default: [],

    },

  },

  data() {

    return {

      timer: null,

      selectNum: 0,

      keyword: "", // 搜索值

      checkboxValue:

        this.checkedList.length > 0 ? [].concat(this.checkedList) : [], // 行业选中的值

      checkboxList: [], //行业列表

      checkboxListCopy: [], // 页面搜索备份行业列表

      marketValueList: [], // 市场列表

      marketCheckedValue:

        this.marketCheckedList.length > 0

          ? [].concat(this.marketCheckedList)

          : [], // 市场选中列表

      colorStyle: ["#666666", "#FF0000", "#069c42"],

    };

  },

  created() {

    this.getCheckboxData();

  },

  watch: {

    keyword(newVal, oldVal) {

      if (oldVal !== newVal) {

        this.searchContent(newVal);

      }

    },

  },

  methods: {

    // 多选框列表

    getCheckboxData() {

      this.marketValueList = [];

      this.checkboxList = [];

      clearTimeout(this.timer);

      uni.showLoading();

      this.timer = setTimeout(() => {

        if (this.selectItem.plateID != 1001) { // 行业列表

          this.crArr.forEach((i) => {

            this.selectItem.childNode.forEach((res) => {

              if (i.plateId == res.plateID) {

                let obj = {

                  code: res.code,

                  name: res.name,

                  plateID: res.plateID,

                  plateTreeID: res.plateTreeID,

                  typeCode: res.typeCode,

                  cr: i.cr,

                  isCheck: this.checkboxValue.some( // 设置选中项

                    (item) => item.id == res.plateID

                  )

                    ? true

                    : false,

                };

                uni.hideLoading();

                this.checkboxList.push(obj);

                this.checkboxListCopy = this.checkboxList;

              }

            });

          });

        } else { // 市场列表

          this.selectItem.childNode.forEach((res1) => {

            let obj = {

              name: res1.name,

              plateID: res1.plateID,

              plateTreeID: res1.plateTreeID,

              typeCode: res1.typeCode,

              isChecked: this.marketCheckedValue.some( // 设置选中项

                (item) => item.id == res1.plateID

              )

                ? true

                : false,

            };

            this.marketValueList.push(obj);

            uni.hideLoading();

          });

        }

      }, 400);

    },

    // 多选项选中与非选中改变

    checkboxChange(item) {

      item.isCheck = !item.isCheck;

      if (this.checkboxValue.some((res) => res.id == item.plateID)) { // 取消选中(这里是对象obj格式)

        this.checkboxValue = this.checkboxValue.filter((item1) => {

          return item1.id != item.plateID;

        });

      } else { // 选中

        let obj = {

          id: item.plateID,

          name: item.name,

        };

        this.checkboxValue.push(obj);

      }

    },

    // 选择市场

    selectMarket(item) {

      item.isChecked = !item.isChecked;

      if (this.marketCheckedValue.some((res) => res.id == item.plateID)) {

        this.marketCheckedValue = this.marketCheckedValue.filter((item1) => {

          return item1.id != item.plateID;

        });

      } else {

        let obj = {

          id: item.plateID,

          name: item.name,

        };

        this.marketCheckedValue.push(obj);

      }

    },

    // 点击取消关闭弹框

    cancelPopup(plateID) {

      if (uni.hideLoading()) {

        if (plateID != 1001) {

          this.keyword = "";

          this.checkboxValue = this.checkboxValue.length > 0 ? this.checkboxValue : [];

          this.selectNum = this.checkboxValue.length > 0 ? this.checkboxValue.length : 0;

        } else {

          this.marketCheckedValue = this.marketCheckedValue > 0 ? this.marketCheckedValue : [];

        }

        this.$emit("cancelPopup"); // 关闭弹框

        signalrInvoke("Quotation", "UnSubscribe", {

          // 取消订阅行情

          QuotationType: "PlateIndexQuotationInfo",

        });

      }

    },

    // 搜索

    searchContent(value) {

      if (value.trim() != "") {

        this.checkboxListCopy = this.fuzzyQuery(

          this.checkboxList,

          value.trim()

        );

      } else {

        this.checkboxListCopy = this.checkboxList;

      }

    },

    // 确定选择条件

    comfirmSelect(plateID) {

      this.selectItem.isClick = true;

      if (plateID != 1001) {

        this.$emit("getSelectValue", this.checkboxValue);

      } else {

        this.$emit("getSelectValue", this.marketCheckedValue);

      }

    },

    // 输入框搜索

    fuzzyQuery(list, keyWord) {

      let arr = [];

      for (let i = 0; i < list.length; i++) {

        if (list[i].name.indexOf(keyWord) >= 0) {

          arr.push(list[i]);

        }

      }

      return arr;

    },

    // 数字格式化

    toDecimal(num, digit = 2, isRround = true) {

      if (num == null || num == undefined) {

        return "";

      }

      return toDecimal(num, digit, isRround);

    },

    // 涨跌幅小数转百分比(乘以100)

    numMul(arg1, arg2) {

      var r1 = arg1 + "";

      var r2 = arg2 + "";

      var r3 = 0;

      var r4 = 0;

      try {

        r3 = r1.split(".")[1].length;

      } catch (err) {

        r3 = 0;

      }

      try {

        r4 = r2.split(".")[1].length;

      } catch (err) {

        r4 = 0;

      }

      return (

        (Number(r1.replace(".", "")) * Number(r2.replace(".", ""))) /

        Math.pow(10, r4 + r3)

      );

    },

    // 数值保留2位小数

    toRatio(num, digit = 2) {

      if (num == null) {

        return 0.0;

      }

      return this.toDecimal(this.numMul(num, 100), digit);

    },

  },

};

</script>

<style lang="scss" scoped>

.rangeBox {

  width: 100%;

  padding: 0 30rpx;

  .titleBox {

    margin: 48rpx 0 30rpx 0;

    .title {

      font-size: 36rpx;

      font-family: Noto Sans S Chinese;

      font-weight: bold;

      color: #333333;

    }

    .title1 {

      font-size: 24rpx;

      font-family: Noto Sans S Chinese;

      color: #ff0000;

    }

  }

  .secondTitle {

    font-size: 30rpx;

    font-family: Noto Sans S Chinese;

    font-weight: normal;

    color: #6a6a6a;

    margin-bottom: 57rpx;

  }

  .checkList {

    display: flex;

    flex-wrap: wrap;

    justify-content: space-between;

    margin-bottom: 216rpx;

    .checkItem {

      width: 216rpx;

      height: 77rpx;

      background: #eeeeee;

      border-radius: 3rpx;

      display: flex;

      align-items: center;

      justify-content: center;

      font-size: 24rpx;

      font-family: Noto Sans S Chinese;

      font-weight: 400;

      color: #333333;

      margin-bottom: 24rpx;

    }

    .active {

      background-color: #dee4ef;

      border: 2rpx solid #2f569e;

      color: #2f569e;

      width: 216rpx;

      height: 77rpx;

      border-radius: 3rpx;

      display: flex;

      align-items: center;

      justify-content: center;

      font-size: 24rpx;

      font-family: Noto Sans S Chinese;

      font-weight: 400;

      margin-bottom: 24rpx;

    }

  }

  .selectBox {

    margin-bottom: 30rpx;

    .title {

      font-size: 30rpx;

      font-family: Noto Sans S Chinese;

      font-weight: 500;

      color: #333333;

    }

    .title1 {

      font-size: 30rpx;

      font-family: Noto Sans S Chinese;

      color: #ff0000;

    }

  }

  .search {

    height: 70rpx !important;

    margin-bottom: 60rpx;

    background-color: #eeeeee;

    border-radius: 10rpx;

  }

  .cateCheckbox {

    height: 430rpx;

    overflow-y: scroll;

    margin-bottom: 56rpx;

    .checkBox {

      display: flex;

      justify-content: space-between;

      align-items: center;

      margin-bottom: 50rpx;

      .leftBox {

        display: flex;

        .circle {

          width: 42rpx;

          height: 42rpx;

          border-radius: 50%;

          border: 2rpx solid #bfbfbf;

          display: flex;

          justify-content: center;

          align-items: center;

          .icon-gouxuan1 {

            font-size: 42rpx;

            color: #fff;

          }

        }

        .text {

          font-size: 30rpx;

          font-family: Noto Sans S Chinese;

          font-weight: 400;

          color: #333333;

          margin-left: 18rpx;

        }

      }

      .rightBox {

        font-size: 30rpx !important;

        font-family: Noto Sans S Chinese;

        font-weight: 400;

      }

    }

  }

  .noData {

    height: 200rpx;

    width: 307rpx;

    margin: 120rpx auto;

    padding-top: 220rpx;

    text-align: center;

    font-size: 30rpx;

    color: #939aaa;

    background: url(@/static/images/noData.png) center 10rpx no-repeat;

    background-size: contain;

  }

  .btnOptions {

    margin-bottom: 30rpx;

    display: flex;

    justify-content: space-between;

    .btn {

      display: flex;

      align-items: center;

      justify-content: center;

      border-radius: 10rpx;

      font-size: 30rpx;

      font-family: Noto Sans S Chinese;

      font-weight: 400;

    }

    .leftBtn {

      width: 202rpx;

      height: 88rpx;

      background: #eeeeee;

      color: #333333;

    }

    .rightBtn {

      width: 377rpx;

      height: 88rpx;

    }

    .checkedBtn {

      background: #2f569e;

      color: #ffffff;

    }

    .unCheckedBtn {

      background: #eeeeee;

      color: #333333;

    }

  }

}

</style>

numberFormat.js文件代码:

/**

 * [toDecimal 转化数字为几位小数,四舍五入或者截取多于位数]

 * @param  {[Number]} num         [需转化的数字]

 * @param  {Number} [digit=2]   [需保留或截取的位数]

 * @param  {Boolean} [isRround=true]            [true四舍五入,false截取多于小数]

 * @return {[Number, String]}             [转换后的结果]

 */

export function toDecimal(num,  digit = 2, isRround = true) {

  if (num === null || num === undefined) {

      return ''

  }

  // 负数处理四舍五入,先转成正数

  let sign = ''

  if (num < 0) {

      sign = '-'

  }

  num = Math.abs(num).toString()

  // 出现了科学计数法

  if (num.indexOf('e-') != -1) {

      num = noKeXueJiShuFa(num)

  }

  const numArr = num.split('.')

  if (numArr.length > 1) {

  // 有小数时的处理

      if (numArr[1].length <= digit) {

          // 小数位数少于需保留位数的时候

          return sign + Number(num).toFixed(digit)

      } else {

          // 小数位数多于需保留位数的时候

          if (isRround) {

              // 四舍五入处理

              num = numArr[1][digit] >= 5 ? parseInt(noKeXueJiShuFa(num * Math.pow(10, digit))) + 1 : parseInt(noKeXueJiShuFa(num * Math.pow(10, digit)))

              return sign + (num / Math.pow(10, digit)).toFixed(digit)

          } else {

              // 去除多于小数

              return sign + `${numArr[0]}.${numArr[1].substring(0, digit)}`

          }

      }

  } else {

  // 无小数时的处理

      return sign + Number(num).toFixed(digit)

  }

}

function noKeXueJiShuFa(num) {

  if (String(num).indexOf('e-') != -1) {

      num = '0' + String(Number(num) + 1).substr(1)

  }

  return num

}

用到的图片:

标签:uniapp,color,res,uView,plateID,js,item,num,font
From: https://blog.csdn.net/Mirs_Zhu/article/details/141464111

相关文章

  • js 实现代码雨效果
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>Document</title&g......
  • js逆向学习
    目前本人大三下,想要学习js逆向同学的可以联系我:[email protected]上面是本人做的一些比较复杂的项目,还有很多简单的项目,这里给出图片。还有一些简单的js逆向。教你各种补充环境,各种js算法,教你各种底层的js库,webpack打包,bable的es6转es6原理,异步转同步代码之后如何代码定......
  • python 05-标准库:csv、json、sqlite3、datetime模块
    csv模块importcsv#data.csv不存在时,会现在当前目录下创建一个data.csv文件withopen("data.csv","w",encoding='utf-8')asfile:writer=csv.writer(file)writer.writerow(["trasanction_id","product_id","pric......
  • Javaweb+jsp外卖点餐系统+源码(三)
    第三章详细设计3.1 用户的主界面用户的主菜单界面。页面如图3-1所示:图3-1 用户的主界面3.2用户注册页面用户在首次登录外卖订餐系统管理页面时,需要在注册页面需要完成个人信息的注册。页面如图3-2所示:图3-2外卖订餐系统的注册页面3.3用户登录界面用户通......
  • typescript: deserialize json to object
     /**_oo0oo_*o8888888o*88"."88*(|-_-|)*0\=/0*___/`---'\___*......
  • 看了几十篇论文,实现了个专业算法,用threejs做了个三维人员定位系统示例(已开源)
    需求“threejs中能不能给定几组三维坐标(或者CAD绘制的三维多段线),给一个断面形状,直接生成三维管道?”例如原始CAD图如下:要求用threejs获取线的三维坐标数据自动生成的三维管道效果图如下: 分析如果直接对每条线用threejs中的THREE.TubeGeometry去绘制的话,会出现交岔口出......
  • 基于nodejs+vue在线学习行为的学生课程预警研究与实现[程序+论文+开题]-计算机毕业设
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展,在线教育已成为教育领域不可或缺的一部分,它打破了传统教育的时空限制,为广大学生提供了更加灵活多样的学习途径。然而,在线学习环境的......
  • 基于nodejs+vue血库管理系统[程序+论文+开题]-计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码毕设程序文件开题报告内容研究背景在医疗体系中,血液作为拯救生命的重要资源,其管理与调配的高效性直接关系到患者救治的成功率与生命安全。随着医疗技术的不断进步和临床需求的日益增长,传统的人工......
  • [学习笔记]在不同项目中切换Node.js版本
    @目录使用NodeVersionManager(NVM)安装NVM使用NVM安装和切换Node.js版本为项目指定Node.js版本使用环境变量指定Node.js安装多个版本的Node.js设置环境变量验证配置使用npm脚本切换在开发中,可能会遇到不同的Vue项目需要不同的Node.js,在开发机上如何快速切换Node的......
  • xlsx-js-style前端组装表格数据下载到本地
    1.数据格式:对象:key/valueconstdata1={'合同主体信息':'{\n"合同编号":"FWTsAEY-S1T-2023-01",\n"项目编号":"FTCG2023000265A",\n"项目名称":"福田区第二人民医院食堂服务采购项直",\n"总计/价款&q......