工作中总结或记录的一些记录。

非主父子传值
https://juejin.im/entry/59b0b36d6fb9a0247a611115
调试 vconsole
npm install vconsole

import VConsole from 'vconsole'
const vConsole = new VConsole()

Vue.use(VConsole)
物理键“ 返回 ” 监听
使用 cordova 时,如果不同的页面都调用了,都会默认调用该方法的。

遇到的问题:
如果是 安卓机只有一个 HOME 按键时,解决跳出页面?
使用计数器 count = 2 是 退出程序。
document.addEventListener("backbutton", onBackKeyDown, false);

监听软键盘 安卓手机也是 13

https://blog.csdn.net/wangjuhi/article/details/80112305
refs 的使用

使用说明:拿到对应的 标签。

 <form action="javascript:return true">
         <input type="search" @focus="focusAction()" ref="input1" v-model="keyword" :class="{'font-333': keyword}"  @keyup.prevent.stop="searchWord($event,keyword)" :placeholder="placeholder"  />
</form>
                
// 焦点
 this.$refs.input1.focus();
怎么给返回的值设置值
this.$set(item, 'suppementary', this.canSuppementary)
解决 ios 输入框跟着键盘顶上去
position: fixed; // 如果不想跟着顶上去,可以使用 flex布局 或绝对定位
overflow-y: scroll; // 某个方向 滚动
reduce 使用

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

给为添加的或赋值的 数组添加内容
// accumulator 累计数器
// currentValue 数组中正在处理的当前值
var sum = [0, 1, 2, 3].reduce(function (accumulator, currentValue) {
  return accumulator + currentValue;
}, 0);
// 和为 6

怎么修改对象的值
 dealWithArr(arr){
            // let arr = [
            //     {barcode: "957373",
            //     entorgid: 401,
            //     itemId: 632502,
            //     itemName: "P10 柜式洗碗机 220V,1Ph <55dB E5 WQP12-W5302D-CN-A",
            //     modelManageId: 3537995,
            //     modelType: 1,
            //     organizationId: "17",
            //     stat: 1,
            //     terminalId: 88008
            //     }
            // ]
            let temArr = [], obj = {}

            arr.forEach(vv => {
                if(vv.itemName) {
                    obj.barcode = vv.barcode
                obj.entorgid = vv.entorgid
                obj.itemId = vv.entorgid
                obj.modelManageId = vv.modelManageId
                obj.modelType = vv.modelType
                obj.organizationId = vv.organizationId
                obj.stat = vv.stat
                obj.terminalId = vv.terminalId
                }
                temArr.push(obj)
            })
            return temArr;
        },
懒加载 v-lazy

使用场景: H5中 加图片

在main.js 

import VueLazyload from 'vue-lazyload'

Vue.use(VueLazyload)

// 测试 图片 --- 多张图片时 循环一遍 第一张 丢失的问题!!!!

<div class="item_left"  @click="goPage('proDetail',item)">
     <img class="production_img" v-lazy="item.pictureUrl?item.pictureUrl:noImgdata" alt="">
</div>
                                
<!-- <img class="production_img" v-lazy="item.pictureUrl?item.pictureUrl:noImgdata" alt=""> -->

常见错误
ERROR in ./src/mixins/vouchersMixin.js
Module not found: Error: Can't resolve 'moment' in 'D:\MyData\ex_hech\meidi
 @ ./src/mixins/vouchersMixin.js 11:14-31
 @ ./node_modules/babel-loader/lib!./node_modules/vue-loader/lib/selector.jue

解决:
下载新的 moment 组件, npm i -moment
创建一个 公共的utilit.js

使用场景:公共方法 + mixin

1、创建一个 utilit.js 
let myMixin =  {
   
    hello: function() {
        console.log('这是测试。。。。调用mixin 方法')
    },           
}
export default  myMixin

2、在vue 里面 引入
    
    import myMixin from '../../js/mixin'
	// 调用 js的方法
	myMixin.hello(); // 这是测试。。。。调用mixin 方法

混入Vue https://cn.vuejs.org/v2/guide/mixins.html

它和上面的 公共的 .js 的区别是,它的方法是直接 使用!!! ,而不是 xxx.方法()

建立一个公共组件,然后对该组件进行混入继承.
注意会走两个生命周期,谨慎使用
mixins混入,相当于生成new 组件;组件引用,相当与在父组件内开辟了一块单独的空间
mixins适用于,两个有非常相似的组件,他们基本功能是一样的,但他们之间又存在这足够的差异性。(发票识别:增值税、黑白发票、红色发票)

1、写个 xxx.js
export default {
    methods:{
        // 处理发票, 给外面调用的方法(直接使用即可!!!)
        handleInvoice() {
            console.log('测试 mixin 调用方法');
        },
        //识别发票
        readInvoice() {
            let hasCommissionSale = this.storage.get('hasCommissionSale')
            if(hasCommissionSale) return this.$toast('旗舰店已标注无须上报')
            this.showDialog = true;
        },
    }
};

2、在vue 里引入
// 引入 mixin
import  listenerMixin  from '../../minxin/invoiceMixin.js'

在 export default {
	// 混合  
	mixins:[listenerMixin],    
}里写入。

3、调用 (直接使用 this.xxxx)
this.handleInvoice(123);
this.readInvoice();


点击跳转的写法之一
<div class="passTips-box bd-bottom" @click="goPage('kitchenFeverAllOders', isSelect)">
    <span>全部订单</span>
    <span class="moreOders">
        查看全部订单
        <span class="scaleIconBox">
            <i class="icon-jiantouxiao iconfont"></i>
        </span>
    </span>
</div>

调用:
goPage(url, param) {
    this.$router.push({
        name: url,
        query: {
            param: param
        }
    })
},

---------------------- path (路径) -------------------------
/** 跳到 业绩详情*/
orderDetail:function(item) {
    this.$router.$push({
        // name: 'orderDetail',  // 名字 params
        path: "/orderDetail",  // 路径
        query:{
            // 路由参数
            orderId:item.orderId,
            engineerCode:this.engineerCode
        }
     });
},

记忆:

path + query | name + params

记:path 是查询路径的的 (如有参数,在地址栏显示), name 是 参数的

--------------------------------------router- start -------------------------------------------------

路由跳转传值

router.push(location)

这个方法会向 history 栈添加一个新的记录,当用户点击浏览器后退按钮时,则回到之前的 URL。

// 字符串
router.push('home')

// 对象
this.$router.push({path: '/login?url=' + this.$route.path});

// 带查询参数,变成 /backend/order?selected=2
this.$router.push({path: '/backend/order', query: {selected: "2"}});

// 命名的路由 ---  路由的名称
router.push({ name: 'user', params: { userId: 123 }})

router.replace(location)

设置 replace 属性(默认值: false)的话,当点击时,会调用 router.replace() 而不是 router.push(),于是导航后不会留下 history 记录。即使点击返回按钮也不会回到这个页面。

加上replace: true后,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。

//声明式:
<router-link :to="..." replace></router-link>
// 编程式:
router.replace(...)
//push方法也可以传replace
this.$router.push({path: '/home', replace: true})
两者都可以传递参数,区别是什么?
query 传参配置的是path,而params传参配置的是name,在params中配置path无效
query在路由配置不需要设置参数,而params必须设置
query传递的参数会显示在地址栏中
params传参刷新会无效,但是query会保存传递过来的值,刷新不变 ;

5.路由配置:
传参两种方式
使用query:
this.$router.push({
  path: '/home',
  query: {
    site: [],
    bu: []
}
})
复制代码使用params:
this.$router.push({
  name: 'Home',  // 路由的名称
  params: {
    site: [],
    bu: []
}
})

获取路由参数 (是this. r o u t e . x x x , 不 是 t h i s . route.xxx , 不是 this. route.xxx,this.router.)
 let site = this.$route.query.site
  let bu = this.$route.query.bu
  // 如果是params 传参,那就是this.$route.params.site
  上面就可以获取到传递的参数了

获取路由上面的参数,用的是$route,后面没有 " r "。

总结
params是路由的一部分,必须要有。query是拼接在url后面的参数,没有也没关系。
params一旦设置在路由,params就是路由的一部分,如果这个路由有params传参,但是在跳转的时候没有传这个参数,会导致跳转失败或者页面会没有内容。
params、query不设置也可以传参,但是params不设置的时候,刷新页面或者返回参数会丢失,query并不会出现这种情况.

1.命名路由搭配params,刷新页面参数会丢失

2.查询参数搭配query,刷新页面数据不会丢失

3.接受参数使用this.$router后面就是搭配路由的名称就能获取到参数的值

------------------ query 和 params END --------------------------------

封装h5和ios修改导航栏颜色

 /**
 * 改变状态栏颜色-仅IOS
 * @param p {array} 参数 [r, g, b]
 * @return {*|promise}
 */
changeColor: function (p) {
        return functions.callApi(_MIDEA_COMMON, 'statusBarColor', p);
    },

-------------------------- 使用 ----------------------------
 platform.changeColor([255,255,255]);

解决iphoneX 遮罩层全屏

 mounted() {
        this.getBookId();
        platform.changeColor([255,255,255])
        if(this.isIOS){
            platform.setViewControllerBackGroundColor([{r: 247, g: 249, b: 250, a: 0.95}])
        }
    },
    activated() {
        this.reportProList = this.storage.get('reportProList') ? this.storage.get('reportProList') : [];
        platform.changeColor([255,255,255])
        if(this.isIOS){
            platform.setViewControllerBackGroundColor([{r: 247, g: 249, b: 250, a: 0.95}])
        }
        this.downLoading();
        this.addBurialPoint('FUC00052');
    },

前端监听手机进入后台pause 、恢复到前台运行 resume

 mounted() {                
            // 这里判断 --- 进入手机后台操作什么的。。。
            document.addEventListener('resume', ()=> {
                console.log('进入后台',this.myAddr);
                this.myAddr = {}; // 清空(如果不清空的话,故意不定位,点击拍照后才知道没有开启定位)                
                // 再次定位
                this.getCurrentAddr();               
            })               
        },

------------------------ deviceready --------------------------当cordova被完全加载时会触发deviceready事件,这是每个cordova应用程序都会用到的重要事件。

