vue开发一些常遇见的问题

13 篇文章 0 订阅
9 篇文章 0 订阅

1、显示富文本的内容,自动换行样式,文本超出

<div class="introduction" v-html="introduce"></div>


.introduction {
        font-size: 16px;
        font-weight: 400;
        color: #666666;
        letter-spacing: 1px;
        margin-top: 10px;
        word-wrap:break-word; // 主要就是这两行
        word-break:normal; // 主要就是这两行
 }

2、打开新的页面窗口

toComplete() {
    let routeData = this.$router.resolve({
      path: '/questionnaire',
    })
	window.open(routeData.href, '_blank')
}

3、关闭新开窗口,回到老的页面并刷新老页面

if (window.close) {
     // For IE and Firefox
     window.opener.location.reload() // 刷新老页面
     window.close() // 关闭新窗口
   } else {
    // For Chrome and Safari
   window.open('', '_self', '')
   window.opener.location.reload()
   window.close()
}

4、倒计时

data() {
	countdown: 3 // 倒计时多少s
}

startCountdown() { // 倒计时方法
  let timer = setInterval(() => {
    if (this.countdown > 0) {
       this.countdown -= 1
    } else {
       clearInterval(timer)
    }
  }, 1000)
}

5、背景透明度

      .one {
        color: #e88f21;
        background-color: rgba(232, 143, 33, 0.2); // .2就是透明度
      }

6、数据更新dom没有更新

this.$forceUpdate();

7、获取前几天或者后几天的日期

    getDate() {
      // 创建一个空数组来存储日期
      let dates = [];
      // 获取当前日期
      let now = new Date();
      // 循环获取最近 7 天的日期
      for (let i = 0; i < 7; i++) {
        // 获取当前日期的时间戳
        let timestamp = now.getTime();
        // 计算 i 天前的时间戳
        let dayTimestamp = 24 * 60 * 60 * 1000; // 一天的毫秒数
        let iDayAgoTimestamp = timestamp + i * dayTimestamp; // 前七天还是后七天,在这里控制加还是减
        // 转换为日期对象
        let date = new Date(iDayAgoTimestamp);
        // 格式化日期为 "yyyy-MM-dd" 的字符串并存入数组
        let year = date.getFullYear();
        let month = ("0" + (date.getMonth() + 1)).slice(-2);
        let day = ("0" + date.getDate()).slice(-2);
        dates.push(year + "-" + month + "-" + day);
      }
      this.dateAfter.forEach((item, index) => {
        item.date = dates[index]
      })
    }

8、获取指定天数的日期

function getTheSpecifiedDate(date, theOtherDay) {
	let myDate = new Date(date); //获取今天日期
	myDate.setDate(myDate.getDate() - theOtherDay); //获取指定前几天的日期
	const Y = myDate.getFullYear()
	const M = myDate.getMonth() + 1 < 10 ? '0' + (myDate.getMonth() + 1) : myDate.getMonth() + 1
	const D = myDate.getDate()
	let dateGet = `${Y}-${M}-${D}`
	return dateGet
}

9、根据身份证计算年龄

function analyzeIDCard(IDCard) {
	let age = 0,
		yearBirth, monthBirth, dayBirth;
	//获取用户身份证号码
	let userCard = IDCard;
	//如果身份证号码为undefind则返回空
	if (!userCard) {
		return age;
	}
	let reg = /(^\d{15}$)|(^\d{17}([0-9]|X)$)/; //验证身份证号码的正则
	if (reg.test(userCard)) {
		if (userCard.length == 15) {
			let org_birthday = userCard.substring(6, 12);
			//获取出生年月日
			yearBirth = "19" + org_birthday.substring(0, 2);
			monthBirth = org_birthday.substring(2, 4);
			dayBirth = org_birthday.substring(4, 6);
		} else if (userCard.length == 18) {
			//获取出生年月日
			yearBirth = userCard.substring(6, 10);
			monthBirth = userCard.substring(10, 12);
			dayBirth = userCard.substring(12, 14);
		}
		//获取当前年月日并计算年龄
		let myDate = new Date();
		let monthNow = myDate.getMonth() + 1;
		let dayNow = myDate.getDate();
		let age = myDate.getFullYear() - yearBirth;
		if (monthNow < monthBirth || (monthNow == monthBirth && dayNow < dayBirth)) {
			age--;
		}
		//返回年龄
		return age;
	} else {
		return ''
	}
}

10、根据身份证获取性别

    getGenderByIdNumber(idNumber) {
      if (idNumber) {
        let genderCode; // 性别代码
        if (idNumber.length == 18) { // 二代身份证号码长度为18位(第17位为性别代码)
          genderCode = idNumber.charAt(16);
        } else if (idNumber.length == 15) { // 一代身份证号码长度为15位(第15位为性别代码)
          genderCode = idNumber.charAt(14);
        }
        if (genderCode && !isNaN(genderCode)) {
          // 两代身份证号码的性别代码都为男奇女偶
          if (parseInt(genderCode) % 2 == 0) {
              return '女';
          }
          return '男';
        }
      }
    },

