123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- <template>
- <view class="wk-select-list list">
- <view
- v-for="item in optionsList"
- :key="item.index"
- :class="{active: item.checked}"
- class="list-item"
- @click="handleSelected(item.index)">
- <view class="list-item_icon">
- <image :src="$static('images/icon/check.png')" class="checked-icon" />
- </view>
- <view v-if="hasSlot" class="list-item_label">
- <slot :scope-data="item.data" />
- </view>
- <text v-else class="list-item_label">
- {{ item.data[labelField] }}
- </text>
- </view>
- </view>
- </template>
- <script>
- /**
- * 选项选择
- * @property {Array<Object>} list 选项列表
- * @property {Array} defaultVal 默认勾选的项
- * @property {String} labelField 选项中展示的字段
- * @property {String} valueField 选项值字段
- * @property {Number} max 最大能选择几项,默认正无穷
- * @property {Number} min 至少选择几项,默认0
- * @event {Function} change 勾选项发生变化
- * @slots 自定义选项样式
- */
- import { isObject } from '@/utils/types.js'
- export default {
- name: 'WkSelectList',
- props: {
- value: {
- type: Array,
- default: () => []
- },
- list: {
- type: Array,
- required: true
- },
- labelField: {
- type: String,
- default: 'label'
- },
- valueField: {
- type: String,
- default: 'value'
- },
- max: {
- type: Number,
- default: 1 / 0
- },
- min: {
- type: Number,
- default: 0
- }
- },
- data() {
- return {
- maxlength: 0,
- optionsList: [], // 选项数组
- lastIndex: null // 记录最后一次选中的是第几项
- }
- },
- computed: {
- hasSlot() {
- return this.$scopedSlots.default
- }
- },
- watch: {
- list: {
- handler(val) {
- this.optionsList = this.list.map((item, index) => {
- return {
- data: item,
- checked: false,
- index: index
- }
- })
- // console.log('stht,', this)
- this.getCheckedList()
- },
- immediate: true,
- deep: true
- },
- value: {
- handler() {
- this.getCheckedList()
- },
- deep: true
- },
- max: {
- handler(val) {
- if (this.$isEmpty(val) || val === 0) {
- this.maxlength = 1 / 0
- } else {
- this.maxlength = val
- }
- },
- immediate: true,
- deep: true
- }
- },
- methods: {
- /**
- * 勾选默认选中的项
- */
- getCheckedList() {
- const that = this
- this.optionsList.forEach((item, index) => {
- const findIndex = this.value.findIndex(val => {
- if (isObject(val)) {
- return item.data[that.valueField] === val[that.valueField]
- } else {
- return item.data[that.valueField] === val
- }
- })
- if (findIndex !== -1) {
- if (that.lastIndex === null) {
- that.lastIndex = index
- }
- item.checked = true
- } else {
- item.checked = false
- }
- that.$set(item, 'checked', item.checked)
- })
- },
- /**
- * 选中
- * @param {Number} index
- */
- handleSelected(index) {
- const item = this.optionsList[index]
- item.checked = !item.checked
- // 判断已经选择的项是否超出最大选择数量,如果超出则把最后一次选中项的置为未选中
- const checkedLen = this.optionsList.filter(o => o.checked).length
- if (
- index !== this.lastIndex &&
- this.lastIndex !== null &&
- (checkedLen > this.maxlength)
- ) {
- const lastItem = this.optionsList[this.lastIndex]
- lastItem.checked = false
- this.$set(this.optionsList, this.lastIndex, lastItem)
- }
- if (item.checked) {
- this.lastIndex = index
- }
- this.$set(this.optionsList, index, item)
- this.emitSelected()
- },
- emitSelected() {
- const filterRes = this.optionsList.filter(o => o.checked)
- console.log('filterRes: ', filterRes)
- const res = filterRes.map(o => o.data)
- this.$emit('input', res)
- this.$emit('change', res)
- }
- }
- }
- </script>
- <style scoped lang="scss">
- .wk-select-list {
- .list-item {
- padding: 0 30rpx;
- background-color: white;
- @include left;
- .list-item_icon {
- width: 38rpx;
- height: 38rpx;
- border: 1rpx solid #ccc;
- border-radius: 50%;
- margin-right: 22rpx;
- @include center;
- .checked-icon {
- width: 23rpx;
- height: 23rpx;
- }
- }
- .list-item_label {
- flex: 1;
- font-size: 30rpx;
- color: $dark;
- border-bottom: 1rpx solid $border-color;
- padding: 24rpx 0;
- }
- &.active {
- .list-item_icon {
- background-color: $theme-color;
- border-color: $theme-color;
- }
- }
- }
- }
- </style>
|