123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- <template>
- <view class="relative">
- <view class="tm-dropDownMenu absolute fulled" :style="{zIndex:101}">
- <view
- class="tm-dropDownMenu-bar"
- :class="[
- !black_tmeme && bgColor != 'white' ? bgColor : black_tmeme && bgColor == 'white' ? 'grey-darken-4' : bgColor,
- black_tmeme ? '' : 'shadow-' + bgColor + '-' + shadow,
- black_tmeme ? 'bk' : ''
- ]"
- >
- <tm-row align="center" justify="center">
- <tm-col color="none" justify="center" align="middle" @click="changeIndex(index)" v-for="(item, index) in formartData" :key="index" :width="itemLength + '%'">
- <view class="flex-center" :style="{height: height+'rpx',lineHeight:height+'rpx'}">
- <text class=" pr-10" :style="{fontSize:fontSize+'rpx'}" :class="[activeIndex == index ? 'text-' + activeColor : 'text-' + unColor]">{{ item.title }}</text>
- <tm-icons
- v-if="index!=0"
- style="line-height: 0;"
- dense
- :color="item.shang ? activeColor : unColor"
- size="24"
- :name="item.shang ? 'icon-sort-up' : 'icon-sort-down'"
- ></tm-icons>
- </view>
- </tm-col>
- </tm-row>
- </view>
- <view v-if="formartData[activeIndex]" class="tm-dropDownMenu-body py-24 " :class="[black_tmeme ? 'grey-darken-5 bk' : 'white', 'shadow-' + shadow]">
- <view v-if="formartData[activeIndex]['children']" :style="{maxHeight:maxHeight+'rpx',overflowY: 'auto'}">
- <block v-for="(item, index) in formartData[activeIndex].children" :key="index">
- <block v-if="item['children']&&rendIdx>=index" >
- <view class="pa-24 text-size-s text-weight-b optAniopt" v-if="item['title']">{{ item.title }}</view>
- <view class="optAniopt">
- <block v-if="item.model == 'checkbox'">
- <tm-groupcheckbox>
- <block v-for="(item2, index2) in item.children" :key="index2">
- <tm-checkbox :disabled="item2['disabled'] || item['disabled'] ? true : false" dense v-model="item2.checked">
- <view class="px-10" :class="[item2['disabled'] || item['disabled'] ? 'opacity-6' : '']">
- <tm-button
- :fllowTheme="false"
- :black="black_tmeme"
- :theme="item2.checked ? color: (black_tmeme?'grey-darken-3':'grey-lighten-2')"
- :font-color="item2.checked ? color : 'grey'"
- dense
- style="width: auto"
- font-size="24"
- height="70"
- item-class="mx-14 my-10"
- plan
- block
- icon="icon-check-circle"
- :shadow="2"
- :height="64"
- :round="2"
- >
- {{ item2.title }}
- </tm-button>
- </view>
- </tm-checkbox>
- </block>
- </tm-groupcheckbox>
- </block>
- <block v-if="item.model == 'radio'">
- <tm-groupradio>
- <block v-for="(item2, index2) in item.children" :key="index2">
- <tm-radio :disabled="item2['disabled'] || item['disabled'] ? true : false" dense v-model="item2.checked">
- <view class="px-10" :class="[item2['disabled'] || item['disabled'] ? 'opacity-6' : '']">
- <tm-button
- :fllowTheme="false"
- :black="black_tmeme"
- :theme="item2.checked ? color: (black_tmeme?'grey-darken-3':'grey-lighten-2')"
- :font-color="item2.checked ? color : 'grey'"
- dense
- style="width: auto"
- font-size="24"
- height="70"
- item-class="mx-14 my-10"
- plan
- block
- icon="icon-check-circle"
- :shadow="2"
- :height="64"
- :round="2"
- >
- {{ item2.title }}
- </tm-button>
- </view>
- </tm-radio>
- </block>
- </tm-groupradio>
- </block>
- <block v-if="item.model == 'list'">
- <tm-groupradio key="test">
- <block v-for="(item2, index2) in item.children" :key="index2">
- <tm-radio :inline="false" :disabled="item2['disabled'] || item['disabled'] ? true : false" dense v-model="item2.checked">
- <view class="fulled">
-
- <tm-listitem
- :disabled="item2['disabled'] || item['disabled'] ? true : false"
- :title-color="item2.checked ? color : 'grey-darken-3'"
- :rightIconColor="item2.checked ? color : 'grey-lighten-3'"
- :margin="[24, 12]"
- :title="item2.title"
- fontSize="28"
- :shadow="0"
- :borderBottom="true"
- :rightIconSize='30'
- :rightIcon="item2.checked ? 'icon-check-circle' : ''"
- ></tm-listitem>
- </view>
- </tm-radio>
- </block>
- </tm-groupradio>
- </block>
-
- <block v-if="item.model == 'listCheckbox'">
- <tm-groupcheckbox >
- <block v-for="(item2, index2) in item.children" :key="index2">
- <tm-checkbox :inline="false" :disabled="item2['disabled'] || item['disabled'] ? true : false" dense v-model="item2.checked">
- <view class="fulled">
-
- <tm-listitem
- :disabled="item2['disabled'] || item['disabled'] ? true : false"
- :title-color="item2.checked ? color : 'grey-darken-3'"
- :rightIconColor="item2.checked ? color : 'grey-lighten-3'"
- :margin="[24, 12]"
- :title="item2.title"
- fontSize="28"
- :shadow="0"
- :borderBottom="true"
- :rightIconSize='30'
- :rightIcon="item2.checked ? 'icon-check-circle' : ''"
- ></tm-listitem>
- </view>
- </tm-checkbox>
- </block>
- </tm-groupcheckbox>
- </block>
-
-
- </view>
- </block>
- <block v-else>
- <block v-if="item.model == 'input'&&rendIdx>=index" >
- <view class="pa-24 text-size-s text-weight-b optAniopt" v-if="item['title']">{{ item.title }}</view>
- <tm-input
- :fllowTheme="fllowTheme"
- border-color="grey-lighten-1"
- :disabled="chiludis(item)"
- :black="black_tmeme"
- :color="color"
- :border-bottom="false"
- :input-type="item.type || 'text'"
- :value.sync="item.value"
- ></tm-input>
- </block>
- <block v-if="item.model == 'slider'&&rendIdx>=index" >
- <view class="pa-24 text-size-s text-weight-b optAniopt" v-if="item['title']">
- {{ item.title }}
- <text class="px-24 " :class="[`text-${color}`]">
- {{ item.value ? item.value : '未设置' }}{{ item.value ? (item['suffix'] ? item.suffix : '') : '' }}
- </text>
- </view>
- <view class="px-42 py-24 optAniopt">
- <tm-slider
- :fllowTheme="fllowTheme"
- :disabled="chiludis(item)"
- :black="black_tmeme"
- :color="color"
- :max="item.max ? item.max : 100"
- v-model="item.value"
- >
- <template v-slot:tips>
- {{ item.value }}
- </template>
- </tm-slider>
- </view>
- </block>
- <block v-if="item.model == 'pickers'&&rendIdx>=index" >
- <view class="pa-24 text-size-s text-weight-b optAniopt" v-if="item['title']">
- {{ item.title }}
- </view>
- <view class="optAniopt">
- <tm-pickers
- :default-value.sync="item.value"
- rang-key="title"
- :btn-color="color"
- :list="item.data"
- >
- <tm-input :value="pickTostring(item.value)" prefixp-icon="icon-calendaralt-fill" disabled :placeholder="item['placeholder']?item['placeholder']:'请选择'" suffix-icon="icon-sort-down"></tm-input>
- </tm-pickers>
- </view>
- </block>
- </block>
- </block>
- </view>
- <view class="flex-between px-32 pt-32">
- <tm-button :fllowTheme="fllowTheme" @click="getData" :theme="color" block style="width: 48%;" height="80">确认</tm-button>
- <tm-button
- :fllowTheme="fllowTheme"
- @click="resetinit"
- :black="black_tmeme"
- block
- :theme="color"
- :font-color="color"
- text
- shadow="0"
- style="width: 48%;"
- height="80"
- >
- 重置
- </tm-button>
- </view>
- </view>
- </view>
- <view @click="activeIndex=-1" v-if="activeIndex>-1" class="fixed fulled" :style="{height:height_bg+'px',top:vtop+'px',width:barwidth,background:'rgba(0,0,0,0.33)',zIndex:100}">
-
- </view>
- </view>
- </template>
- <script>
- /**
- * 下拉选项
- * @property {String} color = [] 默认:primary ,主题色下方选项子组件的主题色。
- * @property {String} un-color = [] 默认:black ,默认未激活时。bar条上的文字颜色
- * @property {String} active-color = [] 默认:primary ,默认激活时。bar条上的文字颜色
- * @property {String} bg-color = [] 默认:white ,导航条背景主题色。
- * @property {Number} shadow = [] 默认:10 ,导航条的投影。
- * @property {Array} list = [] 默认:[] ,数据格式见文档
- * @property {Number} maxHeight = [] 默认:650 ,弹出的标签页,最大内容高度,超过自动滚动。
- * @property {Number} height = [] 默认:88 ,标签导航的高度
- * @property {Number} font-size = [] 默认:28 ,标签导航的文字大小
- * @property {Array} default-selected = [] 默认:[] ,默认赋值选中的选项,注意可以是id数组或者对象数组,对象数组情况下必须含id标签符,且是唯一的。
- * @property {Boolean} black = [] 默认:false ,暗黑模式。
- * @property {Function} change 切换选项页面时触发。
- * @property {Function} confirm 点击确认按钮时触发,返回所有选中的项。
- * @example <tm-dropDownMenu color="orange" :list="list"></tm-dropDownMenu>
- */
- import tmRow from '@/tm-vuetify/components/tm-row/tm-row.vue';
- import tmCol from '@/tm-vuetify/components/tm-col/tm-col.vue';
- import tmButton from '@/tm-vuetify/components/tm-button/tm-button.vue';
- import tmIcons from '@/tm-vuetify/components/tm-icons/tm-icons.vue';
- import tmInput from '@/tm-vuetify/components/tm-input/tm-input.vue';
- import tmGroupcheckbox from '@/tm-vuetify/components/tm-groupcheckbox/tm-groupcheckbox.vue';
- import tmCheckbox from '@/tm-vuetify/components/tm-checkbox/tm-checkbox.vue';
- import tmGroupradio from '@/tm-vuetify/components/tm-groupradio/tm-groupradio.vue';
- import tmRadio from '@/tm-vuetify/components/tm-radio/tm-radio.vue';
- import tmSlider from '@/tm-vuetify/components/tm-slider/tm-slider.vue';
- import tmListitem from '@/tm-vuetify/components/tm-listitem/tm-listitem.vue';
- import tmPickers from '@/tm-vuetify/components/tm-pickers/tm-pickers.vue';
- export default {
- components: {tmPickers, tmRow, tmCol, tmButton, tmIcons, tmInput, tmGroupcheckbox, tmCheckbox, tmGroupradio, tmRadio, tmSlider, tmListitem },
- name: 'tm-dropDownMenu',
- props: {
- // 主题色下方选项子组件的主题色
- color: {
- type: String,
- default: 'primary'
- },
- // 默认未激活时。bar条上的文字颜色
- unColor: {
- type: String,
- default: 'black'
- },
- // 默认激活时。bar条上的文字颜色
- activeColor: {
- type: String,
- default: 'gray'
- },
- // 背景颜色。
- bgColor: {
- type: String,
- default: 'white'
- },
- list: {
- type: Array,
- default: () => {
- return [];
- }
- },
- maxHeight:{
- type:Number|String,
- default:650
- },
- height:{
- type:Number|String,
- default:88
- },
- fontSize:{
- type:Number|String,
- default:28
- },
- //菜单的投影。
- shadow: {
- type: Number | String,
- default: 10
- },
- // 可以是id索引也可以是对象数组,可以混着来。
- defaultSelected: {
- type: Array,
- default: () => {
- return [];
- }
- },
- black: {
- type: Boolean | String,
- default: null
- },
- // 跟随主题色的改变而改变。
- fllowTheme: {
- type: Boolean | String,
- default: true
- }
- },
- computed: {
- itemLength: function() {
- if (this.list.length == 0) return 100;
- return 100 / this.list.length;
- },
- black_tmeme: function() {
- if (this.black !== null) return this.black;
- return this.$tm.vx.state().tmVuetify.black;
- }
- },
- watch:{
- list:{
- deep:true,
- handler(){
- this.$nextTick(function() {
- this.formartData = this.chulidata();
- });
- }
- }
- },
- data() {
- return {
- activeIndex: -1,
- formartData: [],
- test: [],
- height_bg:0,
- vtop:0,
- maxLeng:40,//最大渲染级别
- rendIdx:0,
- barwidth:'100%'
- };
- },
- created() {
- this.height_bg = uni.getSystemInfoSync().screenHeight;
- },
- mounted() {
- this.$nextTick(function() {
- this.formartData = this.chulidata();
- let t = this;
- uni.$tm.sleep(40).then(e=>{
- uni.createSelectorQuery().in(this).select('.tm-dropDownMenu').boundingClientRect().exec(function(v){
- // #ifdef H5
- t.vtop = v[0].top+v[0].height+uni.getSystemInfoSync().windowTop;
- // #endif
- // #ifndef H5
- t.vtop = v[0].top+v[0].height;
- console.log(v[0]);
- // #endif
- t.barwidth = v[0].width+'px'
-
- })
- })
- });
- },
- methods: {
- pickTostring(item){
- let p = [];
- item.forEach(el=>{
- if(typeof(el)=="string"){
- p.push(el)
- }else if(typeof el == 'object'){
- p.push(el.title);
- }
- })
- return p.join("-")
- },
- chiludis(item) {
- return item?.disabled || false;
- },
- chulidata() {
- // 处理相关数据格式以保持 一致。
- let t = this;
- let p = this.$tm.deepClone(this.list);
- for (let j = 0; j < p.length; j++) {
- p[j]['dot'] = 0;
- if (p[j]['children']) {
- let ic = p[j].children;
- if (ic.length > 0) {
- for (let k = 0; k < ic.length; k++) {
- let children = ic[k]['children'];
- if (children) {
- if (ic[k]['model'] == 'checkbox'|| ic[k]['model'] == 'listCheckbox' || ic[k]['model'] == 'list' || (ic[k]['model'] == 'radio' && children.length > 0)) {
- for (let z = 0; z < children.length; z++) {
- let im = children[z];
- if (!im.hasOwnProperty('checked')) {
- im['checked'] = false;
- }
- for (let i = 0; i < t.defaultSelected.length; i++) {
- let lsitem = t.defaultSelected[i];
- if (typeof lsitem === 'object') {
- if (lsitem['id'] == im['id']) {
- im['checked'] = true;
- }
- } else {
- if (lsitem == im['id']) {
- im['checked'] = true;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return p;
- },
- // 重置只重置当前打开的页面数量,并不重置其它页面数据。
- resetinit(index) {
- let pd = this.formartData[this.activeIndex];
- if (pd['children']) {
- let ic = pd.children;
- if (ic.length > 0) {
- for (let k = 0; k < ic.length; k++) {
- let children = ic[k]['children'];
- if (children) {
- if (ic[k]['model'] == 'checkbox'||ic[k]['model'] == 'listCheckbox'||ic[k]['model'] == 'list' || (ic[k]['model'] == 'radio' && children.length > 0)) {
- for (let z = 0; z < children.length; z++) {
- let im = children[z];
- im['checked'] = false;
- }
- }
- } else {
- if (ic[k]['model'] == 'slider') {
- ic[k].value = 0;
- } else if (ic[k]['model'] == 'input') {
- ic[k].value = '';
- } else if (ic[k]['model'] == 'pickers') {
- ic[k].value = [];
- } else if (ic[k]['model'] == 'pickersDate') {
- ic[k].value = "";
- }
- }
- }
- }
- }
- this.formartData.splice(this.activeIndex, 1, pd);
- },
- changeIndex(index) {
- this.formartData[index].shang=! this.formartData[index].shang;
- let t = this;
- let itmod = 659;
- clearInterval(itmod)
- if (this.activeIndex === index) {
- this.activeIndex = -1;
-
- } else {
- // this.activeIndex = index;
-
- }
-
- this.$emit('change', this.formartData[index]);
-
- this.rendIdx = 0;
- clearInterval(itmod)
- itmod = setInterval(function(){
- t.rendIdx+=1;
-
- if(t.rendIdx>t.maxLeng||t.activeIndex==-1){
- clearInterval(itmod)
- }
- },10)
- },
- // 获取选中以及填写的数据。
- getData() {
- let p = [...this.formartData];
- let xz = [];
- for (let i = 0; i < p.length; i++) {
- if (p[i]['children']) {
- for (let j = 0; j < p[i].children.length; j++) {
- let ic = p[i].children[j];
- let ps = [];
- if (ic.model == 'checkbox' || ic.model == 'radio' || ic.model == 'listCheckbox' || ic.model == 'list') {
- if (ic['children']) {
- for (let k = 0; k < ic.children.length; k++) {
- if (ic.children[k].checked === true) {
- ps.push(ic.children[k]);
- }
- }
- }
- } else if (ic.model == 'input' || ic.model == 'slider') {
- ps.push(ic);
- } else if(ic.model == 'pickers'){
- ps.push(ic);
- }
- let pyz = { ...ic };
- delete pyz.children;
- xz.push({
- ...pyz,
- children: ps
- });
- }
- }
- }
- this.$emit('confirm', xz);
- this.activeIndex = -1;
- }
- }
- };
- </script>
- <style lang="scss" scoped>
- .tm-dropDownMenu {
- position: relative;
- .tm-dropDownMenu-bar {
- position: relative;
- z-index: 303;
- }
- .tm-dropDownMenu-body {
- background-color: rgba(0, 0, 0, 0.35);
- min-height: 150upx;
- position: absolute;
- z-index: 304;
- width: 100%;
- }
- }
- .optAniopt{
- animation: opt 0.2s linear;
- }
- @keyframes opt{
- 0%{opacity: 0;}
- 100%{opacity: 1;}
- }
- </style>
|