11、图片链接放到浏览器可以打开,但是在img标签里面却无法打开,原因图片的链接是第三方地址,所以在有些浏览器可以会不兼容,导致不显示图片,解决方案加上//images.weserv.nl/?url=

<img class="image-show" src="//images.weserv.nl/?url=https://lmg.jj20.com/up/allimg/tp01/1ZZQ20QJS6-0-lp.jpg" alt="">

12、后端返回文件流,前端处理下载excel

export function getExcel(data) { // 接口
  return request({
    url: '/Test/downloadOrder',
    method: 'POST',
    data,
    responseType: 'blob', // 接受类型
  })
}

// 下载请求
getExcel(state.formList).then((res) => {
  const blob = new Blob([res], { type: 'application/vnd.ms-excel' }) // 构造一个blob对象来处理数据,并设置文件类型
  if (window.navigator.msSaveOrOpenBlob) {
    //兼容IE10
    navigator.msSaveBlob(blob, '订单列表')
  } else {
    const href = URL.createObjectURL(blob) //创建新的URL表示指定的blob对象
    const a = document.createElement('a') //创建a标签
    a.style.display = 'none'
    a.href = href // 指定下载链接
    a.download = '订单列表.xlsx' //指定下载文件名
    a.click() //触发下载
    URL.revokeObjectURL(a.href) //释放URL对象
    state.excelLoading = false
  } // 这里也可以不创建a链接,直接window.open(href)也能下载
})

13、input输入框无法输入的时候

// 第一种方案
@input="changeValue"
changeValue() {
	this.$forceUpdate()
}

// 第二种,可能是在table中,你需要将数据开始就遍历加入字段
this.tableData = res.data.list.map((item) => {
    item.enterpriseName = item.name
    item.enterpriseId = item.id
    item.isSelect = false
    item.enrollNumber = ''
    return item
})

14、循环生成el-form,校验必填项

      <div v-for="(item, index) in resultArr" :key="index">
        <el-form
          :ref="
            (el) => {
              if (el) formRef[index] = el
            }
          "
          class="title-form"
          :inline="false"
          label-position="left"
          label-width="80px"
          :model="item"
          :rules="rules"
        >
          <el-form-item class="result-title" :label="'结果' + (index + 1)">
            <el-button type="primary" @click="delResult(index)">
              删 除
            </el-button>
          </el-form-item>
          <el-form-item label="分数范围" prop="minFraction">
            <div class="score">
              <el-input
                v-model="item.minFraction"
                clearable
                placeholder=""
                style="width: 150px"
              />
              <div style="margin: 0 20px"></div>
              <el-input
                v-model="item.maxFraction"
                clearable
                placeholder=""
                style="width: 150px"
              />
            </div>
          </el-form-item>
          <el-form-item label="测评结果" prop="details">
            <vab-quill
              v-model="item.details"
              :min-height="400"
              :options="configOptions_2"
            />
          </el-form-item>
        </el-form>
      </div>

校验必填项

        let isPass = true
        state.resultArr.forEach((item, index) => {
          state.formRef[index].validate(async (valid) => {
            if (!valid) {
              isPass = false
              console.log(123, isPass)
              return
            }
          })
          if (!isPass) throw new Error('退出forEach循环!')
        })
        if (isPass) emit('resultNext', state.resultArr)

vue2中动态添加

// :ref="'parameters' + index" 主要是这个
<div class="ground-user" v-for="(item, index) in parameters" :key="index">
            <el-form class="group-leader" :model="item" :rules="registerRules" label-position="top" :ref="'parameters' + index">
              <el-form-item label="成员姓名:" label-width="80px" prop="name">
                <el-input v-model="item.name" placeholder="成员姓名" clearable></el-input>
              </el-form-item>
            <i class="el-icon-delete" style="padding-top: 20px;cursor: pointer;padding-left: 20px" v-if="parameters.length > 1" @click="delParameters(index)"></i>
          </div>

// 校验
      this.parameters.forEach((item, index) => {
        this.$refs['parameters' + index][0].validate((valid) => {
          if (!valid) {
            showStatus = true
          } else {
            return false;
          }
        })
      })

15、两数组根据对象id去重

export function repeatArr(arr, arr1) {
	let arrs=[...arr,...arr1]
	//根据id去重
	let map=new Map()
	for(let item of arrs){
			if(!map.has(item.id)){
					map.set(item.id,item)
			}
	}
	let newArr = [...map.values()]; //把map中所有的值取出来放进数组
	return newArr
}