document.addEventListener("deviceready", onDeviceReady, false);

function onDeviceReady() {

    // Now safe to use device APIs

}
------------------------ pause ---------------------------------
document.addEventListener("deviceready", onDeviceReady, false);

function onDeviceReady() {

    document.addEventListener("pause", onPause, false);

}

function onPause() {

    // Handle the pause event

}

------------------------ resume -------------------------------
document.addEventListener("deviceready", onDeviceReady, false);

function onDeviceReady() {

    document.addEventListener("resume", onResume, false);

}

function onResume() {

    // Handle the resume event

}

  

cordova 的使用!!! HTML+原生

-------------------------------- Vuex start --------------------------------------------------------

官网api https://vuex.vuejs.org/zh/api/#state

vuex

export default {
    state,// 唯一根实例(根状态,只读)
    actions, 
    getters, // 暴露出注册的 getter,只读。
    mutations // 唯一更改值 (和 actions 非常像. mutation 必须是同步函数)
}

使用:
0.import { mapState } from 'vuex'

1、
mutations:在组件中使用就是:
this.$store.commit('xxx') 或者 ...mapMutations (['xxx'])

2、
 ...mapMutations({
      add: 'increment' // 将 `this.add()` 映射(相当于)为 `this.$store.commit('increment')`
    })
就是 可以直接使用 this.add(xxx) 其中 add 不是data声明的属性(vuex里的)。
3、
const mutations ={
    'Increment':(state,data)=>{
        state.increment = data
    },   
    'ENTER_REFRESH':(state ,data)=> {
        state.enterRefresh = data
    }
};
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。
Action 通过 store.dispatch 方法触发:
Vue.use(Vuex); // 全局(注册)
:就是在根实例(state)注册后,就可以通过 this.$store 访问了。
this.$store.state.count

Vuex.Store 实例方法

commit

import {mapState, mapActions, mapMutations} from 'vuex';

commit(type: string, payload?: any, options?: Object)
commit(mutation: Object, options?: Object)
提交 mutation 时。options 里可以有 root: true,它允许在命名空间模块里提交根的 mutation。

使用:
	 this.$store.commit('NEW_TERMINAL_ARR', this.terminaArr);
     this.$store.commit('DATE_IS_RESET', false);

dispatch

import {mapState, mapActions, mapMutations} from 'vuex';

dispatch(type: string, payload?: any, options?: Object)
dispatch(action: Object, options?: Object)
分发 action。options 里可以有 root: true,它允许在命名空间模块里分发根的 action。返回一个解析所有被触发的 action 处理器的 Promise。

