vue 笔记一
computed property based on the prop’s value.避免直接更改道具一个为解决此问题的简单模式此错误是什么意思,什么原因造成的为什么改变道具是一种反模式使用时如何避免这种情况 v-model非主父子传值https://juejin.im/entry/59b0b36d6fb9a0247a611115调试 vconsolenpm insta...
工作中总结或记录的一些记录。
非主父子传值
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 = {
"&": "&",
"<": "<",
">": ">",
'"': '\"',
// "'": ''',
"/": '/',
"$":'$',
// "\\":"\\"
};
// 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 = {
"&":"&" ,
"<":"<" ,
">":">" ,
'"':'"' ,
// ''': "'" ,
'/':"/",
'$':'$',
// "\":"\\"
};
// return String(s).replace(/("&"|"<")/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>
简书:光明程辉
更多推荐
所有评论(0)