16、element ui中遇到时间、级联选择等等,数组有数据,但是视图不更新问题,应该使用push,而不是直接赋值

	getBeforeTwo(time) {
      this.signInTime = []
      let currentTime = new Date(time)
      let twoHoursAgo = currentTime.setHours(currentTime.getHours() - 2)
      this.signInTime.push(getNowDate(twoHoursAgo))
      this.signInTime.push(this.activityTime[1])
      console.log(this.signInTime)
      return this.$forceUpdate()
    }

17、限制选择时间到分钟

// vue2
<el-date-picker
  style="width: 100%"
  v-model="activityTime"
  type="datetimerange"
  format="yyyy-MM-dd HH:mm"
  value-format="yyyy-MM-dd HH:mm"
  placeholder="选择日期"
  :picker-options="option"
  :disabled="disableStatus"
  @change="activityTimeChange">
</el-date-picker>

// vue3
<el-date-picker
  v-model="activityTime"
  :disabled="disableStatus"
  :disabled-date="disabledDate"
  end-placeholder="结束时间"
  format="YYYY-MM-DD HH:mm"
  range-separator="到"
  start-placeholder="开始时间"
  style="width: 100%"
  type="datetimerange"
  value-format="YYYY-MM-DD HH:mm"
  @change="activityTimeChange"
/>

18、英文不允许整个单词换行

    word-wrap: break-word;
    word-break: break-all;

19、web直传oss

<template>
  <div style="background: #fff">
    <el-upload
      class="avatar-uploader"
      action="https://xxxx.oss-cn-shanghai.aliyuncs.com"
      :data="dataObj"
      :show-file-list="false"
      :headers="hearder"
      :on-success="handleAvatarSuccess"
      :before-upload="beforeAvatarUpload">
      <img v-if="imageUrl" :src="imageUrl" class="avatar">
      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
    </el-upload>
  </div>
</template>

<script>
import { getToken } from '@/api/ossImage'
export default {
  name: 'IntelligentAuditingIndex',

  data() {
    return {
      imageUrl: '',
      dataObj: { // 后端返回的
        policy: '',
        signature: '',
        ossaccessKeyId: '',
        dir: '',
        host: '',
        callback: '',
        key: '',
        accessid: '',
      },
      hearder: {},
      action: '',
    };
  },
  created() {
    this.getObject()
  },

  mounted() {},

  methods: {
    getObject() {
      getToken().then(res => { // 后端接口返回的
        this.dataObj.policy = res.policy
        this.dataObj.signature = res.signature
        this.dataObj.ossaccessKeyId = res.accessid
        this.dataObj.accessid = res.accessid
        this.dataObj.dir = res.dir
        this.dataObj.host = res.host
        this.dataObj.callback = res.callback
      })
      this.hearder.Authorization = "Bearer " + window.localStorage.getItem('token')
    },
    handleAvatarSuccess(res, file) {
      this.imageUrl = URL.createObjectURL(file.raw);
    },
    beforeAvatarUpload(file) {
      this.dataObj.key = this.getUUID() + file.name
      console.log(this.dataObj.host + '/' + this.dataObj.key) // 拼接之后就是图片地址
      const isJPG = file.type === 'image/jpeg';
      const isLt2M = file.size / 1024 / 1024 < 2;

      if (!isJPG) {
        this.$message.error('上传头像图片只能是 JPG 格式!');
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!');
      }
      return isJPG && isLt2M;
    },
    getUUID() {
      return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
          return (c === 'x' ? (Math.random() * 16 | 0) : ('r&0x3' | '0x8')).toString(16)
      })
    }
  },
};
</script>

<style lang="scss" scoped>
  .avatar-uploader .el-upload {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
  }
  .avatar-uploader .el-upload:hover {
    border-color: #409EFF;
  }
  .avatar-uploader-icon {
    font-size: 28px;
    color: #8c939d;
    width: 178px;
    height: 178px;
    line-height: 178px;
    text-align: center;
  }
  .avatar {
    width: 178px;
    height: 178px;
    display: block;
  }
</style>

20、限制选择时间不能小于当前时间

<el-date-picker
  style="width: 100%"
  v-model="activityTime"
  type="datetimerange"
  format="yyyy-MM-dd HH:mm"
  value-format="yyyy-MM-dd HH:mm"
  placeholder="选择日期"
  :picker-options="option"
  :disabled="disableStatus"
  @change="activityTimeChange">
</el-date-picker>

// 如果选择的时间小于当前时间,则把当前时间赋值给选择的时间
activityTimeChange(e) {
  if(!e) {
    this.submitData.activityStartTime = ''
    this.submitData.activityEndTime = ''
    return
  }
  let startAt = new Date(e[0]) * 1000 /1000;
  if(startAt < Date.now()) {
    this.activityTime[0] = getNowDate()
  }
  let endAt = new Date(e[1]) * 1000 /1000;
  if(endAt < Date.now()) {
    this.activityTime[1] = getNowDate()
  }
  this.submitData.activityStartTime = this.activityTime[0]
  this.submitData.activityEndTime = this.activityTime[1]
  this.getBeforeTwo(this.activityTime[0])
}

