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

父组件代码:

<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

}

用到的图片:

  • 19
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值