UNPKG

miue-ui

Version:

ali miniProgram UI components for vehicle.

559 lines (543 loc) 16 kB
/** * author:dansion@163.com * data:2022-07-01 * version:V1.0.0 */ import _MENU from './Menu'; const EVENT={}; EVENT.TYPE={ LOWER:'lower', UPPER:'upper', SCROLL:'scroll', MENU_PRESS:'MENU_PRESS', LIST_PRESS:'LIST_PRESS', SCROLL_LOAD:'SCROLL_LOAD', ON_SHOW:'ON_SHOW', } EVENT.build=(target,obj)=>{ /* * type:事件类型 * target:事件目标 * timeStamp:时间戳 * present:当前 索引 * index: * data: * presentMenu * presentItem * menu:[] * list:[] * * } */ let _timeStamp=Date.now(); let {type='NULL',present=null,item=null,show=null,order=null}=obj; //console.log(obj); let _event={ type:type, target:target, timeStamp:_timeStamp, present:present, index:present, menu:target.data.menus, list:target.data.list, total:target.data.total, data:item, style:target.data.style, show:show, order:target.data.order } if(type==EVENT.TYPE.MENU_PRESS){ } if(type==EVENT.TYPE.LIST_PRESS){ _event.currentMenu=target.data.menus[target.data.pointType]; } return _event; } const NOTICE_TEXT=new Map([ ['loading','数据加载中'], ['end','已经到底了'], ['empty','暂时没有数据'], ['error','发生错误了'], ]); const LOADING_STYLE=[ 'ball-clip-rotate-pulse', 'ball-pulse', 'ball-beat', 'ball-pulse-sync', 'line-scale', 'line-scale-pulse-out', 'line-scale-pulse-out-rapid', 'ball-pulse-rise', 'ball-scale-ripple-multiple', 'ball-scale-ripple-multiple-dot', ]; const animation = my.createAnimation({ transformOrigin: "opacity", duration: 3000, timeFunction: "ease-in-out", delay: 0, }); Component({ mixins: [], data: { list:[], total:0, present:-1, order:'', scrollIntoView:0, scrollNum:0, menus:[], isMenu:false, menuIntoView:0, visible:false, type:'normal', listNotice:"", pointType:-1, notice:{}, systemInfo:{}, orientation:'landscape', relation:null,// 关联播放器 style:'list',// list= 文本列表, tile= 图片列表 playState:false, playiconAnim:false, // false=一般图标, true=动画图标 class:'', listAnimation:'', EVENT_TYPE:EVENT.TYPE, voice_menu:false, voice_select:false, voice_next_prev:false, }, props: { onRenderList:'' }, didMount() { //初始化组件 this.animation=animation; //获取窗口大小,根据窗口的情况,设备默认 orientation的值。 my.getSystemInfo({ success: (res) => { this.setData({ systemInfo: res }) //当窗口宽 小于 高 为portrait:竖屏,否则为 横屏。 if(res.windowWidth<res.windowHeight){ this.setData({orientation:"portrait"}); } } }) this._init(); }, didUpdate() {}, didUnmount() {}, methods: { _init(){ // 初始化时候设当前列表为空。 // this._noticeText('empty'); 部份设备以及车机响应慢,默认为empty,再调整共它状态会有闪的。 //向所在 Page 注册自己。 let _id=this.props.id?this.props.id:'lister_'+this.$id; this.data.id=_id; //console.log(_id); if(this.$page.MIUE==undefined){ this.$page.MIUE=new Map(); } this.$page.MIUE.set(this.props.id,this); //根据入参 menu 渲染菜单数据。 if(this.props.menu!=undefined){ let _currentType; let _menu=this.props.menu.split('|'); let _menuObj=[]; _menu.forEach((item,idx)=>{ let _items=item.split(':'); let _disabled=false; let _type=_items[1]; if(_type==undefined){ _disabled=true; } let _selected=_items[2]?true:false; _menuObj.push({text:_items[0],type:_items[1],selected:_selected,disabled:_disabled}); if(_selected){ _currentType=_items[1]; } }); this.setMenu({menu:_menuObj,current:_currentType}); } // 定义列表类型/ 浮动 和 正常类弄 let _type=this.props.type || ''; if(_type=='float'){ this.setData({type:_type}); this.setData({visible:false}); } // 定义列表是不是可以入参动画 let _playiconAnim=this.props.playiconAnim || false; if(_playiconAnim=='true'){ this.setData({playiconAnim:true}); } let {loadingstyle=0}=getApp().config || my.MIUE_CONFIG || {}; this.setData({loadingstyle:loadingstyle}); }, setMenu(obj){ /** * menu={ * type: * text: * disabled: * visible: 是否可见 * } */ let {menu,current}=obj; // 对菜单进行初始化 this.setData({isMenu:true});// 标记有菜单模式 this.setData({menus:_MENU.init(menu)}); if(current){ this._selectMenu(current); } // 菜单无指向时,默认第一个 if(this.data.pointType<0){ current=menu[0].type; this._selectMenu(current); } }, setMenuItem(obj){ let {type,visible=true,disabled=false}=obj let menus=this.data.menus; menus.forEach((element,index) => { //console.log(element); if(type==element.type){ element.visible=visible; element.disabled=disabled; } }); this.setData({menus:menus}); }, setPresent(idx,toview){ this.setData({present:idx}); if(toview){ this.setScrollIntoView(idx); } }, scrollToEnd(){ this.setData({scrollIntoView:'end'}); }, // 设备当前滚动并显示到第N个 setScrollIntoView(idx){ let canViewNun=5;//最小可视条目 let scrollNum=this.data.scrollNum;//当前滚动的位置,默认0 let maxView=scrollNum+canViewNun; let scrollIntoView=this.data.scrollIntoView; if(idx < scrollNum){ scrollNum=idx; } if(idx > maxView){ scrollNum=idx-canViewNun; } this.setData({scrollIntoView:scrollNum}); }, //设置当前列表数据 setDatas(obj){ this.setData({ listAnimation: 'listerViewShow' }); let {total,list=[],order,style,menus,notice,cssClass}=obj; total=total || list.length; //let {total=obj.list.length,style}=obj; this.setListData(list); this.setTotal(total,notice); this.setData({style:style}); this.setData({order:order}); if(menus!=undefined){ this.setData({menus:_MENU.init(menus)}); } if(cssClass!=undefined){ this.setData({cssClass:cssClass}); } }, // 清除列表数据。 clearListData(){ this._noticeText('loading'); this.setData({list:[]}); }, claerMenuData(){ this.setData({menus:[{text:''}]}); }, // 设置列表数据。 setListData(ls){ this._noticeText('loading'); try { //let _list=ls; //let _listLength = _list.length; //this.setData({list:_list}); let new_list=[...ls]; // let new_length = new_list.length; let original_length=this.data.list.length; if(new_length>original_length){ // 对新数据进行减除操作; new_list.splice(0,original_length); // 定义 spliceData 的入参数数组对象; let sp_arr=[original_length,0]; sp_arr=sp_arr.concat(new_list); this.$spliceData({'list':sp_arr}) } let total=this.data.total; // 当列表数据长度和数所都是 0 的情况 if(new_length==0 && total==0){ this._noticeText('empty'); }else if(new_length>=total){ // 当实际长度大于总长时: this._noticeText('end'); } return new_list; } catch (error){ //console.warn(error); this._noticeText('error'); } }, setListDataPlayItem(playid){ //console.log(`setListDataPlayItem,playid:${playid}`) if(playid){ let list=this.data.list; list.forEach((ele,idx) => { //console.log(`ele.id:${ele.id},playid:${playid}`); if(ele.id==playid){ ele.isplay=true; }else{ ele.isplay=false; } }); this.setData({list}) } }, // 设置列表总长度。 setTotal(n,notice={}){ let total=this.data.total; total=n; this.setData({total}); let _listLength=this.data.list.length; if(_listLength>=total){ this._noticeText('end'); } // 当列表长度为 0时 if(_listLength==0){ let {text,detail}=notice; this._noticeText({type:'empty',text:text,detail:detail}); } }, setPlayState(b){ this.setData({playState:b}); }, _renderNotice(){ // todo }, _noticeText(obj){ let {type='error',text='',detail=''}=obj; if(typeof(obj)=='string'){ type=obj; } if(text==''){ text=NOTICE_TEXT.get(type); } //加载的样式 if(type=='loading'){ let loadingstyle=this.data.loadingstyle % LOADING_STYLE.length; type= LOADING_STYLE[loadingstyle]; } let notice=this.data.notice; notice.text = text; notice.detail= detail; notice.type=type; this.setData({notice}); }, setMessage(obj){ //let obj=s; let {text='',detail='',message=''}=obj; if(typeof(obj)=='string'){ text=obj; } //兼容入参不是 text ,而是 message if(text=='' && message!=''){ text=message; } this._noticeText({type:'error',text:text,detail:detail}); }, // 当菜单被点击的事件 onMenuTap(e){ this.setData({ listAnimation: 'listerViewHide' }); this._selectMenu(e.target.dataset.type); }, // 菜单被点击的事件的处理 _selectMenu(type){ let _index; let _current=type; //console.log(_current); let _isfirstItem=null; // 当前是第一个可见菜单 let menus=this.data.menus; menus.forEach((element,index) => { //console.log(element); // 当前是第一个可见菜单 if(element.visible && _isfirstItem==null){ _isfirstItem=index; } if(_current==element.type){ element.selected=true; _index=index; }else{ element.selected=false; } }); // console.log(_obj); this.setData({pointType:_index}); // 当前是第一个可见菜时间,对页面进行样式设置; if(_index==_isfirstItem){ this.setData({firstMenuSelected:true}); }else{ this.setData({firstMenuSelected:false}); } this.setData({menus:menus}); // 处理菜单被点击之事的滚动逻辑 let _currentMenuintoview=this.data.menuIntoView; let _mentintoview=this.data.menuIntoView; if(_index > 2 ){ _mentintoview=_index - 2 + 1; this.setData({menuscrolltop:1}); // 滚动列表会有兼容问题,需要添加一个scrolltop属性兼容 if(_mentintoview==1){ this.setData({menuscrolltop:0}); } this.setData({menuIntoView:_mentintoview}); }else{ this.setData({menuscrolltop:0}); // 滚动列表会有兼容问题,需要添加一个scrolltop属性兼容 } // 触发 onPress 事件 if(this.props.onPress){ this.props.onPress( EVENT.build(this,{type:EVENT.TYPE.MENU_PRESS,present:_index,item:menus[_index]}) ); } }, // 当列表被点击 onListTap(e){ let idx=e.target.targetDataset.index; if(idx!=undefined && this.props.onPress){ this.props.onPress( EVENT.build(this,{type:EVENT.TYPE.LIST_PRESS,present:idx,item:this.data.list[idx]}) ); } //存在关联player 直接调用播放 if(this.data.relation!=null){ this.data.relation.play(_event); } }, // 向上滚动 upper(e){ if(this.props.onScroll){ this.props.onScroll(EVENT.build(this,{type:EVENT.TYPE.UPPER})); } }, // 向下滚动 lower(e){ if(this.props.onScroll){ this.props.onScroll(EVENT.build(this,{type:EVENT.TYPE.LOWER})); } // 滚动到最下面~~ let {list,total='unknow'}=this.data; //console.log(list); //console.log(total); //console.log(list.length < total); //console.log((list.length < total || total=='unknow')); if(list.length>1 && (list.length < total || total=='unknow')){ //console.log('onScrollLoad---'); if(this.props.onScrollLoad){ this.props.onScrollLoad(EVENT.build(this,{type:EVENT.TYPE.SCROLL_LOAD})); } this._noticeText('loading'); } }, // 滚动操作 scroll(e){ if(this.props.onScroll){ this.props.onScroll(EVENT.build(this,{type:EVENT.TYPE.SCROLL})); } //当前滚动的位置,默认0 let listLength=this.data.list.length + 1; this.data.scrollNum= e.detail.scrollTop / e.detail.scrollHeight * listLength; }, // 当整体表被展示(浮动模式) show(b){ this.setData({visible:b}); if(this.props.onShow){ this.props.onShow(EVENT.build(this,{type:EVENT.ON_SHOW,show:b})); } }, // 当整体被关闭(浮动模式) onClose(e){ //console.log(e); this.show(false); }, // 语音VGUI指令 select:“第N个" onVoiceSelectCommand(e){ // 获取语音VGUI的热词 let {result=0,command={}}=e || {}; let {action}=command || {}; // action: next,previous,select let tapEvent={ type:'voice', timeStamp:Date.now(), target:{targetDataset:{index:-1,}} } if(action=="select"){ result=result-1;// 列表第一项是0开始,所有需要 -1; tapEvent.target.targetDataset.index=result; this.onListTap(tapEvent); } }, onMenuVoice(e){ //my.showToast({content:e.target.dataset.type}); //console.log(e); let menu=this.data.menus; let {querywords=''}=e; //获取Voice 的关健词 //console.log(menu); menu.forEach((ele,idx)=>{ if(querywords==ele.text){ let type=ele.type; this._selectMenu(type); } }); //this._selectMenu(e.target.dataset.type); }, // 语音被命中上一页/ 下一页操作 onVoiceNextPrevCommand(e){ let {result=0,command={}}=e || {}; let {action}=command || {}; // action: next,previous let {present=-1}=this.data; let tapEvent={ type:'voice', timeStamp:Date.now(), target:{targetDataset:{index:-1,}} } if(present==-1){ let action_str=action=='next'?'向后一个':'向前一个'; if(this.props.onError){ this.props.onError( { refer:`voice_${action}`, type:'voice', action:action, timeStamp:Date.now(), index:present, code:'20000', message:`当前列表为空或不可选,[${action_str}]操作无效!` } ); } }else{ if(action=='next'){ tapEvent.target.targetDataset.index=present+1; this.onListTap(tapEvent); } if(action=='previous'){ console.log(`present:${present},index:${tapEvent.target.targetDataset.index}`) tapEvent.target.targetDataset.index=present-1; this.onListTap(tapEvent); } } } }, });