// 格式化日对象
export function getNowDate(time = null) {
  var date = time ? new Date(time) : new Date()
  var sign2 = ":";
  var year = date.getFullYear() // 年
  var month = date.getMonth() + 1; // 月
  var day = date.getDate(); // 日
  var hour = date.getHours(); // 时
  var minutes = date.getMinutes(); // 分
  var seconds = date.getSeconds() //秒
  var weekArr = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期天'];
  var week = weekArr[date.getDay()];
  // 给一位数的数据前面加 “0”
  if (month >= 1 && month <= 9) {
    month = "0" + month;
  }
  if (day >= 0 && day <= 9) {
    day = "0" + day;
  }
  if (hour >= 0 && hour <= 9) {
    hour = "0" + hour;
  }
  if (minutes >= 0 && minutes <= 9) {
    minutes = "0" + minutes;
  }
  if (seconds >= 0 && seconds <= 9) {
    seconds = "0" + seconds;
  }
  return year + "-" + month + "-" + day + " " + hour + sign2 + minutes;
}

22、vue路由配置提示超出循环,进入死循环的时候,因为只要内遇到next()的时候就会一直执行,只有遇到了next()才会停止

// 处理路由方法
import router from '@/router'
import store from '@/store'

// 全局前置守卫
let hasGetInfo = false
router.beforeEach(async (to, from, next) => {
  // 设置页面标题
  let title = (to.meta.title ? to.meta.title : "管理平台")
  document.title = title
  const token = window.localStorage.getItem('token')
  if(token) {
    if(to.path != '/compulsoryCertification' && window.localStorage.getItem('whetherAttestation') == 10){ // 这一行至关重要
      next({ path: '/compulsoryCertification' })
    }
    if(to.path == '/login'){
      next({ path: from.path ? from.path : '/' })
    }
    if(!hasGetInfo) {
      try{
        await store.dispatch("getMenu")
      }catch(err){
        console.log('获取菜单列表失败');
      }
      try{
        await store.dispatch("getInfo")
      }catch(err){
        console.log('获取用户信息');
      }
      try{
        await store.dispatch("getProblem")
      }catch(err){
        console.log('获取问卷失败');
      }
      hasGetInfo = true
    }
    next()
  }else {
    if(to.path != '/login' && to.path != '/notice') next({ path: "/login" })
    next()
  }
})

// 全局后置守卫
router.afterEach((to, from) => {
})

23、虚假进度条

       <el-progress class="progress-file" v-if="flagProgress" :percentage="uploadPercent"></el-progress>



      flagProgress: false, // 是否显示进度条
      uploadPercent: 0, // 当前进度
      countdown: 15, // 倒计时多少s
      timer: null, // 定时器

	
    handleProgress() {
      this.timer = setInterval(() => {
        let number = Number((Math.random() * 10).toFixed(0))
        console.log(number)
        if (this.countdown > 0) {
          this.countdown -= 1
          this.uploadPercent += number
        } else {
          clearInterval(this.timer)
        }
      }, 500)
    }

24、在线预览文档

<iframe :src="attachmentSrc" frameborder="0" width="100%" height="1200"></iframe>


  data(){
    return {
      imgUrl: '',
      imgType: '.jpg,.JPEG,.PNG,.GIF,.BMP,.TIFF,.WEBP,.HEIF',
      attachmentSrc: 'https://view.officeapps.live.com/op/view.aspx?src=', // 主要是这句,调用了微软的在线预览文档接口
    }
  },

25、oss直传

          <el-upload
            class="avatar-logo-uploader"
            :action="uploadImageUrl"  // oss上传地址,oss域名
            :data="dataObj" // 上传的参数
            :headers="hearder" // 上传的头部数据,token之类的
            :show-file-list="false"
            :on-success="handleLogoSuccess"
            :before-upload="beforeUpload"
            accept=".jpg,.JPEG,.PNG,.GIF,.BMP,.TIFF,.WEBP,.HEIF">
            <img v-if="enterpriseInfo.enterpriseLog" :src="enterpriseInfo.enterpriseLog" class="avatar">
            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
          </el-upload>

    this.uploadImageUrl = process.env.VUE_APP_OSS // 我将上传地址放env了
    this.hearder = hearder  // 头部参数
    

// 方法
    handleLogoSuccess(response){
      this.enterpriseInfo.enterpriseLog = this.dataObj.host + '/' + this.dataObj.key
    },
    async beforeUpload(file) {
      this.dataObj.key = this.dataObj.key + file.name
      const isJPG = file.type === 'image/jpg' || file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/gif' || file.type === 'image/bmp' || file.type === 'image/tiff' || file.type === 'image/webp' || file.type === 'image/heif'
      const isLt2M = file.size / 1024 / 1024 < 50

      if (!isJPG) {
        this.$message.error('仅支持.JPG、.JPEG、.PNG、.GIF、.BMP、.TIFF、.WEBP、.HEIF格式!')
      }
      if (!isLt2M) {
        this.$message.error('图片大小不能超过 50MB!')
      }
      return isJPG && isLt2M;
    },