使用:
this.$store.dispatch('getPromotionActivityDetail', params).then(data => { }

replaceState

replaceState(state: Object)
替换 store 的根状态,仅用状态合并或时光旅行调试。

watch

watch(fn: Function, callback: Function, options?: Object): Function
响应式地侦听 fn 的返回值,当值改变时调用回调函数。fn 接收 store 的 state 作为第一个参数,其 getter 作为第二个参数。最后接收一个可选的对象参数表示 Vue 的 vm.$watch 方法的参数。
要停止侦听,调用此方法返回的函数即可停止侦听。

使用:
 watch: {
            keyword(newVal, oldVal) {
                // 防抖动
                var timer = setTimeout(() => {
                    clearTimeout(timer);
                    this.downLoading();
                }, 1000)
            }
        }

subscribe

通常用于插件

辅助函数

mapState

为组件创建计算属性以返回 Vuex store 中的状态.

mapState(namespace?: string, map: Array<string> | Object<string | function>): Object

mapState

https://juejin.im/post/5ae433ab518825671a6388d5

import { mapState, mapAction } from 'vuex'
  computed: {
        ...mapState({
            todoList: state => state.demo.todoList
        })
    },

mutatuions.js

// 使用:例如:…mapState({nearbyAddress: state => state.xxx.nearbyAddress,//选择的附近位置信息})

const mutations = {        
	 // 附近的位置
     'NEARBY_ADDRESS': (state, list) => {
         state.nearbyAddress = list;
     },
     // 当前地址
    'SETCUR_ADDR': (state, curAddr) => {
        state.curAddr = curAddr
    },
}
export default mutations;

mapState

  // mapState辅助函数:计算多个状态值
  computed: mapState({
    cc: state => state.workReport.cc,
    userInfo: state => state.com.userInfo,
    bookId: state => state.activity.bookId,
    defaultCC: state => state.workReport.defaultCC,
  }),

mapActions

创建组件方法分发 action

mapActions(namespace?: string, map: Array<string> | Object<string | function>): Object


mapMutations

mapMutations(namespace?: string, map: Array<string> | Object<string | function>): Object

创建组件方法提交 mutation。

vuex

与商店有关的使用(注册后可使用): this.$store

1、同步提交
this.$store.commit('SETCUR_ADDR',addr); 
2、清空提交
this.$store.('SETCUR_ADDR',{}); 

3、state 创建那么多属性对象,怎么使用?
通过 mapState助手 来使用。(作用是:计算多个对象、属性)

computed: mapState({})
或者: 
computed: {  // 作用是:计算多个对象、属性
    ...mapState({
        shopList: state => state.shop.clientListSearch,
        orgId: state => state.shop.orgId,//产品中心id
        userInfo: state => state.com.userInfo,            
    })
},
-------------------- 实现 ----------------------
1、创建 store.js
action(dispatch、commit)\mutations(mutate)\state (render)

引入:   import {api} from '../api';
		import ajax from '../ajax';
state: (存放对象或属性的。供 action 或 mutation 调用它定义的属性 )
const state = {
    companyList: [],//产品中心列表
    shopList: [],//门店列表
    terminalName: '',//门店名
    shopDetail: {},
}
getter:
const getters = {};

const actions = {
	getShopList({commit, dispathc, state}, param) {
        return ajax.post(api.getMktInspectionTerminal, param)
    },
    getClientList({commit, dispathc, state}, param) {
        return ajax.post(api.getMktInspectionCustomer, param)
    },
};

mutations:
const mutations = {
	// 方法名
    'GET_COMPANY_LIST': (state, list) => {
        state.companyList = [];
        list.map((v, i, t) => {
            v.active = false;
            state.companyList.push(v);
        });
    },
    'SETCUR_ADDR': (state, curAddr) => {
        state.curAddr = curAddr
    },
};

export default {
    state,
    getters,
    actions,
    mutations
}
mutatuons: --------------- 使用
// 设置当前定位 (使用方法:state.currentLocation)
 ...mapState({
     currentLocation: state => state.sign.currentLocation,
 })

// 定位的对象
'SET_LOCATION_CURRENT': (state, data) => {
    state.currentLocation = data;
},
this.$store.commit 到哪里?
this.$store.commit 的值实际上就是 mutations 。

怎么使用?:
computed: {
    ...mapState({
         currentLocation: state => state.sign.currentLocation,
     })
 }

---------------------------------------------------- Vuex end -----------------------------------

this 闭包了。

const self = this
处理参数带“反斜杠”
 let tempString = JSON.stringify(config.data).replace(/\\/g, "%")
   
 项目打印显示是被转成了 "%",如果是其它的话,根据项目的打印替换。
在移动端的点击返回按钮的 "返回"形式

场景:返回时,动画效果是不一样的。

加上 $ 和去掉 $ 是有区别的。(右往左,和左往右)
prototype 原型
prototype 属性使您有能力向对象添加属性和方法。
语法:
object.prototype.name=value
怎么使用某个组件
1、引入路径
import DatePicker from "../../components/public/datePickerV2/date-picker.vue";
2、引入组件
components: {
    DatePicker
  },
3、使用组件
<date-picker ref="datePicker"
                 :visible='showDate'
                 v-if="showDate"
                 :value="dateVal"
                 :min="time"
                 :max="maxTime"
                 :title="pickerTitle"
                 @select="setDateVal"
                 @cancel="closeDatePicker"></date-picker>
4、@ 代表: 方法 ,: 代表属性

安装某个版本插件

npm uninstall better-scroll
npm i better-scroll@1.13.4

// 默认 前面有个箭头 (手动去掉 package.json)
 "better-scroll": "^1.13.4",

时间选择器

滴滴内部组件: https://didi.github.io/cube-ui/#/zh-CN/docs/date-picker

// ---------- 解决日期选择滑动 卡死 --------------
npm uninstall better-scroll
npm i better-scroll@1.13.4	

旧版的toast

main.js

import Toast from './components/toast'
Vue.use(Toast)

响应式

 this.$set(item, 'checked',false)
监听真机物理返回键
 /** 监听物理返回按钮 */
  beforeRouteLeave (to, from , next) {
      // next(false)//可以通过在这里写逻辑来处理用户点了物理返回之后的操作
      // console.log('监听物理返回按钮'); // replace    
      // 清空图片选择相册 记录
      localStorage.removeItem('limitThree');  
        // 清空
        // if(to.name == "cleanseHome"){
          // localStorage.setItem('noRef',true);
          // this.$router.push({name:"createMenu"});
        // }else{
          // localStorage.setItem('noRef',true);
          next();
        // }
  }
怎么拿到当前月的最后一天
 var year = date.getFullYear();
      var month = date.getMonth() + 1;
      var day = date.getDate();
      var lastDate = new Date(year, month, 0).getDate();
      this.endDate = year + '-' + (month>9?month:'0'+month) + '-' + lastDate;
      console.log('当前时间是:',this.endDate , this.maxTime);
没有数据占位符:样式
.no_data{
        position: absolute;
        top:58%;
        left: 50%;
        transform: translateX(-50%) translateY(-50%);
        overflow: hidden;   
        .no_data_img {
            width: 138px;
            height: 83px;
        }
        .no_data_content {
            margin-top: 20px;
            font-family: PingFangSC-Regular;
            font-size: 16px;
            color: #999999;
            text-align: center;
        }
    }
解决安卓机键盘把元素顶上去

场景: 点击搜索时,下面的或底部的 “提交按钮” 被键盘顶上去了。

// 父元素添加 最小高度,子元素 使用 abstrolute
min-height: 500px;
height: 100%;
去掉滚动的细线:
xxxx::-webkit-scrollbar {
            display: none;
            height: 0;
        }
兼容(解析值)
消息推送:
使用 JSON.parse 解析,才有值。
  console.log('消息id:',data.extra.showWidgetKey.workAttendanceId); // undefind
                        console.log('兼容id:',JSON.parse(data.extra.showWidgetKey).workAttendanceId); // 有值
                        
 this.$router.$replace({
                                path: "/leaveRecord",
                                query: {
                                    workAttendanceID: JSON.parse(data.extra.showWidgetKey).workAttendanceId,
                                }
                            });
-----------------------------------------------

document.addEventListener("deviceready", () => {
                platform.getExtra(["com.midea.msd.guideCommunity"]).then((data) => {
                    let extraData = data.extra
                    if(!data.extra){
                        this.getDefaultData(this.employeeType);
                        return false;
                    }
                    ajax.setDefault(this.employeeType);
                    this.getBaseDataNew();

                    // //设置消息
                    let tempData = data;

                    console.log('date........' , data);

                    console.log('JSON.parse(data.extra.showWidgetKey).....' , JSON.parse(data.extra.showWidgetKey));

                    console.log('data.extra.showWidgetKey.....' , data.extra.showWidgetKey);

                    if(data.extra.action){
                        data.extra = data.extra;
                    }else if(data.extra.showWidgetKey.action){
                        data.extra = data.extra.showWidgetKey;
                    }else if(JSON.parse(data.extra.showWidgetKey).action){
                        data.extra = JSON.parse(data.extra.showWidgetKey);
                    }


                    switch (data.extra.action || data.extra.showWidgetKey.action || JSON.parse(data.extra.showWidgetKey).action) {

                        case 'interactiveForumAdoption': //回答被采纳 --- 回答详情
                            this.$router.$replace({ // 参数replyId
                                name: "answersDetail",
                                query: {
                                    replyId: data.extra.id,
                                    comFrom: data.extra.comFrom,
                                    bookId: data.extra.bookId
                                }
                            });
                            break;
                        case 'interactiveForumReply': //回复有了新评论 -- 全部评论
                            this.$router.$replace({ // 参数replyId
                                name: "allCommont",
                                query: {
                                    // commentId: data.extra.commentId,
                                    replyId: data.extra.id,
                                    comFrom: data.extra.comFrom,
                                    bookId: data.extra.bookId
                                }
                            });
                            break;
                        case 'interactiveForumQuestion':  //问题有了新回复--- 问题详情
                            this.$router.$replace({ // 参数replyId
                                name: "answersDetail",
                                query: {
                                    replyId: data.extra.id,
                                    comFrom: data.extra.comFrom,
                                    bookId: data.extra.bookId
                                }
                            });
                            break;
                        case 'interactiveForumAskQuestion':  //跳问题详情
                            this.$router.$replace({ // 参数replyId
                                name: "problemDetails",
                                query: {
                                    questionId: data.extra.id,
                                    comFrom: data.extra.comFrom,
                                    bookId: data.extra.bookId
                                }
                            });
                            break;
                        case 'toMyfans':  //跳我的粉丝
                            this.$router.$replace({
                                name: "myFans",
                                query: {
                                    comFrom: 1,
                                }
                            });
                            break;
                        case 'toMycontent':  //跳我的关注
                            this.$router.$replace({
                                name: "myAttention",
                                query: {
                                    comFrom: 1,
                                }
                            });
                            break;
                        case 'toMyAnswer':  //跳我的回答
                            this.$router.$replace({
                                name: "myAnswers",
                                query: {
                                    comFrom: 1,
                                }
                            });
                            break;
                        case 'fromAssitant':
                            let tempData = {};
                            let defaultData = {};
                            tempData = data.extra.showWidgetKey;
                            if (this.judgeClient() == "Android") {
                                defaultData = JSON.parse(tempData);
                            } else {
                                defaultData = tempData
                            }
                            this.employeeType = defaultData.employeeType
                            this.bookId = defaultData.bookId
                            this.$store.commit('SET_BOOKIS', this.bookId);
                            this.getDefaultData(this.employeeType);
                            break;
                        default:
                            this.getDefaultData(this.employeeType);
                    }
                })
            })
怎么修改input的默认颜色
input默认颜色是:#999999

input::-webkit-input-placeholder{
    color: #999999;
}

样式写法

<div class="ranking_information_item-descNum">
	{{currentPerson.praiseNum?currentPerson.praiseNum:'0'}}
</div>

// -------------- 样式写法 (有 “ - ” 号的使用 & )--------------
.ranking_information_item{
          flex: 1;
              display: flex;
              flex-direction: column;
               justify-content: center;
              align-items: center;
              &-desc{
               // font-family: PingFangSC-Semibold;                  
               font-family: DINAlternate-Bold;
               font-size: 20px;
               color: #333333;
               text-align: center;
               line-height: 26px;
              }
             &-descNum{
               font-family: DINAlternate-Bold;
               font-size: 20px;
               color: #00B9FF;
               text-align: center;
               line-height: 26px;
             }
            &-cate{
              font-family: PingFangSC-Regular;
              font-size: 14px;
              color: #999999;
              text-align: center;
              line-height: 11px;
              margin-top: 6px;
       }
}
激活按钮颜色: isActivity 是属性, submitButton是样式!!!

<div class="gayButton " @click="confirmGift" :class="{'submitButton': isActivity}">提交</div>

// -------- 方法 ------------
confirmGift() {
    this.addOutSide();
},
//新增用户接口
addOutSide() {
    if (this.limitSub) return false;
    if (!this.checkoutAll()) return;
    this.limitSub = true;
    let params = {
    }
---------------------------------------------------
// div
<div class= "praiseDetails_content-preview"> 测试 </div>

// 样式
 .praiseDetails_content {
        margin-top: 45px;
        padding: 0 15px;
        font-family: PingFangSC-Regular;
        font-size: 14px;
        color: @col-333;
        display: flex;
        flex-direction: column;
        justify-content: center;
        .mar{
            margin-right: 0;
        }
        &-preview{
            display: flex;
            justify-content: flex-start;
 	    }
 }
 
 // -------------------------  写法 -------------------------------
 <div class="content">
 	<div class="content-items-title"></div>
 	<div class="content-items-test"></div>
 </div>
 
 // 样式 --- 层层累加
 .content {
 	 &-items {
          &-title {
               &::before {}
          }
          &-test {}
 	 }
 }
// --------------------- 使用 &:  链接 -------- 5n :表示5的倍数
奇数:“odd”、 偶数:“even”

 &:nth-of-type(8){
     margin-right: 0;
  }
// ---------------------------- ----------------------------------------

 <div class="dialog-footer-control">
      <span class="dialog-footer-control-item bd-bottom" @click="tackPicture(1)">拍照</span>
      <span class="dialog-footer-control-item" @click="tackPicture(2)">从相册选取</span>
 </div>
 // --- 样式
 .dialog-footer{
      &-control{
          &-item{
                    padding: 15px 0;
                    width: 100%;
                    text-align: center;
                    font-family: PingFangSC-Regular;
                    font-size: 14px;
                    color: #333333;
                }
      }
 }
 
 //-------------- 字体 间距-------------------------
 letter-spacing: 0.58px;
 
 // --------------- 搜索 ---------------------------
 <div class="search-boxs bd-bottom">
                <div class="inputBox">
                    <i class="iconfont icon-chaxunx"></i>
                    <form action="javascript:return true">
                        <input type="search" class="searchTitle" :class="{'col-333': condition}" placeholder="请输入型号/名称" v-model="condition" @keyup.prevent.stop="searchWord($event,condition)" >
                    </form>
                    <i class="iconfont icon-chax " v-if='condition.length'  @click.prevent.stop="clear"></i>
                </div>
            </div>
 // --------------- 样式 -----------------
  margin-top: 45px;
        // s 不使用公共的样式
        .search-boxs{
            margin-top: 60px;
            background: #fff;
            .inputBox{
                width: 100%;
                padding: 0px 15px 15px 15px;
                display: flex;
                position: relative;

                form{
                    flex: 1;
                    display: flex
                }
                input{
                    flex: 1;
                    height: 28px;
                    border: 1px solid #f5f5f5;
                    border-radius: 16px;
                    outline: none;
                    background: #f5f5f5;
                    text-indent: 30px;
                    font-size: 14px;
                    padding-right: 33px;
                }
                .col-333{
                    color: #333;
                }
                // 去掉默认的 叉
                input::-webkit-search-cancel-button {
                    display: none;
                }
                .icon-chaxunx{
                    position: absolute;
                    top: 8px;
                    right: 32px;
                    color: #999999;
                    font-size: 13px;
                }
                .icon-chax{
                    position: absolute;
                    top: 7px;
                    right: 31px;
                    color: #d8d8d8;
                    font-size: 15px;
                }
            }
        }
怎么自定义组件
 <calendar ref="calendar"
          @select="selectDate"
          :attendanceList="attendanceList"
          :selMonth="curMonth"
          @preMon="preMon"
          @selectMon="showDatePicker"
          @nexttMon="nexttMon">
</calendar>
// ----- @xxx 表示是 自定义组件的 方法, :xxx 表示是自定义组件 的属性(  props: {})
总结:他们是一 一 对应的!!!

例如:
	  props: {
	  	// 是否显示农历
         lunar: {
                type: Boolean,
                default: false
         },
	    // 自定义月份名称
        months: {
            type: Array,
            default: function () {
                return window.navigator.language.toLowerCase() == "zh-cn" ? ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'] : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
            }
        },
          selMonth: {
                type: String,
                default: ''
            },
          attendanceList: {
            type: Array,
            default() {
                return []
            }
        }
	  }
      min-height: 44px; // 50 一定要给高 (否则低端安卓机不会显示)
      transform: translateY(2px); // 向上偏移 2个像素(比定位好多了)
伪类的使用:
class="content-items-title"
    {
    position: relative;
    font-family: PingFangSC-Medium;
    font-size: 16px;
    }
    
    --------------------- 文字前面显示一个 颜色点 ------------------------
     &-items {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 15px 0;

            &-title {
                position: relative;
                font-family: PingFangSC-Medium;
                font-size: 16px;

                &::before {
                    content: '';
                    width: 4px;
                    height: 12px;
                    position: absolute;
                    left: -15px;
                    top: 5px;
                    background: @skyBlue;
                }
            }
       }
    ---------------------------------------------------
    0、::before{}
    1、 content: '';
    2、大小、宽高、定位什么的

选择左右:

 <div class="comment-quertion">
        1.请选择本次上门清洗人员的服务内容
        <span class="required">*</span>
      </div>
      <div class="service-choice">
        <div
          class="service-item"
          v-for="(item, index) in serviceList"
          :key="index"
          :class="{'service-item-click': item.choose}"
          @click="choiceServiceList(index)"
        >{{item.name}}</div>
      </div>
      
强制刷新
 // 强制刷新
 // this.$forceUpdate();
地图标记
引入样式 map.less

自定义组件

头部组件

<style lang="less">
    @import "../assets/style/variable.less";
    .header{
        display: flex;
        justify-content: space-between;
        position: fixed;
        z-index: 1;
        font-size: 18px;
        top:0;
        left: 0;
        right:0;
        height: 45px;
        box-sizing: border-box;
        line-height: 44px;
        text-align: center;
        background: #fff;
        user-select: none;
        .back{
            position: relative;
            font-size: 21px;
            color: #333333;
            line-height: 44px;
            padding-left: 15px;
            width: 30px;
            &.icon-back {
                &::before {
                    position: absolute;
                    top: 51%;
                    left: 11px;
                    margin-top: -10px;
                    line-height: 0;
                    padding: 10px 0;
                }
            }
        }
        .title{
            font-family: PingFangSC-Regular;
            font-size: 17px;
            color: #333333;
            text-align: center;
            line-height: 17px;
        }
        .left-con{
            flex-grow: 1;
        }
        .middle-con{
            position: absolute;
            top:50%;
            left: 50%;
            transform: translateX(-50%) translateY(-50%);
            overflow: hidden;           
        }
        .right-con{
            flex-grow: 0;
            padding-right: 15px;
            font-size: 18px;
            color: #666;
        }
    }
    .header-back{
        position: absolute;
        top: 1px;
        left: 32px;
        font-family: PingFangTC-Regular;
        font-size: 18px;
        color: #333333;
    }
</style>
<template>
    <header class="header  bd-bottom" v-if="show">
       <div class="back icon-back iconfont" v-if="showBack" @click="back"></div>
        <span class="header-back" @click="back"></span>
        <div class="left-con">
            <slot name="left"></slot>
        </div>
        <div class="middle-con" v-if="!title">
            <slot name="middle"></slot>
        </div>
        <div class="title middle-con" v-if="title">
            {{title}}
            <slot></slot>
        </div>
        <div class="right-con">
            <slot name="right"></slot>
        </div>
    </header>
</template>
<script>
    export default{
    	props:{
    	    showBack:{
    	    	type:Boolean,
                default:true
            },
            title: {
    	    	type: String,
            },
            show:  {
    	    	type:Boolean,
                default:true
            },
            backFun: {
                type: Function,
            }
        },
        data() {
            return{

            }
        },
        mounted(){

        },
        methods: {
            back () {
                if(this.backFun){
                    this.backFun();
                }else{
//                    console.log(this.$route)
                    this.$router.back();
                }
            }
        }
    }
</script>


ios怎么和HTML建立通信(混合开发)?
vue 里需要引入 <script src="./cordova.js>
1、在 index.html 文件下引入  <script src="./cordova.js?ver=md5"></script>

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
    <title>h5-dev-mobile-funny-sign</title>
    <script src="http://webapi.amap.com/maps?v=1.3&key=45d29c6f1826ea0b2a30e84cfb43f922"></script>
</head>

<body>
    <div id="app"></div>
    <script src="./cordova.js?ver=md5"></script>
    <script src="./cordova_plugins.js?ver=md5"></script>
    <!-- built files will be auto injected -->
</body>

</html>

vue 创建一个 platform 文件夹

里面创建一个 index.js

http://dy.163.com/v2/article/detail/DQSGL5PK05492JTS.html

例如:通知(ios 和 网页的使用) ---- Cordova嵌入webview使用(iOS)

https://www.jianshu.com/p/c629b820f914
http://www.pianshen.com/article/5731242536/
https://rensanning.iteye.com/blog/2019289 (必看)
---------------------- 强大的 Cordova 框架 (原生开发和VUE(H5)混合开发)----------------------
Cordova前身是phonegap,而PhoneGap是Nitobi软件公司2008年推出的一个框架,旨在弥补web和iOS之间的不足,使得web和iPhone SDK之间的交互更容易。https://www.jianshu.com/p/c629b820f914

JiaCordova是为了让项目对于Cordova引入更加方便快捷的一个封装式插件,插件中已经集成的关于Cordova跟其一些常用的第三库,对于Cordova的配置模板也进行整理,且封装从服务端下载ZIP包进行解压到沙盒文件夹中,利用Cordova进行请求的功能;最大程度上简化关于Cordova的运用跟学习成本;(https://www.cnblogs.com/wujy/p/6908454.html)

 
https://blog.csdn.net/u011042316/article/details/83828371

Cordova框架中第一个应该掌握的就是这个 deviceready 事件。

Cordova提供的通过HTML5调用Native功能并不是立即就能使用的,Cordova框架在读入HTML5代码之后,要进行HTML5和Native建立桥接,在未能完成这个桥接的初始的情况下,是不能调用Native功能的。在Cordova框架中,当这个桥接的初始化完成后,会调用他自身特有的事件,即deviceready事件。 

js 代码:
document.addEventListener('deviceready', function () {  
  console.log('Device is Ready!');  
  // ....your code  
}, false);  


Promise


子父组件传值

https://blog.csdn.net/wy6250000/article/details/83793400
https://segmentfault.com/a/1190000014381699
https://www.cnblogs.com/sichaoyun/p/6690322.html

https://segmentfault.com/a/1190000010530600?utm_source=tag-newest

vue的父子组件间通信可以总结成一句话:
父组件通过 prop 给子组件下发数据,子组件通过$emit触发事件给父组件发送消息,即 prop 向下传递,事件向上传递。

Prop (常用)

单选
 //单选
        getChecked(item,idx) {
            this.activityColor = true;

           this.list[idx].checked = !this.list[idx].checked
           this.tempArr = this.list.filter(v => v.checked)
            
           if(this.list.length == this.tempArr.length && this.tempArr.length != 0) {
               this.isAll = true
           } else {
               this.isAll = false;               
           }
            // 置灰色
           if (this.tempArr.length == 0 ) {
               this.activityColor = false;
           }
          console.log('6666',this.tempArr.length);
            
                     
        },
全选
 //全选
        allChecked(type) {
             this.activityColor = true;

            if(!type){
                this.list.forEach((item, index)=> {
                    item.checked = true
                    this.tempArr.push(item);

                })
                this.isAll = true
            } else {
                this.list.forEach((item, index)=> {
                    item.checked = false
                })
            }

            this.tempArr = this.list.filter(v => v.checked)

            if(this.list.length == this.tempArr.length && this.tempArr.length != 0) {
               this.isAll = true
           } else {
               this.isAll = false;
               this.activityColor = false;
           }
        },
=号的区别

简单来说就是使用“”时,如果两边类型不同,js引擎会把它们转换成相同类型然后在进行比较,而“=”则不会进行类型转换,因此当两边不是属于同一个类型,肯定不相等。

var a = 0, b = '0';

alert((a == b) + '--' + (a === b))

此时看到的结果为“true–false”
垂直居中
<div data-v-6be20e6e="" class="mask"></div>
// 样式
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 201;
    background: #000;
    opacity: 0.5;
    
<div data-v-6be20e6e="" class="popover-body"><div data-v-6be20e6e="" class="list"><div data-v-6be20e6e="" class="item bd-bottom "> 写日报</div> <div data-v-6be20e6e="" class="item bd-bottom">写周计划</div> <div data-v-6be20e6e="" class="item bd-bottom">写月报</div></div></div>

// 样式
position: absolute;
    top: 50%;
    left: 50%;
    width: 242px;
    height: 150px;
    -webkit-transform: translateX(-50%) translateY(-50%);
    transform: translateX(-50%) translateY(-50%);
    background: #fff;
    border-radius: 5px;
    z-index: 202;

闭包


js去重


使用过滤和数组的区别

this.tempArr = this.list.filter(v => v.checked)
// 效果一样(代码长度可不一样!!!) 

this.list.forEach(item => {
  // 保存在一个临时数组里
  if(item.checked ){
      this.tempArr.push(item);                  
  }
})
左右结构 (左边给个固定宽度,右边给个自适应flex)
.prototypeSampling_page .prototypeSampling_content .space[data-v-3893e4d5] {
    -webkit-box-pack: justify;
    -webkit-justify-content: space-between;
    justify-content: space-between;
}
.block .left {
    -webkit-flex-basis: 100px;
    flex-basis: 100px;
}
.right {   
    display: -webkit-flex;
    display: flex;
}
防抖功能 (示例:搜索)
 // 确认搜索
searchWord() {
    //防抖
    clearTimeout(this.timeId);

    this.timeId = setTimeout(() => {
        this.getConditionModelList();
    }, 300);
},

搜索框(样式)




----------------- 搜索 ----------------------------
 margin-top: 45px;
        // s 不使用公共的样式
        .search-boxs{
            margin-top: 60px;
            background: #fff;
            .inputBox{
                width: 100%;
                padding: 0px 15px 15px 15px;
                display: flex;
                position: relative;

                form{
                    flex: 1;
                    display: flex
                }
                input{
                    flex: 1;
                    height: 28px;
                    border: 1px solid #f5f5f5;
                    border-radius: 16px;
                    outline: none;
                    background: #f5f5f5;
                    text-indent: 30px;
                    font-size: 14px;
                    padding-right: 33px;
                }
                .col-333{
                    color: #333;
                }
                input::-webkit-search-cancel-button {
                    display: none;
                }
                .icon-chaxunx{
                    position: absolute;
                    top: 8px;
                    right: 32px;
                    color: #999999;
                    font-size: 13px;
                }
                .icon-chax{
                    position: absolute;
                    top: 7px;
                    right: 31px;
                    color: #d8d8d8;
                    font-size: 15px;
                }
            }
        }

只要某个item有下划线,其它的没有。应该怎么处理?
分开使用,制定一个公共的 样式,有的就赋值上去。 或使用h5 的样式,指定某个的样式
触摸事件(百度的)
支持vue2.0的面向指令的touch指令,基于touchjs(原百度实现的移动端手势库)
vue2.0之后的要使用next分支才行,之前的使用master分支即可

npm install vue-touch@next --save

import VueTouch from 'vue-touch'

Vue.use(VueTouch,{name:'v-touch'});

其中tap是模拟点击事件,pinch 模拟双指缩放,rorate是模拟旋转手势,swipe模拟快速滑动,drap模拟拖拽,hold表示长按,doubletap模拟双击。

侧滑删除:
https://blog.csdn.net/qq_33026699/article/details/82733574

https://segmentfault.com/a/1190000011062124
js 字符串 json 间的转化
JSON.stringify(this.backObj);
JSON.parse(this.paramsValue));
防止返回多次调用
this.$router.replace({path:'./prototypeSampling'});
搜索-- 防抖动 节流
 <div class="search-box">
      <div class="inputBox">
        <img class="icon-chaxunx" src="../../assets/icon/search.svg" />
        <form action="javascript:return true">
          <input
            type="search"
            placeholder="请输入顾客姓名/手机/产品型号"
            v-model="condition"
            @keyup.prevent.stop="searchWord($event,condition)"
            :class="{'col-333': condition}"
          />
        </form>
        <img
          src="../../assets/img/clear_new.png"
          class="icon-chax"
          v-if="condition.length"
          @click.prevent.stop="clear"
        />
      </div>
    </div>
    
 // --------------------- js --------------------
 searchWord(e,val) {
      console.log('val',val);
      
      if (this.condition || e.keyCode === 13) {
        this.condition = val;
        // --- 防抖 
        let timer = setInterval(() => {
            clearInterval(timer);
            // 发送请求 
            this.downLoading();
          }, 500);       
      }
    },
    
    或者 (性能没那么好)
    
    watch: {
    condition (oldVal, newVal){
      if (newVal != oldVal) {
          let timer = setInterval(() => {
            clearInterval(timer);
            this.downLoading();
          }, 500);
      }
    }
  }

flex

div:nth-of-type(2) {flex-basis: 80px;} 设置第二个弹性盒元素的初始长度为 80 像素:

async

/*** 获取用户消息 */
​  async initPlatform(){
​  }

js some的使用

var hasWasher =  rep[12].some(item=>{
    if(item.baseDataId=='12'){
        return true
    }
})
过滤器的使用

 filters: {
	// 时间显示1位数时前面要加0
    getLocalTime: function(timestamp) {
      var d = new Date(timestamp);
      var date =
        d.getFullYear() + "-" +
        (d.getMonth() + 1 < 10 ? '0' + (d.getMonth() + 1) : d.getMonth() + 1 )+ "-" +
        (d.getDate() <10 ? '0' + d.getDate() : '' + d.getDate() )+ " " +
        (d.getHours() <10 ? '0' +d.getHours() : d.getHours()) +
        ":" +
        (d.getMinutes() <10 ? '0'+d.getMinutes(): d.getMinutes()) +
        ":" +
        (d.getSeconds() < 10 ? '0'+d.getSeconds() : d.getSeconds());
      return date;
    }
  },
  
------------------- 使用 -----------------------
<div class="content-item">
    <label>申请时间:</label>
    <div class="value">{{item.subReportDate | getLocalTime}}</div>
</div>
发送请求
api:
	const api = {    
    	addWeekWorkPlan:     'addWeekWorkPlan',//周计划上报
	}
actions:
    const actions = {
		//周计划上报
      addWeekWorkPlan({commit}, param) {
        return ajax.post(api.addWeekWorkPlan, param);
      },
   }
-------------------------使用场景-----------------------------
this.$store.dispatch('getPromotionActivityDetail', params).then(data => {}

或者 (使用辅助函数)
 methods: {
      ...mapActions([        
        'addWeekWorkPlan'
      ]),
	this.addWeekWorkPlan(param).then(data => {}
}
怎么适配android、ios 0.5像素边框

在移动端有时候,设置 border 0.5 上是有兼容问题的,有些安卓机就是不显示。那么可以:

使用伪类

.item_btn{
    display: inline-block;
    margin-right: 7px;
    width: 86px;
    height: 32px;
    line-height: 32px;
    font-size: 13px;
    text-align: center;
    color: #00b9ff;
    position: relative;
    &::after{
        content: " ";
        position: absolute;
        left: 0;
        right: 0;
        z-index: 2;
        border-radius: 8px;
        width: 200%;
        height: 200%;
        border: 1px solid #00B9FF;
        transform-origin: 0 0;
        transform: scale(0.5, 0.5);
    }
}

使用 高德、百度地图 之间的转化

(坐标转换:https://lbs.amap.com/api/javascript-api/reference/lnglat-to-address#m_AMap.convertFrom)
1、项目里面使用的是 高得地图。
有的模块提使用百度提交, 需要转 百度。(现在优化的 是硬件GPS 转 高德 提交!!!)
2、省略 再转百度,然后提交的步骤。

// 高德转百度后 
tranBaidu(addr, type) {
    console.log('百度转化前的经纬度是:',addr,type);
    var newShopStr = addr.longitude + ',' + addr.latitude;
    console.log('百度转换接口的值:',newShopStr);

    var url = 'http://api.map.baidu.com/geoconv/v1/?' + 'coords=' + newShopStr + '&from=1&to=5&ak=YcbD6LjauYE0HLSwmejmOzTrshR5uAR3';
    var tranBaidu = axios.create();
    tranBaidu.get(url).then(rep => {
        if (rep.status === 200 && rep.data) {

            addr.longitude = rep.data.result[0].x;
            addr.latitude = rep.data.result[0].y;

        } else {
            let errMsg = rep.msg || '转换失败'
            console.log('转换失败' + errMsg)
        }
    }).catch(err => {
        console.log('百度转换接口出错')
        err = err || '百度转换接口出错'
        console.error(err)
        throw(err)
    })
},

2、其它(GPS)经纬度转高德(拿到 经纬度)
// gps坐标转换高德
tranGaode(myAddr) {
    // var myAddr = storage.get('curAddr')
    var gps = [myAddr.longitude, myAddr.latitude]
    AMap.convertFrom(gps, 'gps', (status, result) => {
        if (result.info === 'ok') {
            console.log('先是百度转高德:',gps);

            myAddr.longitude = result.locations[0].M;
            myAddr.latitude = result.locations[0].O;
            this.$store.commit('SETCUR_ADDR', myAddr);
            this.initMap(myAddr)
        }
    });
},

百度地图的 红色标注

需要在自己的样式里面引入的.

例如:
	 .amap-marker-content{
    .icon-map-marker{
      background-image: url("../images/local.svg") ;
      background-position: center center;
      background-repeat: no-repeat;
      color: @white;
      background-size: 26px;
      width: 27px;
      height: 37px;
      text-align: center;
    }
  }

对输入的文字(有特殊字符什么的)处理 – 正则

util.decode(str)

// 封装
 /*
  * 转换特殊字符*/
  /*编码*/
  encode:function(str) {
    var patt=/[\ud800-\udbff][\udc00-\udfff]/g; // 检测utf16字符正则
    str = str.replace(patt, function(char){
      var H, L, code;
      if (char.length===2) {
        H = char.charCodeAt(0); // 取出高位
        L = char.charCodeAt(1); // 取出低位
        code = (H - 0xD800) * 0x400 + 0x10000 + L - 0xDC00; // 转换算法
        return "&#" + code + ";";
      } else {
        return char;
      }
    });
    var entityMap = {
      "&": "&amp;",
      "<": "&lt;",
      ">": "&gt;",
      '"': '&#92;&#34;',
      // "'": '&#39;',
      "/": '&#x2F;',
      "$":'&#36;',
      // "\\":"&#92;&#92;"
    };
    // encodeURIComponent该方法是为了兼容后端不兼容\的问题
    // return encodeURIComponent(String(str).replace(/[&<>"\/$]/g, function (s) {
    //   return entityMap[s];
    // }));
      var delStr =  String(str).replace(/[&<>"\/$]/g, function (s) {
          return entityMap[s];
      });
      // 
      return delStr.replace(/\n/g,'\\n').replace(/\\u00a0|\s+/ig, '');
  },
  /*解码*/
  decode:function (s) {
      // return decodeURIComponent(s);
    if(!s){
      return '';
    }
    var entityMap = {
      "&amp;":"&" ,
      "&lt;":"<" ,
      "&gt;":">" ,
      '&#34;':'"' ,
      // '&#39;': "'" ,
      '&#x2F;':"/",
      '&#36;':'$',
      // "&#92;":"\\"
    };
    // return String(s).replace(/("&amp;"|"&lt;")/g, function (s) {
    //   return entityMap[s];
    // });
    for(let i in entityMap){
      s = s.replace(new RegExp(i,'g'),entityMap[i]);
    }
    var patt =/&#(\w{6}|\d{6});/g;
    s = s.replace(patt,function (code) {
      var char,H,L;
      char =code.replace(/&#/g,'');
      char =char.replace(/;/g,'');
      H = Math.floor((char-0x10000) / 0x400)+0xD800; // 高位
      L = (char - 0x10000) % 0x400 + 0xDC00; // 低位
      return String.fromCharCode(H,L);
    });
    // return decodeURIComponent(s);
      return s;
  },
input 文字缩进
padding-left: 0.5em;
使用rem 和 %
链接:http://caibaojian.com/rem-vs-em.html

rem 和 em 单位是由浏览器基于你的设计中的字体大小计算得到的像素值。
em 单位基于使用他们的元素的字体大小。
rem 单位基于 html 元素的字体大小。
em 单位可能受任何继承的父元素字体大小影响
rem 单位可以从浏览器字体设置中继承字体大小。
使用 em 单位应根据组件的字体大小而不是根元素的字体大小。
在不需要使用em单位,并且需要根据浏览器的字体大小设置缩放的情况下使用rem。
使用rem单位,除非你确定你需要 em 单位,包括对字体大小。
媒体查询中使用 rem 单位
不要在多列布局中使用 em 或 rem -改用 %。
不要使用 em 或 rem,如果缩放会不可避免地导致要打破布局元素
路由守卫
场景: 路由跳转前做一些验证,比如登录验证,是网站中的普遍需求等。

vue-route 提供的 beforeRouteUpdate 可以方便地实现导航守卫。


  beforeRouteLeave(to, from, next) {
	to: Route: 即将要进入的目标 路由对象
	from: Route: 当前导航正要离开的路由
	next(); 
	next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
  },

闭包:或者说”闭包函数“ — 很多高级的应用都是通过闭包才能实现的。

1、它是一个函数。
2、它可以访问 一个函数内部的局部变量。
原理:js中只有函数内部的”子函数“ 才能读取局部变量。
需求:
	怎么从外部读取局部变量?(闭包:就是在一个函数里面再定义一个函数)。
优点:
	1、可以读取函数内部的变量。
	2、让那些变量始终保持在内存中。
注意:(缺点)
	1、保存在内存中。不会被释放,导致性能问题。需要手动释放。
	2、
let 形成了一个块级作用域。
这就是为什么,for 循环的时候定义 for(let i=0;xxx;xxx)的原因了。或post 传参数的时候。
let params = {
    dayDate: this.currentDate,
    sysId: 'mmp',
};
 this.$store.dispatch('getWorkDayDetails', params).then(data => { }).catch(e=>{
    this.$hideLoading();
    this.$toast(e || 'getWorkDayDetails接口出错');
})

block、异步、promise 的使用?


promise

 return Promise.resolve(rep.List);
解构
import { XTextarea, Group, Actionsheet, Popup } from "vux";

slot的使用: 具名插槽、插槽
自定义组件使用

另外slot 插槽还可以定义默认值,如果父组件没有对应的插槽标签,那么deom上显示的是<slot ></slot> 标签里的内容.
//  具名插槽
 <header>
 	<div class="right-con">
 			// 这个 444 是不会显示的(因为有了 具名插槽的存在)
 			<div> 444 </dev>
 			// 如果 right 没有对应的值,就显示 555
            <slot name="right">555</slot>
        </div>
 <header>

路由传参数 https://blog.csdn.net/qq_40851816/article/details/80695124

区别:
传递参数会拼接在路由后面,出现在地址栏
this.$router.push({path: ' 路由 ', query: {key: value}});   参数取值  -- this.$route.query.key

使用这种方式,参数不会拼接在路由后面,地址栏上看不到参数
this.$router.push({name: ' 路由的name ', params: {key: value}})  参数取值  -- this.$route.params.key

监听物理键返回
/** 监听物理返回按钮 */
  beforeRouteLeave (to, from , next) {
      // next(false)//可以通过在这里写逻辑来处理用户点了物理返回之后的操作
      console.log('监听物理返回按钮'); // replace    
      // 清空图片选择相册 记录
      localStorage.removeItem('limitThree');  
        // 清空
        // if(to.name == "cleanseHome"){
          // localStorage.setItem('noRef',true);
          // this.$router.push({name:"createMenu"});
        // }else{
          // localStorage.setItem('noRef',true);
          next();
        // }
  }
过滤器 – 就是筛选掉不想要的,或转化成想要的值。
// 写一个文件或 定义一个过滤方法。
const vFilters = {
    orgFilter: (val) => {
        let returnName = ''
        switch (val) {
            case '10':
                return returnName= '家用空调'
            case '11':
                return returnName = '冰箱'
            case '12':
                return returnName = '洗衣机'
            case '13':
                return returnName = '中央空调'
            case '14':
                return returnName = '环境电器'
            case '15':
                return returnName = '生活电器'
            case '16':
                return returnName = '微清'
            case '17':
                return returnName = '厨房和热水'
            default:
                break;
        }
    }
}
使用过滤器
<span>{{item.organizationId | orgFilter}}</span>
// 显示的ui是 对应的值。

vuex状态管理

1、项目创建后,然后安装vuex,使用命令:npm install vuex --save
2、然后我们执行npm run dev 启动项目。
3、然后我们在项目的src目录下新建一个目录store。
4、必须 引入import vue 和 vuex ,然后 Vue.use(xxx)

说明:

1、state 数据源
2、getter 相当于 vue中的computed 计算属性。(getter可以用于监听、state中的值,并返回计算后的结果)

使用:

import { mapGetters, mapActions } from "vuex";
 methods: {
    ...mapActions([
      "getCustomerInfoList", // 查询用户列表信息
      "seizeCustomer", // 抢占客户成功
      "getCustomerInfo", // 清洗活动状态
    ]),
    }
    // 调用
    var param = {
        customerId: id
      };
    this.seizeCustomer(param)
    .then(rep => {

    }).catch(e => {          
      this.$toast(e || "网络出小差,请稍后重试!");
    }); 
    // -------------- 相当于 ----------------------
     this.$store.dispatch('seizeCustomer', params).then(rep => {
         
     }).catch(e => {
        this.$toast(e || '网络出小差,请稍后重试!')
     })

vuex

this.$store.commit('SET_TERMINAL_ID', id);  // 异步

components

import searchPage from "../searchPage";
import cancelCauseVue from "../../components/pages/cancelCause";

components: {
    searchPage,
    cancelCauseVue
  },
监听搜索(watch)
variable.less 文件(设置全局的变量)

// 变量文件
@border-base: #e8e8e8;
@bd-base: #f2f2f2;
// iconfont 字体
@import '../icon/iconfont.css';

@border-base: #e1e1e1; 
@col-666: #666666; 
@col-e1: #e1e1e1; 
@col-333: #333333; 
@col-999: #999999; 
@skyBlue: #11BFF4; 
@white: #ffffff; 
@col-f5: #f5f5f5; 
@col-pink: #FF7EA9; 
@col-d8: #D8D8D8;
// -------------- less 文件 -------------
@import "./variable.less";
// 设置
.col-333{ 
  color: @col-333; 
} 
// 传 关键字
search: this.condition, // 搜索 (获取搜索框的)
// ----------------------------------
<input
    type="search"
    :placeholder="keyword?keyword:placeholder"
    v-model="keyword"
    @keyup.prevent.stop="searchWord($event,keyword)"
    class='默认颜色'
    :class="{'col-333': condition}"
>
// -----------------------------------                       
 watch: {
    keyword(oldVal, newVal) {
      if (newVal != oldVal) {
        let timer = setInterval(() => {
          clearInterval(timer);
          this.downLoading();
        }, 500);
      }
    }
  }
生命周期
 // 点击后拿到数据返回给下单地址
  beforeRouteLeave (to, from, next) {
    if (to.name === 'home') {
      to.query.temp = '这里是参数,选中后的地址'
    }
    console.log(to)
    console.log(from)
    next()//一定不要忘记写
  },

图层:

 <div class="mask" v-if="showDialog" @click="showDialog = false"></div>
 <div class="dialog" v-if="showDialog"></div>
 
 注意: 设置 层级
  z-index: 999;
图片:(动态加载)需要 :src
:class="{'col-333': condition}"
-----------------------------------------------------
<img :src="items.imgUrl?items.imgUrl : noImgdata">
// 引入 图片(防止在打包的时候没有加载进来)
import noImgdata from '../assets/image/no_imgdata.png'
// 或者 定义一个属性 xxx,使用 require ,再绑定。
addCusImg:require("../../assets/image/新增潜在客户@2x.png"),

  或者:
  <img class="shopImg" :src="showimg(item.picture)" alt>
// 使用
// 如果有多张图片返回选第一张(门店)
showimg(userImgString){
  if(userImgString&&userImgString.split(",").length>0){
    return userImgString = userImgString.split(",")[0];
  } else {
    return userImgString;
  }

},

转化(数字转文字)

// 请假类型转换
    changeStatus(val) {
      switch (val) {
        case "轮休":
          return "0";
          break;
        case "闭店装修":
          return "5";
          break;
        case "产假":
          return "6";
          break;
        default:
          break;
        }
    }
   使用:
  this.changeStatus(this.typeLeave),

路由跳转和传值的几种方式。


谷歌(window)跨域

右击 --> 属性(空格)--> 添加下面的
--disable-web-security --user-data-dir=C:\MyChromeDevUserData,--user-data-dir
在C盘: 创建一个文件夹 MyChromeDevUserData

防抖和节流 (https://juejin.im/post/5cce5380f265da03826129bf?utm_source=gold_browser_extension)

Debounce 防抖
 原理:当连续触发某个方法的时候,该方法就不执行。(触发结束后再执行)

$nextTick

对于 Vue 来说,从数据变化到执行 DOM 更新,这个过程是异步的,发生在下一个 tick 里。
Vue.nextTick()
    .then(function () {
    	// DOM 更新了
	})
分割(split)、拼接
subjectValue.split(/.jpgmideaMmp2016/g);
splice 删除

字体 (em)em相对于父元素,rem相对于根元素。

em 指字体高,任意浏览器的默认字体高都是16px。
所以未经调整的浏览器都符合: 1em=16px。那么12px=0.75em, 10px=0.625em。
换算:
	为了简化font-size的换算,需要在css中的body选择器中声明Font-size=62.5%,这就使em值变为 16px*62.5%=10px。
    这样12px=1.2em, 10px=1em。
总结:
	只需要将你的原来的px数值除以10,然后换上em作为单位就行了。
需要注意:
	1. em的值并不是固定的;
	2. em会继承父级元素的字体大小。
重写步骤:
1. body选择器中声明Font-size=62.5%;
2. 将你的原来的px数值除以10,然后换上em作为单位;
	
像素(px):用于元素的边框或定位。

em/rem:用于做响应式页面,不过我更倾向于rem,因为em不同元素的参照物不一样(都是该元素父元素),所以在计算的时候不方便,相比之下rem就只有一个参照物(html元素),这样计算起来更清晰。

分页

console.log("提交参数:。。。。", params);
      this.showLoading();
      this.$store.dispatch("getPossibleCustList", params).then(data => {
        console.log("潜在客户列表查询结果:", data);
        this.hideLoading();
        if(data.retcode == "SUCC"){
          if(data.custList.length <=0){
                 this.$toast("暂时没有数据哦!");
                   // 清空
                   this.userList = [];
              }
              // 分页 
              if (this.page.pageNum === 1) {
                  this.userList = [];
              }
              if (data.custList && data.custList.length < this.page.pageSize) {
                  this.page.isMore = false;
              } else {
                  this.page.isMore = true;
                  this.page.pageNum++;
              }
             this.userList = this.userList.concat(data.custList);
        } else {
          this.userList = [];
          this.$toast(data.errmsg || "查询不到相关信息");
        }
      }).catch(err => {
        this.Toast(err.msg || "接口出错!");
        this.hideLoading();
      });

打电话

   <a :href="'tel:'+item.respondentPhone">{{item.respondentPhone}}</a>
手机校验
// 手机号码、电话号码校验
  checkPhone(mobile) {
                // var tel = /^0\d{2,3}-?\d{7,8}$/;
                var tel = /^([0-9]{3,4}-)?[0-9]{7,8}$/;
                // var phone = /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1}))+\d{8})$/;
                var phone = /^1[3456789][0-9]{9}$/;
                if (phone.test(mobile) || tel.test(mobile)) {
                    return true;
                } else {
                    this.Toast('请输入有效的手机号码!');
                    return false;
                }
   },
去掉 input 禁止后的背景颜色
background:transparent;

scroller 组件

独立的 样式
.my-scroller{
    background-color: @white;
    position: absolute;
    top: 146px;
    right: 0;
    left: 0;
    bottom: 0;
    overflow: hidden;
 }

scroller

 // 一定要设置,否则出错
            .my-scroller {
                position: absolute;
                top: 10px;
                bottom: 0px;
                left: 0;
                right: 0;
                overflow: hidden;
            }
修改后台返回顺序
<div class='title omit' v-for="item in v.subjectList" v-if="type==1">
<div v-if="item.subjectSeq == 2">{{item.subjectValue}}</div>
</div>
<div class='title omit' v-for="item in v.subjectList" v-if="type==1">
<div v-if="item.subjectId == 201903">{{item.subjectValue}}</div>
</div>
地址选择 (使用 静态.js)
<!--/**
* @component 地区选择器组件
* @name selAddress
* @author Jacky
* @props
    -- isShow:Boolean false 是否显示地区选择器组件
    -- isReset: Boolean false 是否刷新数据
    -- isClick: 当前层级
    -- provinceName: 选择的省,
    -- cityName: 选择的市,
    -- countyName: 县/区,
    -- streetName: 街道,
    -- curLevelList: Array 当前层级的数据,
    -- getAdrr, 选择当前层级的地区
    -- cancel, 隐藏组件需要传递的事件
    -- dealProvince, 处理每次打开组件时默认显示省份的数据
    -- dealOtherArea, 处理除省以外的地区数据
*/-->
<style lang="less" scoped>
    .addr_parrent_box {
        overflow: hidden;
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        background: rgba(0, 0, 0, .7);
        z-index: 9999;
        font-family: PingFangSC-Regular;
        font-size: 14px;
        .addr_box {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            height: 300px;
            background: #ffffff;
            border-radius: 4px 4px 0 0;
            .describe {
                position: relative;
                width: 100%;
                line-height: 50px;
                font-size: 14px;
                text-align: center;
                color: #666666;
            }
            .close_box {
                position: absolute;
                top: 50%;
                right: 5px;
                width: 40px;
                height: 40px;
                transform: translateY(-50%);
            }
            .close_pupo {
                position: absolute;
                top: 50%;
                left: 50%;
                font-size: 10px;
                transform: translateX(-50%) translateY(-50%);
            }
        }
        .select_area {
            padding: 0 15px;
            width: 100%;
            line-height: 47px;
            .selected_obj {
                overflow: hidden;
                display: inline-block;
                margin-right: 20px;
                max-width: 60px;
                text-overflow: ellipsis;
                white-space: nowrap;
                color: #00B9FF;
                vertical-align: middle;
                border-bottom: 2px solid #00B9FF;
            }
            .font_color {
                color: #333;
                border-bottom: none;
            }
        }
        .select_content {
            position: relative;
            width: 400%;
            height: 210px;
            .content_box_list {
                display: flex;
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                justify-content: space-around;
                // transform: translate3d(0, 0, 0);
                // transition: transform .2s ease;
                // -moz-transition: transform .2s ease; /* Firefox 4 */
                // -webkit-transition: transform .2s ease; /* Safari and Chrome */
                // -o-transition: transform .2s ease; /* Opera */
                .content_box {
                    flex: 1;
                    height: 100%;
                    line-height: 21px;
                    color: #333333;
                    .item_box_list::-webkit-scrollbar {
                        display: none;
                        width: 0;
                    }
                    .item_box_list {
                        -webkit-overflow-scrolling: touch;
                        overflow-y: scroll;
                        padding: 0 15px;
                        height: 100%;
                        .item_box {
                            line-height: 50px;
                        }
                    }
                }
            }
        }
    }
    @-webkit-keyframes fadeInUp {
        from {
            opacity: 0;
            // transform: translate3d(0, 292px, 0);
        }
        100% {
            opacity: 1;
            transform: none;
        }
    }
    @keyframes fadeInUp {
        from {
            opacity: 0;
            transform: translate3d(0, 292px, 0);
        }
        100% {
            opacity: 1;
            transform: none;
        }
    }
    .fadeInUp {
        transform: translate3d(0, 0, 0) !important;
    }
    .slideLeftRight_2 {
        transform: translate3d(-25%, 0, 0) !important;
    }
    .slideLeftRight_3 {
        transform: translate3d(-50%, 0, 0) !important;
        animation-delay:.2s;
    }
    .slideLeftRight_4 {
        transform: translate3d(-75%, 0, 0) !important;
        animation-delay:.4s;
    }
</style>
<template>
    <div class="addr_parrent_box" v-if="isShow" @click="cancel">
        <div class="addr_box" @click.prevent.stop>
            <div class="describe">
                请选择所在地区
                <span class="close_box" @click="cancel">
                    <i class="close_pupo icon-chax1 iconfont"></i>
                </span>
            </div>
            <div class="select_area bd-top bd-bottom">
                <span class="selected_obj" :class="provinceName?'font_color':''">{{ provinceName? provinceName : '请选择' }}</span>
                <span class="selected_obj" :class="cityName?'font_color':''" v-if="provinceName">{{ cityName? cityName : '请选择' }}</span>
                <span class="selected_obj" :class="countyName?'font_color':''" v-if="cityName">{{ countyName? countyName : '请选择' }}</span>
                <span class="selected_obj" v-if="countyName">{{ streetName? streetName : '请选择' }}</span>
            </div>
            <div class="select_content" :class="{'fadeInUp':isShow}">
                <ul class="content_box_list" :class="{'slideLeftRight_2':isClick===2, 'slideLeftRight_3':isClick===3, 'slideLeftRight_4':isClick===4}">
                    <li class="content_box">
                        <ul class="item_box_list">
                            <li class="item_box bd-bottom"  v-for="(item, index) in curLevelList" :key="index" @click="getAd(2, item, index)">{{ item.regionName }}</li>
                        </ul>
                    </li>
                    <li class="content_box">
                        <ul class="item_box_list">
                            <li class="item_box bd-bottom" v-for="(item, index) in curLevelList" :key="index" @click="getAd(3, item, index)">{{ item.regionName }}</li>
                        </ul>
                    </li>
                    <li class="content_box">
                        <ul class="item_box_list">
                            <li class="item_box bd-bottom" v-for="(item, index) in curLevelList" :key="index" @click="getAd(4, item, index)">{{ item.regionName }}</li>
                        </ul>
                    </li>
                    <li class="content_box">
                        <ul class="item_box_list">
                            <li class="item_box bd-bottom" v-for="(item, index) in curLevelList" :key="index" @click="getAd(5, item, index)">{{ item.regionName }}</li>
                        </ul>
                    </li>
                </ul>
            </div>
        </div>
    </div>
</template>
<script>
    import addrData from '../js/addressJson.js';
    export default {
        data() {
            return {
                isClick: 1,
                provinceName: '',
                cityName: '',
                countyName: '',
                streetName: '',
                curLevelList: [],
                selectAddrData: [],
                currentLevel: 1
            }
        },
        props: {
            isShow: {
                type: Boolean,
                default: false
            },
            isRest: {
                type: Boolean,
                default: false
            }
        },
        activated() {
            this.dealProvince()
        },
        methods: {
            // 取消选择
            cancel() {
                this.currentLevel = 1
                this.$emit('cancelAddr')
            },
            // 选择省市区
            getAd(type, item, ind) {
                if(this.currentLevel>=type) return;
                this.getAdrr(type, item, ind)
            },
            getAdrr(type, item, ind) {
                switch (type) {
                    case 2:
                        this.provinceName = item.regionName;
                        this.cityName = '';
                        this.countyName = '';
                        this.streetName = '';
                        this.selectAddrData.push(item);
                        this.dealOtherArea(item);
                        this.currentLevel = 2;
                        break;
                    case 3:
                        this.cityName = item.regionName;
                        this.countyName = '';
                        this.streetName = '';
                        this.selectAddrData.push(item);
                        this.dealOtherArea(item);
                        this.currentLevel = 3;
                        break;
                    case 4:
                        this.countyName = item.regionName;
                        this.streetName = '';
                        this.selectAddrData.push(item);
                        this.dealOtherArea(item);
                        this.currentLevel = 4;
                        break;
                    case 5:
                        this.streetName = item.regionName;
                        var selData = this.provinceName + this.cityName + this.countyName + this.streetName;
                        this.selectAddrData.push(item);
                        this.dealOtherArea(item);
                        this.currentLevel = 1;
                        this.$emit('selFinish', selData, this.selectAddrData);
                        break;
                    default:
                        break;
                }
                this.isClick = type;
            },
            // 处理打开该组件时展示的是省的数据
            dealProvince() {
                this.curLevelList = [];
                for (var key in addrData) {
                    var obj = {}
                    if (key.length == 3) {
                        obj.regionName = addrData[key][0];
                        obj.regionId = key
                        this.curLevelList.push(obj);
                    }
                }
            },
            // 处理非省份的数据
            dealOtherArea(preItem) {
                this.curLevelList = [];
                for (var key in addrData) {
                    var obj = {}
                    if (preItem.regionId == addrData[key][1]) {
                        obj.regionName = addrData[key][0];
                        obj.regionId = key
                        this.curLevelList.push(obj);
                    }
                }
            }
        },
        watch: {
            isRest(newVal, oldVal) {
                if(newVal) {
                    this.isClick = 1;
                    this.provinceName = '';
                    this.cityName = '';
                    this.countyName = '';
                    this.streetName = '';
                    this.selectAddrData = [];
                    this.dealProvince();
                }
            }
        }
    }
</script>

使用

import selectAddress from "../../components/pages/selAddress";
 components: {
    showTackPic,  
    selectAddress,
    autoInput
  
  },

<select-address
      :isShow="showAddr"
      @cancelAddr="cancelAddr"
      @selFinish="selFinishAddr"
      :isRest="isRest"
    ></select-address>
 /** 选择地区完成 调用(这里的id 会和 地址关联) */
    selFinishAddr(showData, reportData) {
      this.addr = showData;
      this.provinceId = reportData[0].regionId;
      this.cityId = reportData[1].regionId;
      this.districtId = reportData[2].regionId;
      this.townId = reportData[3].regionId;
      this.provinceName = reportData[0].regionName;
      this.cityName = reportData[1].regionName;
      this.districtName = reportData[2].regionName;
      this.townName = reportData[3].regionName;
      this.cancelAddr();
    },

 // 取消选择 地址
    cancelAddr() {
      this.isRest = true;
      this.showAddr = false;
    },

搜索vue

<style lang="less" scoped>
@import "../../../assets/style/pages/retails/kitchenFever/searchTemp";
</style>
<style lang="less">
input {
  font-size: 14px;
  color: #999;
  font-family: PingFangSC-Regular;
}

.searchItem{
    height: 40px;
    line-height: 40px;
    padding-left: 15px;
    border-bottom: 0.5px solid #ccc;
}
</style>
<template>
    <div class="searchTemp_page">
        <div class="result_search_box bd-bottom">
            <div class="result_back"  @click="cancelSearch">
                <img src="../../../assets/images/retails/headerBack.svg" alt="">
            </div>
            <div class="search-input">
                <i class="iconfont icon-sousuo"></i>
                <form action="javascript:return true">
                    <input type="search"  ref="input" v-model="keyword" :class="{'font-333': keyword}" @keyup="searchWordBtn(keyword)" :placeholder="placeholder"  />
                </form>
                <div v-if="keyword.length" class="icon-chaxSvg" @click.prevent.stop="clear">
                    <img src="../../../assets/images/retails/chax.svg" alt="" class="checked-img">
                </div>
            </div>
            <div class="result_cancel" @click="searchWordBtn(keyword)">搜索</div>
        </div>
        <!-- <form action="javascript:return true">
            <div class="search-header bd-bottom">
                <div class="back" @click="cancelSearch">
                    <img src="../../../assets/images/indexHome/header-back.svg" alt="" >
                </div>
                <i class="iconfont icon-sousuo"></i>
                <div class="search-input">
                    <input type="search" ref="input" v-model="keyword" :class="{'font-333': keyword}" @keyup.prevent.stop="searchWord($event, keyword)" :placeholder="placeholder" />
                    <i v-if="keyword.length" class="icon-chaxSvg" @click.prevent.stop="clear">
                        <img src="../../../assets/images/retails/chax.svg" alt="" class="checked-img">
                    </i>
                </div>
                <span class="cancel-btn" @click="searchWordBtn(keyword)">搜索</span>
            </div>
        </form> -->


        <div  class="history" ref="history" v-if="!showSearch">
            <div class="bd-bottom">
                <div class="history-header">
                    <div class="title">历史搜索</div>
                    <!-- <div class="clean-btn  iconfont icon-lajitongx" @click.stop="cleanHistory"></div> -->
                    <div class="clean" @click.stop="cleanHistory">清除记录</div>
                </div>
                <div v-if="searchHistory.length" class="history-content">
                    <!--  @click="toSearch(item)" -->
                    <div class="history_item" v-for="(item,idx) in tempArr" :key='idx' >
                        <span @touchstart="start(item)" @touchmove="move" @touchend="end(item, idx)">{{item.dataName}}</span>
                        <!-- <i class="iconfont icon-chax" @click.prevent.stop="clearSearchHistory(item)"></i> -->
                        <div class="shanchu" @click.prevent.stop="clearSearchHistory(idx)" v-if="item.hasCha">
                            <img src="../../../assets/images/retails/shanchu.png" alt="">
                        </div>
                    </div>
                </div>
            </div>

             <div class="hot-Search">
                <div class="hot-Search-title">大家都在卖</div>
                <div class="hot-Search-detail">
                    <span @click="toSearch(item)" v-for="item in hotSearchDetali" :key='item'>{{item}}</span>
                </div>
            </div>
        </div>


        <div v-if="showSearch" class="searchList">
            <div v-for="item in showSearchList" :key="item" class="searchItem" @click="goSearchDetail(item)">
                {{item}}
            </div>
        </div>

        <searchResult :show="showResult" :keyword="keyword" @cancelResult="cancelResult"></searchResult>
    </div>
</template>
<script>
import searchResult from '../retailHome/searchResult.vue'
export default {
    data() {
        return {
            placeholder: "输入关键词搜索",
            searchHistory: [],
            keyword: '',
            productionList: [],
            showSearch: false,
            searchList: [],  //搜索页
            showSearchList: [], //模糊搜索结果
            hotSearchDetali:[],
            tempArr: [],
            longClick:0,  // 长按标志
            timeOutEvent: 0,  // 计时器
            showResult: false,
            keyword: '',
        };
    },
    components: { searchResult },
    watch: {
        keyword(newVal,oldVal){
            this.searchMthod(newVal);
        }
    },

    methods: {
        cancelResult(val) {
            this.keyword = '';
            this.showResult = false;
        },
        // 解决部分机型点击无效
        start(item) {
            var that = this;
            this.longClick=0;
            this.timeOutEvent =setTimeout(function(){
                that.longClick=1;
            },500)
        },
        move(e) {
            clearTimeout(this.timeOutEvent);
            this.timeOutEvent = 0;
            e.preventDefault();
        },
        end(item, i) {
            clearTimeout(this.timeOutEvent);
            if(this.timeOutEvent!=0 && this.longClick==1){
                this.$set(item, 'hasCha', true)
            }
            if(this.timeOutEvent!=0 && this.longClick==0){
                this.toSearch(item.dataName)
            }
            return false;
        },
        //跳转搜索结果页
        goSearchDetail(keyword){
            this.searchHistoryMethod(keyword);
            // this.$router.$replace({path:'/searchResult',query:{keyword}})
            this.toSearch(keyword);
        },

        cleanHistory(){
            this.searchHistory = [];
            localStorage.removeItem('searchHistory');
        },
         //点击搜索键查找
        searchWordBtn(keyword) {
            // this.$refs['input'].blur();
            console.log(12222222)
            if(this.keyword){
                consooe.log(22222333445)
                this.searchHistoryMethod(keyword);
                this.toSearch(keyword);
            }
            this.searchMthod(keyword);
        },
        //点击历史记录去到搜索页
        toSearch(keyword){
            // this.keyword = keyword;
            // this.$router.push({path:'/searchResult',query:{keyword}})
            this.keyword = keyword
            this.showResult = true
        },
        //回车键查找
        searchWord(e, keyword) {

            if(e.keyCode == 13 && keyword != ''){
                this.searchHistoryMethod(keyword);
                this.toSearch(keyword);
            }

            this.searchMthod(keyword);

        },
        //点击搜索键查找
        searchWordBtn(keyword) {
            if(this.keyword){
                this.searchHistoryMethod(keyword);
                this.toSearch(keyword);
            }

            this.searchMthod(keyword);

        },

        //存入缓存,且只存入9个最新搜索记录
        searchHistoryMethod(keyword){
            this.searchHistory.unshift(keyword);
            var temp = this.searchHistory;
            let searchTemp = [] //做搜索记录去重
            for(var i=0 ; searchTemp.length < 9 && i < temp.length ; i++){
                    if( searchTemp.indexOf(temp[i]) == -1){
                    searchTemp.push(temp[i]);
                    }
            }
            this.searchHistory = searchTemp;
            localStorage.setItem('searchHistory',searchTemp);
        },

        searchMthod(keyword){
            this.showSearchList = [];
            if(this.keyword == ''){
                this.showSearch = false;
            }else{
                this.showSearch = true;
                //历史上报记录
                if(this.searchList && this.searchList.length){
                    this.searchList.map(item => {
                        if(item.toLowerCase().indexOf(keyword.toLowerCase()) != -1){
                            this.showSearchList.push(item);
                        }
                    })
                }else{
                    this.showSearchList = [];
                }
            }
        },

        clear() {
            this.keyword = "";
            this.showSearch = false;
        },

        clearSearchHistory(idx){
            // this.searchHistory = this.searchHistory.filter(item => {
            //     return item != keyword
            // })
            this.searchHistory.splice(idx, 1)
            localStorage.setItem('searchHistory',this.searchHistory);
        },

        cancelSearch() {
            this.showSearch = false;
            this.$router.go(-1);
        },

    },
    activated() {
        let hotSearchList = localStorage.getItem('hotSearch') || []
        if(hotSearchList){
            this.hotSearchDetali = JSON.parse(hotSearchList)
        }

        let searchStr = localStorage.getItem("searchHistory");
        if(searchStr){
            this.searchHistory = searchStr.split(',');

            this.searchHistory.forEach((item, idx) => {
                let obj = {}
                obj.dataName = item
                obj.hasCha = false
                this.tempArr.push(obj)
            })
        }else{
            this.searchHistory = [];
        }

        this.searchList = JSON.parse( localStorage.getItem('searchList') );
    },
    deactivated(){
      this.keyword = '';
      this.productionList = []
      this.tempArr = []
    }
}
</script>

简书:光明程辉
Logo

前往低代码交流专区

更多推荐