封装的js

import { getToken } from '@/api/ossImage'

let dataObj = {
  policy: '',
  signature: '',
  ossaccessKeyId: '',
  dir: '',
  host: '',
  callback: '',
  key: '',
  accessid: '',
}

export const hearder = {
  Authorization: "Bearer " + window.localStorage.getItem('token')
}

export const getOss = async () => {
  await getToken().then(res => { // 后端接口返回的,需要传回给后端的
    dataObj.policy = res.policy
    dataObj.signature = res.signature
    dataObj.ossaccessKeyId = res.accessid
    dataObj.accessid = res.accessid
    dataObj.dir = res.dir
    dataObj.key = res.dir + getUUID()
    dataObj.host = res.host
    dataObj.callback = res.callback
  })
  return dataObj
}

export const getUUID = () => { // 生成的路径,防止重复
  let str = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
      return (c === 'x' ? (Math.random() * 16 | 0) : ('r&0x3' | '0x8')).toString(16)
  })
  let result = '/' + str + '/' + getNowDate() + '/'
  return result
}

export function getNowDate() {
  var date = new Date()
  var sign2 = ":";
  var year = date.getFullYear() // 年
  var month = date.getMonth() + 1; // 月
  var day = date.getDate(); // 日
  var hour = date.getHours(); // 时
  var minutes = date.getMinutes(); // 分
  var seconds = date.getSeconds() //秒
  var weekArr = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期天'];
  var week = weekArr[date.getDay()];
  // 给一位数的数据前面加 “0”
  if (month >= 1 && month <= 9) {
    month = "0" + month;
  }
  if (day >= 0 && day <= 9) {
    day = "0" + day;
  }
  if (hour >= 0 && hour <= 9) {
    hour = "0" + hour;
  }
  if (minutes >= 0 && minutes <= 9) {
    minutes = "0" + minutes;
  }
  if (seconds >= 0 && seconds <= 9) {
    seconds = "0" + seconds;
  }
  return year + "-" + month + "-" + day + "-" + hour + sign2 + minutes + sign2 + seconds;
}

26、菜单

<template>
  <div class="f-menu" :style="{width: $store.state.operationMenu}">

    <el-menu background-color="#FFFFFF" text-color="#5E5E5E" :default-active="$route.path" unique-opened
      :collapse="isMenuCollapse" @select="handleSelect" :collapse-transition="false">
      <div v-for="(item,index) in menus" :key="index">
        <el-submenu v-if="item.children && item.children.length > 0" :index="item.path">
          <template slot="title">
            <i :class="item.meta.icon"></i>
            <span slot="title">{{item.name}}</span>
          </template>
          <div v-for="(item2,index2) in item.children" :key="index2">
            <el-submenu v-if="item2.children && item2.children.length > 0" :index="item2.path">
              <template slot="title">
                <i :class="item2.meta.icon"></i>
                <span slot="title">{{item2.name}}</span>
              </template>
              <el-menu-item v-for="(item3,index3) in item2.children" :key="index3" :index="item3.path" :disabled="!item3.enable">
                <i :class="item3.meta.icon"></i>
                <span slot="title">{{item3.name}}</span>
              </el-menu-item>
            </el-submenu>
            <el-menu-item v-else :index="item2.path" :disabled="!item2.enable">
              <i :class="item2.meta.icon"></i>
              <span slot="title">{{item2.name}}</span>
            </el-menu-item>
          </div>
        </el-submenu>
        <el-menu-item v-else :index="item.path" :disabled="!item.enable">
          <i :class="item.meta.icon"></i>
          <span slot="title">{{item.name}}</span>
        </el-menu-item>
      </div>
    </el-menu>
  </div>
</template>

<script>
  import {
    mapState
  } from 'vuex'

  export default {
    name: 'FMenu',
    data() {
      return {};
    },
    mounted() {},
    created() {},
    computed: {
      ...mapState(["userinfo","getMenuTotal", "menus", "isMenuCollapse"])
    },
    methods: {
      async handleSelect(e) {
        if(e != '/index' && e != '/enterpriseCertification' && e != '/enterpriseEdit' && this.userinfo.whetherAttestation != 20){
          this.$router.push({ path: '/enterpriseCertification'})
          this.$message({ type: 'warning', message: '请先进行企业认证!'})
          this.$forceUpdate()
          return
        }
        this.$router.push(e)
      }
    },
  };
</script>

<style lang="scss" scoped>
  .f-menu {
    background: #FFFFFF;
    position: fixed;
    left: 0;
    bottom: 0;
    top: 60px;
    overflow-y: auto;
    overflow-x: hidden;
    width: 200px;
    border-right: 1px solid #d7d4d4;

    ::v-deep .el-menu-item {
      height: 56px;
    }
    ::v-deep .is-active {
      background-color: #E0E8FF !important;
      color: #000000;
    }
    ::v-deep .is-active::after {
      content: '';
      position: absolute;
      width: 8px;
      height: 56px;
      right: 0;
      bottom: 0;
      background: #0880FF;
    }
    ::v-deep .is-opened::after {
      display: none;
    }
    ::v-deep .el-menu {
      border: none;
    }

    .el-menu-vertical-demo:not(.el-menu--collapse) {
      width: 200px;
      min-height: 400px;
    }

    /*隐藏文字*/
    ::v-deep .el-menu--collapse .el-submenu__title span {
      display: none;
    }

    // /*隐藏 > */
    ::v-deep .el-menu--collapse .el-submenu__title .el-submenu__icon-arrow {
      display: none;
    }
  }
</style>

27、element时间选择器禁止隐藏年

          <el-date-picker
            popper-class="RedefineScope-node-repeat" // 主要是这行,进行设置class
            v-model="formSeach.month"
            type="month"
            placeholder="请选择月"
            format="MM"
            value-format="MM"
            @change="clearMonth">
          </el-date-picker>

<style lang="scss"> // 然后是这行,不能再当前页面更改,要不然一直不生效,这个问题找的我头都快炸了,一定要去掉scoped
  .RedefineScope-node-repeat .el-date-picker__header--bordered {
    display: none;
  }
</style>

28、取消接口

import request from '@/utils/request'
import axios from 'axios'  // 关键代码
const CancelToken = axios.CancelToken   // 关键代码

export const getFileZip = (params, that) => request({
	url: '/api/ReviewSubmission/Pack',
	method: 'GET',
	params,
	// 关键代码 cancelToken
	cancelToken: new CancelToken(function executor(c) {
		that.cancel = c
	}) 
})


// 使用
getFileZip(params, this).then((res) => {})
this.cancel('请求已取消') // 在哪里取消就在哪里执行这行代码

29、默认展开指定的菜单
default-openeds:当前打开的 sub-menu 的 index 的数组

<el-menu ref="elMenuRef" background-color="#FFFFFF" text-color="#5E5E5E" :default-active="$route.path" :unique-opened="false"
      :collapse="isMenuCollapse" @select="handleSelect" :collapse-transition="false" :default-openeds="menuListPurview" @close="menuClose">
      <div v-for="(item,index) in menus" :key="index">
        <el-submenu v-if="item.children && item.children.length > 0" :index="item.path" :class="item.path == '/declaration' || '/promote' || '/exponent' ? 'hide-right' : ''">
          <template slot="title">
            <i :class="item.meta.icon"></i>
            <span slot="title">{{item.name}}</span>
          </template>
          <div v-for="(item2,index2) in item.children" :key="index2">
            <el-submenu v-if="item2.children && item2.children.length > 0" :index="item2.path">
              <template slot="title">
                <i :class="item2.meta.icon"></i>
                <span slot="title">{{item2.name}}</span>
              </template>
              <el-menu-item v-for="(item3,index3) in item2.children" :key="index3" :index="item3.path" :disabled="!item3.enable">
                <i :class="item3.meta.icon"></i>
                <span slot="title">{{item3.name}}</span>
              </el-menu-item>
            </el-submenu>
            <el-menu-item v-else :index="item2.path" :disabled="!item2.enable">
              <i :class="item2.meta.icon"></i>
              <span slot="title">{{item2.name}}</span>
            </el-menu-item>
          </div>
        </el-submenu>
        <el-menu-item v-else :index="item.path" :disabled="!item.enable">
          <i :class="item.meta.icon"></i>
          <span slot="title">{{item.name}}</span>
        </el-menu-item>
      </div>
    </el-menu>

// 默认展开的菜单
menuListPurview: ['/declaration', '/promote', '/exponent']

// 不允许收起这三个菜单
menuClose(e) {
 if(e == '/declaration' || e == '/promote' || e == '/exponent') {
 	this.$refs.elMenuRef.open(e)
 }
}

30、el-collapse 箭头改成文字加箭头

 ::v-deep .el-icon-arrow-right:before{
    content: "展开  \e6df";
  }
  ::v-deep .el-icon-arrow-right.is-active:before{
    content: "收起  \e6e1";
  }
  ::v-deep .el-icon-arrow-right.is-active{
    transform: rotate(0deg);
  }
  ::v-deep .el-collapse-item__arrow{
    min-width: 55px;
  }

31、校验两次密码是否一致

      registerRules: {
        confirmPassword: [
          { required: true, message: '确认密码不能为空', trigger: 'blur' },
          { min: 10, max: 20, message: '确认密码应为10-20位数', trigger: 'blur' },
          { pattern: /^(?=.*\d)(?=.*[A-Za-z])[A-Za-z\d$@$!%*#?&]{10,}$/, message: '最小10位,至少包含一个字母和一个数字'},
          { validator: validateCheckpwd, trigger: "change" }  // 主要就是这个validateCheckpwd
        ],
      },
data() {
    // 检查两次密码是否一样
    let validateCheckpwd = (rule, value, callback) => {
      if (value === this.registerForm.password) {
        callback();
      } else {
        callback(new Error("密码不一致, 请重新输入确认密码"));
      }
    }
}

32、vue滑动指定位置


对应的标签要加上   ref="description"

window.scrollTo({
   top: this.$refs[value].getBoundingClientRect().top + window.scrollY - 70,
   behavior: 'smooth' // 平滑滚动
})

33、微信分享H5
先引入微信js-sdk

npm install weixin-js-sdk

封装的分享

import wx from 'weixin-js-sdk'	// 使用js-sdk
import {
  getWechatConfig
} from "@/api/auth"  //为你提供timestamp、nonceStr、signature的后端接口

/**
 * 获取微信配置
 * @param {*} tag 调用页面的this
 * @param {*} share_title 分享标题
 * @param {*} share_desc 分享描述
 * @param {*} share_link 分享链接
 * @param {*} share_cover 分享封面(配图)
 * @returns 
 */
export const wechatConfig = (share_title, share_desc, share_link, share_cover) => {
  console.log(share_title, share_desc, share_link, share_cover)
  // 记录进入app时的url
  if (typeof window.entryUrl === 'undefined' || window.entryUrl === '') {
    window.entryUrl = encodeURIComponent(location.href.split('#')[0])
  }
  // 进行签名的时候  Android 不用使用之前的链接, ios 需要
  let signLink =  /(Android)/i.test(navigator.userAgent) ? encodeURIComponent(location.href.split('#')[0]) : window.entryUrl;
  let url_share = window.location.href.split('#')[0]
  // var wx_host = encodeURIComponent(window.location.href.split('#')[0]) //后端获取签名,需要前端传url,url要求看注解
  const cover = share_cover || 'https://hbimg.huaban.com/a2a9a71b293f6664b342e0cefc6e1fccd5f921f83cfa5-RoYLU8_fw658/format/webp'; //不重要的默认图片地址
  return new Promise((resolve, reject) => {
    getWechatConfig({ url: signLink }).then((res) => {
      if (res.code == 200) {
        const config = {
          debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
          appId: res.data.app, // 必填,公众号的唯一标识
          timestamp: res.data.timestamp, // 必填,生成签名的时间戳
          nonceStr: res.data.nonceStr, // 必填,生成签名的随机串
          signature: res.data.signature, // 必填,签名
          jsApiList: ["updateAppMessageShareData", "updateTimelineShareData"], // 必填,需要使用的JS接口列表,注意查看官方文档,部分js接口即将废弃,我这里用的是新的
          // openTagList: ["wx-open-launch-weapp"], // 可选,需要使用的开放标签列表(当前标签用于跳转微信小程序)
        };
        wx.config(config) //通过config接口注入权限验证配置
        wx.ready(function () { //通过ready接口处理成功验证
          //分享给朋友
          wx.updateAppMessageShareData({
            title: share_title, // 分享标题
            desc: share_desc, // 分享描述
            link: `${url_share}#/${share_link}`, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
            imgUrl: cover, // 分享后显示的封面图
            success: function () {}, // 设置成功回调
          });
          
          //分享到朋友圈
          wx.updateTimelineShareData({
            title: share_title, // 分享标题
            link: `${url_share}#/${share_link}`, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
            imgUrl: cover, // 分享图标
            success: function () {
              // 用户点击了分享后执行的回调函数
            }
          })
          return resolve(true)
        });
        wx.error(function (res) {
          // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
          alert("config信息验证失败")
          alert(res)
          return reject(false)
        });
      }
    });
  })
}

34、vue项目导入高德地图选择地址

<template>
  <div class="app-container">
    <!--搜索组件-->
    <div>
      <el-select
        v-model="keywords"
        filterable
        remote
        placeholder="请输入关键词"
        :remote-method="remoteMethod"
        :loading="loading"
        :clearable="true"
        size="mini"
        @change="currentSelect"
        style="width: 500px"
      >
        <el-option
          v-for="item in options"
          :key="item.id"
          :label="item.name"
          :value="item"
          class="one-text"
        >
          <span style="float: left">{{ item.name }}</span>
          <span style="float: right; color: #8492a6; font-size: 13px">{{
              item.district
            }}</span>
        </el-option>
      </el-select>
    </div>
    <!--地图组件-->
    <div id="guide-map" style="height: 500px;"></div>
  </div>
</template>
<script>
import AMapLoader from "@amap/amap-jsapi-loader";
// 设置安全密钥
window._AMapSecurityConfig = {
  securityJsCode: '', // 从高德获取
}
export default {
  name: 'MapAddress',
  props: {
    deployedAddress: {
      type: String,
      default: '123'
    },
    deployedAreaLatitude: {
      type: Number,
      default: 39.90923
    },
    deployedAreaLongitude: {
      type: Number,
      default: 116.397428
    },
  },
  watch: {
    deployedAddress(val) {
      this.keywords = val
      setTimeout(() => {
        //设置marker
        this.searchMarker = new AMap.Marker({
          map: this.map,
          position: [this.deployedAreaLongitude, this.deployedAreaLatitude],
        })
        //定位
        this.map.setCenter([
          this.deployedAreaLongitude,
          this.deployedAreaLatitude,
        ])
      }, 500)
    }
  },
  mounted() {
    this.initMap();
  },
  data(){
    return {
      //地图实例
      map: null,
      //路径坐标点集合
      coordinateList: [],
      //起点坐标
      startCoordinate: {},
      //终点坐标
      endCoordinate: {},
      //起点坐标描述
      startCoordinateDescription: '经度:请选择起点' + ',     纬度:请选择起点' ,
      //终点坐标描述
      endCoordinateDescription: '经度:请选择终点' + ',     纬度:请选择终点',
      //选择起点
      isStart: true,
      //起点Marker
      startMarker: null,
      //终点Marker
      endMarker: null,
      //搜索点Marker
      searchMarker: null,
      // 搜索提示
      AutoComplete: null,
      // 搜索关键字
      keywords: "",
      // 搜索节流阀
      loading: false,
      // 搜索提示信息
      options: [],
      form: {},
    }
  },
  methods: {
    //初始化地图
    initMap() {
      AMapLoader.reset()
      AMapLoader.load({
        key: '', // 从高德获取
        version: '2.0',   // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
        plugins: ['AMap.AutoComplete', 'AMap.PlaceSearch', 'AMap.Marker', 'AMap.Geocoder', 'AMap.Geolocation'],  // 需要使用的的插件列表
        AMapUI: {
          version: '1.1',
          plugins: []
        }
      }).then((AMap)=>{
        // 初始化地图
        this.map = new AMap.Map('guide-map',{
          viewMode : "2D",  //  是否为3D地图模式
          zoom : 14,   // 初始化地图级别
          center : [121.415883, 31.193473], //中心点坐标
          resizeEnable: true,
          willreadoften: true
        });
        //鼠标点击事件
        this.map.on('click', this.clickMapHandler)
        // 搜索提示插件
        this.AutoComplete = new AMap.AutoComplete({ city: "全国" });
        // 地址逆向解析插件
        this.geoCoder = new AMap.Geocoder({
          city: '010', //城市设为北京,默认:“全国”
          radius: 1000, //范围,默认:500
        })
        // 正向地理编码
        this.geocoder = new AMap.Geocoder({
          city: this.keywords,
        })
      }).catch(e => {
        console.log(e);
      });
    },
    // 逆解析地址
    toGetAddress() {
      let lnglat = [this.form.lng, this.form.lat]
      this.geoCoder.getAddress(lnglat, (status, result) => {
        if (status === 'complete' && result.regeocode) {
          this.keywords = result.regeocode.formattedAddress
          this.form.address = result.regeocode.formattedAddress
          this.$emit('markerData', this.form)
        }
      })
    },
    // 点击地图事件
    clickMapHandler(e){
      //选择起点
      if (this.startMarker) {
        // this.map.remove(this.startMarker)  不知道为什么无效,先留着
        this.map.clearMap()
      }
      //标点
      this.startMarker = new AMap.Marker({
        map: this.map,
        position: [e.lnglat.lng, e.lnglat.lat], // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
      })
      this.form.lng = e.lnglat.lng
      this.form.lat = e.lnglat.lat
      this.toGetAddress()
      // 将创建的点标记添加到已有的地图实例
      this.map.add(this.startMarker)
    },
    // 搜索地址
    remoteMethod(query) {
      if (query !== "") {
        this.loading = true;
        setTimeout(() => {
          this.loading = false;
          this.AutoComplete.search(query, (status, result) => {
            this.options = result.tips;
          });
        }, 200);
      } else {
        this.options = [];
      }
    },
    // 选中提示
    currentSelect(val) {
      // 清空时不执行后面代码
      if (!val) {
        return ;
      }
      // 自动适应显示想显示的范围区域
      this.map.setFitView();
      //清除marker
      if (this.searchMarker){
        this.map.remove(this.searchMarker)
      }
      //设置marker
      this.searchMarker = new AMap.Marker({
        map: this.map,
        position: [val.location.lng, val.location.lat],
      });

      this.keywords = val.name
      //定位
      this.map.setCenter([val.location.lng, val.location.lat])
      this.$emit('selectData', val)
    }
  }
}
</script>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值