vue 全局动态修改title、keywords、description
路由:
{
path: "xxx",
name: "xxx",
component: () =>import('..xxx'),
meta: {
title: 'xxx',
keywords:'xxx',
description:'xxx'
},
},
实现
router.beforeEach((to,from,next)=>{
/*********动态修改keywords和description*************/
if(Object.keys(to.meta).length>0 && to.matched.length>0){
let this_meta=to.matched[to.matched.length-1].meta
console.log(this_meta,'---this_meta---')
if(this_meta.title)document.title=this_meta.title
let head = document.getElementsByTagName('head');
let meta_keyword=document.createElement('meta');
if(document.querySelector('meta[name="keywords"]')){
document.querySelector('meta[name="keywords"]').setAttribute('content',this_meta.keywords)
}else{
meta_keyword.setAttribute('name','keywords')
meta_keyword.setAttribute('content',this_meta.keywords)
head[0].appendChild(meta_keyword)
}
let meta_description=document.createElement('meta');
if(document.querySelector('meta[name="description"]')){
document.querySelector('meta[name="description"]').setAttribute('content',this_meta.description)
}else{
meta_description.setAttribute('name','description')
meta_description.setAttribute('content',this_meta.description)
head[0].appendChild(meta_description)
}
}
/**********************************************/
next()
})
其他方法:
filters.js:
export function formatNumber(num, type) {
if (num) {
num = num.toString().replace(/[,]/g, '')
}
if (num === '' || num === null || num === undefined || num === 'inf' || num == '-') {
return '--'
}
num = parseFloat(num)
if (!type) {
/* 大于100 保留2位小数 否则显示4位小数 */
let _num = parseFloat((num * 1000) / 1000).toFixed(2)
return formatCurrency(_num)
}
if (type === '%') {
// let _num = parseFloat((num * 1000) / 1000).toFixed(2) * 100
return maxDecimal(num, 4)
}
if (type === 'int') {
let _num = parseFloat((num * 1000) / 1000).toFixed(0)
return _num
}
}
/**
*
* 金额加,分隔符(正则)
* **/
export function formatCurrency(value) {
if (!value) return 0
const valueArray = value.toString().split('.')
const valueNum = Number(valueArray[0].toString().replace(/,/g, ''))
valueArray[0] = Math.abs(valueNum).toString().split('').reverse().join('').replace(/(\d{3})/g, function(word) {
return word + ','
}).replace(/^(\s|,)+|(\s|,)+$/g, '').split('').reverse().join('')
return valueNum >= 0 ? valueArray.join('.') : ('-' + valueArray.join('.'))
}
/**
*
* 金额加,分隔符
* **/
export function formatCurrency1(num) {
//将num中的$,去掉,将num变成一个纯粹的数据格式字符串
num = num.toString().replace(/\$|\,/g, '');
//如果num不是数字,则将num置0,并返回
if ('' == num || isNaN(num)) {
return '0';
}
//如果num是负数,则获取她的符号
var sign = num.indexOf("-") >= 0 ? '-' : '';
if (num.indexOf("-") >= 0) {
num = num.substring(1)
}
//如果存在小数点,则获取数字的小数部分
var cents = num.indexOf(".") > 0 ? num.substr(num.indexOf(".")) : '';
cents = cents.length > 1 ? cents : ''; //注意:这里如果是使用change方法不断的调用,小数是输入不了的
//获取数字的整数数部分
num = num.indexOf(".") > 0 ? num.substring(0, (num.indexOf("."))) : num;
//如果没有小数点,整数部分不能以0开头
if ('' == cents) {
if (num.length > 1 && '0' == num.substr(0, 1)) {
return '0! ';
}
}
//如果有小数点,且整数的部分的长度大于1,则整数部分不能以0开头
else {
if (num.length > 1 && '0' == num.substr(0, 1)) {
return '0! ';
}
}
//针对整数部分进行格式化处理,这是此方法的核心,也是稍难理解的一个地方,逆向的来思考或者采用简单的事例来实现就容易多了
/*
也可以这样想象,现在有一串数字字符串在你面前,如果让你给他家千分位的逗号的话,你是怎么来思考和操作的?
字符串长度为0/1/2/3时都不用添加
字符串长度大于3的时候,从右往左数,有三位字符就加一个逗号,然后继续往前数,直到不到往前数少于三位字符为止
*/
for (var i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++) {
num = num.substring(0, num.length - (4 * i + 3)) + ',' + num.substring(num.length - (4 * i + 3));
}
//将数据(符号、整数部分、小数部分)整体组合返回
return (sign + num + cents);
}
function maxDecimal(number, num) {
let regExp = new RegExp("^(.\*\\..{" + num + "}).*$")
return String(number).replace(regExp, "$1")
}
数字处理方法tools.js:
// 字符串true、false转布尔true、false
String.prototype.toBool = function(){
return (/^true$/i).test(this);
}
//清除字符串首尾空格
String.prototype.trim=function(){
return this.replace(/^(\s|`)+|(\s|`)+$/g, '')
}
// 格式数字千分
String.prototype.kB=Number.prototype.kB=function(){
const valueArray = this.toString().split('.')
const valueNum = Number(valueArray[0].toString().replace(/,/g, ''))
valueArray[0] = Math.abs(valueNum).toString().split('').reverse().join('').replace(/(\d{3})/g, function(word) {
return word + ','
}).replace(/^(\s|,)+|(\s|,)+$/g, '').split('').reverse().join('')
return valueNum >= 0 ? valueArray.join('.') : ('-' + valueArray.join('.'))
}
const tools={
// 加、减、乘、除浮点计算
priceFigure(value1, value2, type = '-') {
value1 = value1 || 0
value2 = value2 || 0
const decimals1 = value1.toString().indexOf('.') != -1 ? value1.toString().split('.').at(-1) : null
const decimals2 = value2.toString().indexOf('.') != -1 ? value2.toString().split('.').at(-1) : null
let extNum = decimals1 ? decimals1.length : 0
if (decimals2 && decimals2.length > extNum) {
extNum = decimals2.length
}
let extLength = extNum
extLength = extLength % 2 == 0 ? extLength + 1 : extLength
let num = 0
if (type == '+') {
num = ((Number(value1) * Math.pow(10, extLength)) + (Number(value2) * Math.pow(10, extLength))) / Math.pow(10, extLength)
}
if (type == '-') {
num = ((Number(value1) * Math.pow(10, extLength)) - (Number(value2) * Math.pow(10, extLength))) / Math.pow(10, extLength)
}
if (type == '*') {
num = ((Number(value1) * Math.pow(10, extLength)) * (Number(value2) * Math.pow(10, extLength))) / (Math.pow(10, extLength) * Math.pow(10, extLength))
}
if (type == '/') {
num = ((Number(value1) * Math.pow(10, extLength)) / (Number(value2) * Math.pow(10, extLength)))
}
return num
},
numFormatK(value){
if (!value) return 0
// 方法一:
const valueArray = value.toString().split('.')
valueArray[0] = valueArray[0].toString().replace(/,/g, '').split('').reverse().join('').replace(/(\d{3})/g, function(word) {
return word + ','
}).replace(/^(\s|,)+|(\s|,)+$/g, '').split('').reverse().join('')
return valueArray.join('.')
// 方法一:
// const value_zhi = value.toString().split(',').join('')
// const value_zhiArray = value_zhi.split('.')
// if (value_zhiArray[0] == '') {
// return ''
// }
// const oneNumArray = value_zhiArray[0].split('').reverse()
// const numArray = new Array(oneNumArray.length).fill('null')
// const qianArray = []
// if (numArray.length >= 3) {
// numArray.forEach((_, index) => {
// if (index % 3 == 0 && index > 0) {
// qianArray.push(index)
// }
// })
// }
// let num = 0
// qianArray.forEach(item => {
// oneNumArray.splice(item + num, 0, ',')
// num++
// })
// return oneNumArray.reverse().join('') + (value_zhiArray.length > 1 ? `.${value_zhiArray[1]}` : '')
}
}
export default tools
挂载其他方法,包括filters.js :
//引入filters.js
import * as filters from '@/common/utils/filters.js'
//引入tools.js
import * as tools from '@/common/utils/tools.js'
let authList=[]//权限列表
const install=(Vue,router)=>{
//挂载filters.js
Object.keys(filters).forEach(key => {
Vue.filter(key,filters[key])
Vue.prototype[key] = filters[key];
})
// 挂载 tools.js里面的方法
Object.keys(tools).forEach(key => {
Vue.prototype['$'+key]=tools[key]
})
//html标签处理
Vue.prototype.$htmlChange=(str)=>{
const objectFn = {
// 获取标签上面的数据
getDomValue(word, type, value) {
const regXLink = RegExp(`<${type}`, 'g')
const regXLink1 = RegExp(`${type}>`, 'g')
const wordDiv = word.replace(regXLink, '<div').replace(regXLink1, 'div>')
const Dom = document.createElement('div')
Dom.innerHTML = wordDiv
return Dom.children[0].getAttribute(value)
},
// 打电话
// <phone>10086</phone>
phoneChange: (word, type, text) => {
return `<a href='tel:${text}'>${text}</a>`
},
// 发短信
// <sms phone='10086' message='短信消息'>短信</sms>
smsChange: (word, type, text) => {
const phone = objectFn.getDomValue(word, type, 'phone')
const message = objectFn.getDomValue(word, type, 'message')
return `<a href='sms:${phone}?body=${message}'>${text}</a>`
},
// 发送位置
// <location location='116.281469,39.866035'>发送位置</location>
locationChange: (word, type, text) => {
const location = objectFn.getDomValue(word, type, 'location')
return `<a href="geopoint:${location}">${text}</a>`
},
// 发送邮件
// <email>15683520@qq.com</email>
emailChange: (word, type, text) => {
return `<a href="mailto:${text}">${text}</a>`
},
init: (str) => {
if (!str) return
const regX = RegExp(`<[a-zA-Z]+.*?>([\\s\\S]*?)<\/[a-zA-Z]*?>`, 'gm')
return str.replace(regX, function(word, text) {
let type = ''
word.replace(/<\/[a-zA-Z]*?>/gm, function(wordType) {
type = wordType.replace('</', '').replace('>', '')
return wordType
})
// 运行特殊处理的标签方法
if (objectFn[`${type}Change`]) {
return objectFn[`${type}Change`](word, type, text)
} else {
// 没有方法就不处理
return word
}
})
}
}
return objectFn.init(str)
}
// 判断元素是否被隐藏(会一直往上查 ,查询父级有没有隐藏。元素隐藏,display:none)
Vue.prototype.$getIsNone=(el)=>{
const getAllComputedStyle=(obj,property)=>{
if(window.getComputedStyle){
//现在要把用户输入的property中检测一下是不是驼峰,转为连字符写法
//强制把用户输入的词儿里面的大写字母,变为小写字母加-
//paddingLeft → padding-left
property = property.replace(/([A-Z])/g , function(match,$1){
return "-" + $1.toLowerCase();
});
return window.getComputedStyle(obj)[property];
}else{
//IE只认识驼峰,我们要防止用户输入短横,要把短横改为大写字母
//padding-left → paddingLeft
property = property.replace(/\-([a-z])/g , function(match,$1){
return $1.toUpperCase();
});
return obj.currentStyle[property];
}
}
const getNone=(el)=>{
if(el.nodeName!='BODY'){
if(getAllComputedStyle(el,'display')=='none'){
return true
}
return getNone(el.parentNode)
}
return false
}
return getNone(el)
}
// 获取相同元素在页面的显示节点方法一,
// {
// el: '.box-item',//显示的盒子
// scrollDom: '.main-wrapper',//滚动的盒子,页面滚动传递'window',默认'window'
// isRepetition: true,//是否重复获取,默认true
// lookRatio: 0//显示盒子的判断比例,默认0(表示只要显示一点就说明在页面上)
// }
Vue.prototype.$getDomViewShow=(objectData)=>{
const { el, scrollDom = 'window', isRepetition = true, lookRatio = 0 } = objectData
let scrollY = 0
if (scrollDom != 'window' && document.querySelector(scrollDom)) {
scrollY = document.querySelector(scrollDom).getBoundingClientRect().y
}
const getDom = (domEl, parent = null) => {
const elArray = domEl.split(' ').filter(n => n != '')
const parentDom = parent || document
let thisDom = null
try {
thisDom = parentDom.querySelectorAll(elArray[0])
} catch (_) {
thisDom = [parentDom.querySelector(elArray[0])]
}
const nextArray = elArray.slice(1, elArray.length)
if (nextArray.length > 0) {
return getDom(nextArray.join(' '), thisDom[0])
} else {
return thisDom
}
}
const Dom = getDom(el)
const DomArray = []
if (Dom) {
Dom.forEach(item => {
const clientRect = item.getBoundingClientRect()
const isViewShow = item.getAttribute('isViewShow') || 0
if (clientRect.y >= 0) {
if (clientRect.y <= window.innerHeight && (window.innerHeight - clientRect.y) >= item.offsetHeight * Number(lookRatio)) {
if (isViewShow == 0) {
item.setAttribute('isViewShow', 1)
DomArray.push(item)
}
} else {
if (isRepetition)item.setAttribute('isViewShow', 0)
}
} else {
if (Math.abs(clientRect.y + scrollY) <= item.offsetHeight * (1 - Number(lookRatio))) {
if (isViewShow == 0) {
item.setAttribute('isViewShow', 1)
DomArray.push(item)
}
} else {
if (isRepetition)item.setAttribute('isViewShow', 0)
}
}
})
}
return DomArray
}
// 获取相同元素在页面的显示节点方法二,
// {
// el: '.card-item',//显示的盒子
// scrollDom:document.querySelector('.main-wrapper'),//滚动的盒子,不传默认null
// isRepetition: false,//是否重复获取,默认false
// lookRatio: 0//显示盒子的判断比例,默认0(表示只要显示一点就说明在页面上)
// }
// this.$getDomViewShow2({
// el: '.card-item'
// }).then(res => {
// console.log(res)
// })
Vue.prototype.$getDomViewShow2=(obj)=>{
return new Promise((r, _) => {
const { el, scrollDom = null, isRepetition = false, lookRatio = 0 } = obj
const options = {
root: scrollDom,
rootMargin: '0px',
threshold: lookRatio
}
const observer = new IntersectionObserver((entries) => {
const arrayDom = []
entries.forEach(item => {
if (item.isIntersecting) {
arrayDom.push(item.target)
item.target.setAttribute('isViewShow', 1)
if (!isRepetition) {
observer.unobserve(item.target)
}
}else{
if(isRepetition){
item.target.setAttribute('isViewShow', 0)
}
}
})
r(arrayDom)
}, options)
const getDom = (domEl, parent = null) => {
const elArray = domEl.split(' ').filter(n => n != '')
const parentDom = parent || document
let thisDom = null
try {
thisDom = parentDom.querySelectorAll(elArray[0])
} catch (_) {
thisDom = [parentDom.querySelector(elArray[0])]
}
const nextArray = elArray.slice(1, elArray.length)
if (nextArray.length > 0) {
return getDom(nextArray.join(' '), thisDom[0])
} else {
return thisDom
}
}
const Dom = getDom(el)
// 关闭监视器
observer.disconnect()
Dom.forEach(item => {
// 关闭监察
observer.unobserve(item)
if (item.getAttribute('isViewShow') != 1) {
observer.observe(item)
}else{
if(isRepetition){
item.setAttribute('isViewShow', 0)
}
}
})
})
}
// 深拷贝
Vue.prototype.$deepCopy = (data) => {
const map = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regExp',
'[object Undefined]': 'undefined',
'[object Null]': 'null',
'[object Object]': 'object'
}
const fn = (data) => {
const type = map[Object.prototype.toString.call(data)]
let dataObjectArray = null
if (type == 'array') {
dataObjectArray = []
data.forEach(item => {
dataObjectArray.push(fn(item))
})
return dataObjectArray
} else if (type == 'object') {
dataObjectArray = {}
for (const key in data) {
dataObjectArray[key] = fn(data[key])
}
return dataObjectArray
} else {
return data
}
}
return fn(data)
}
/**
* 设备类型
* @param 1.ios App
* @param 2.android App
* @param 3.wap
* @param 4.wechat
* @param 5.小程序
* @param 5.钉钉
*/
Vue.prototype.deviceType = function () {
let useragent = window.navigator.userAgent,
ua = window.navigator.userAgent.toLowerCase();
if (useragent.indexOf("iOS_APP") != -1) {//ios
return 1;
} else if (useragent.indexOf("ANDROID_APP") != -1) {//android
return 2;
} else if (ua.match(/MicroMessenger/i) == "micromessenger") {//微信环境
//需引入weixin-js-sdk依赖
wx.miniProgram.getEnv((res) => {
if (res.miniprogram) { //在微信小程序中
return 5;
} else { //在微信浏览器
return 4;
}
});
} else if(useragent.indexOf('DingTalk')!=-1){//钉钉环境
return 6;
}else {//其他
return 3;
}
}
// 权限列表判断,使用 v-auth='权限名'
Vue.directive('auth', {
inserted:(el, binding)=>{
let value=binding.value
if(authList.indexOf(value)==-1){
el.parentNode.removeChild(el)
}
}
})
// 总线跨页面传值
//this.$HWBUS.$on('fn',res=>{
// console.log(res)
// })//监听
// this.$HWBUS.$emit('fn',999)//传值
Vue.prototype.$HWBUS=new Vue()
// 替换文本中的${xx}参数
// const data = {
// date: '2022-12-02',
// name: 'xxx',
// address: '上海'
// }
// const str = '${name}于${date},出生于${address}'
// console.log(this.$analysis(str, data)) //xxx于2022-12-02,出生于上海
Vue.prototype.$analysis=(str, data, matchArray = ['${', '}']) => {
// const regX = RegExp(`<[a-zA-Z]+.*?>([\\s\\S]*?)<\/[a-zA-Z]*?>`, 'gm')
const regX = RegExp(`\\${matchArray[0]}+.*?([\\s\\S]*?)${matchArray[1]}.*?`, 'g')
return str.replace(regX, function(word, key) {
const returnData = data[key] || null
if (returnData) {
return returnData
}
return word
})
}
//格式化字符串里面的html,并添加样式
Vue.prototype.$formatHtml(val) {
const sing = '`'
const regxd = RegExp(`${sing}<[^${sing}]+>${sing}`, 'g')
val = val.replace(regxd, function(word) {
if (/<[^<]+>/g.test(val)) { // 判断是否存在html标签
const getHtml = (word) => {
let wordString = word.replace(/^(\s|`)+|(\s|`)+$/g, '')// 清除前后`符号
const htmlArray = []
wordString.replace(/<\/[^<]+>/g, function(word1) { // 获取每个标签类型的结束标签,即存在/的标签,比如:</div>
htmlArray.push(word1.replace(/^(\s|<\/)+|(\s|>)+$/g, ''))// 获取html里面存在的标签,并清除前<,后>
})
// 获取html标签以及中间的值
const htmlText = []
htmlArray.forEach(item => {
const regX = RegExp(`<${item}[^<]+<\/${item}>`, 'g')
console.log(regX)
wordString.replace(regX, function(word2) {
htmlText.push(word2)
})
})
console.log(htmlText)
htmlText.forEach(item => {
var ele = document.createElement('span')
ele.appendChild(document.createTextNode(item))
wordString = wordString.replace(RegExp(item, 'g'), `<span class='codeHtml' style='display: inline-block;padding: 4px 2px;background-color: #fff5f5;color: #ff502c;border-radius: 2px;'>${ele.innerHTML}</span>`)
})
return wordString
}
return getHtml(word)
} else {
return word
}
})
return val
}
// 选中文本、div、select()
Vue.prototype.$selectText = (element) => {
var text = document.getElementById(element)
var range
if (document.body.createTextRange) {
range = document.body.createTextRange()
range.moveToElementText(text)
range.select()
} else if (window.getSelection) {
var selection = window.getSelection()
range = document.createRange()
range.selectNodeContents(text)
selection.removeAllRanges()
selection.addRange(range)
/* if(selection.setBaseAndExtent){
selection.setBaseAndExtent(text, 0, text, 1);
}*/
} else {
console.log('none')
}
}
// 防止重复点击 this.$throttle(()=>{fn()},isClick,(res)=>{isClick=res} )()
Vue.prototype.$repeatClick = (fn, isClick, cb) => {
return function() {
const context = this
const args = arguments
if (isClick) {
fn.apply(context, args)
cb && cb(false)
}
}
}
// 事件节流(多少秒内只能执行一次)
// fn:方法
// 时间
// this.$throttle(fn, 500) || this.$throttle(()=>{fn()}, 500)()
Vue.prototype.$throttle = (fn, delayTime) => {
let clickTime = 0
return function() {
const context = this
const args = arguments
const nowTime = new Date()
if (nowTime - clickTime > delayTime) {
fn.apply(context, args)
clickTime = nowTime
}
}
}
// 事件防抖(多少秒后执行,再次调用重新计算,比如监听滚动停止等)
// immediate:是否立即执行
// this.$debounce(fn, 500) || this.$debounce(()=>{fn()}, 500)()
Vue.prototype.$debounce = (fn, delayTime, immediate) => {
let timeout
return function() {
const context = this
const args = arguments
if (timeout) clearTimeout(timeout)
if (immediate) {
var callNow = !timeout
timeout = setTimeout(() => {
timeout = null
}, delayTime)
if (callNow) fn.apply(context, args)
} else {
timeout = setTimeout(() => {
fn.apply(context, args)
}, delayTime)
}
}
}
// 计算日期
Vue.prototype.$getDate=(option={})=>{
const {value=null,numD=0,numM=0,numY=0,dayArray=['周一','周二','周三','周四','周五','周六','周天']}=option
let d=null
if(!value){
d=new Date()
}else{
let valueSuccess=value.split('-').join('/')
valueSuccess=value.split('.').join('/')
d=new Date(valueSuccess)
}
d.setDate(d.getDate()+numD)
d.setMonth(d.getMonth()+numM)
d.setFullYear(d.getFullYear()+numY)
let yy=d.getFullYear()
let mm=d.getMonth()+1
mm=mm<10?'0'+mm:mm
let dd=d.getDate()
dd=dd<10?'0'+dd:dd
let m=d.getMinutes()
m=m<10?'0'+m:m
let s=d.getSeconds()
s=s<10?'0'+s:s
let day=d.getDay()
day=day==0?7:day
let ymd=`${d.getFullYear()}-${d.getMonth()+1}-${d.getDate()}`
let yymmdd=`${yy}-${mm}-${dd}`
return{
yy,mm,dd,m,s,day,dayText:dayArray[day-1],
ymd:ymd,
yymmdd:yymmdd,
ymdms:`${ymd} ${m}:${s}`,
yymmddms:`${yymmdd} ${m}:${s}`,
}
},
// 判断数据类型
Vue.prototype.$typeOf=(value)=>{
let str=Object.prototype.toString.call(value)
str=str.replace('object','').replace('[','').replace(']','')
str=str.replace(/(^\s*)|(\s*$)/g, "").toLowerCase()
if(value=='null' || value=='undefined'){
str=typeof(value)
}
return str
}
// 打印操作
// html:需要打印页面的html代码,样式必须行内
// type:需不需要打印
Vue.prototype.$printFn=(html,type=1)=>{
var userAgent = navigator.userAgent.toLowerCase(); //取得浏览器的userAgent字符串
if (userAgent.indexOf("trident") > -1) {
this.$message.error('请使用google或者360浏览器打印')
return false;
} else if (userAgent.indexOf('msie') > -1) {
this.$message.error('请使用google或者360浏览器打印')
return false;
} else {//其它浏览器使用lodop
var headstr = "<html><head><title></title></head><body>";
var footstr = "</body></html>";
var printData = html; //获得 div 里的所有 html 数据
var wind = window.open("", "newwin","toolbar=no,scrollbars=yes,menubar=no");
wind.document.body.innerHTML = headstr + printData + footstr;
if(type==1){
wind.print();
}
}
}
// 去除字符串空格
// isBoolean=true:当数据为空字符串的时,返回false
Vue.prototype.$trim=(str,isBoolean)=>{
if (str == null) {
str = "";
}
let thisStr=str.replace(/(^\s*)|(\s*$)/g, "")
if(isBoolean){
if(thisStr==''){
return false
}else{
return thisStr;
}
}
return thisStr;
}
// 文件预览
// ops = {
// "pdf": true, //word文档尝试以pdf方式显示,默认false
// "watermark": "XDOC文档预览", //水印文本,显示水印
// "saveable": false, //是否允许保存PDF,默认true
// "printable": false, //是否允许打印PDF,默认true
// "copyable": false, //是否允许选择复制内容,默认true
// "toolbar": false, //是否显示底部工具条,默认true
// "title": "文档预览", //自定义标题
// "expire": 30, //预览链接有效期,单位分钟,默认永久有效
// "limit": "1,3", //限制页数,如:“5”表示只显示前5页,“2,5”表示从第2页开始的5页,对pdf/doc/docx/ppt/pptx有效
// "mtime": 1633093801, //文件修改时间戳(精确到秒)或修改时间(如:2021-10-01 21:10:01),值改变刷新缓存,实时预览
// };
Vue.prototype.$previewFile=(value,ops={})=>{
let url=`http://view.xdocin.com/xdoc?_xdoc=${value}`
for (var a in ops) {
url += "&" + a + "=" + encodeURIComponent(ops[a]);
}
window.open(url)
},
// 文件下载
Vue.prototype.$downloadFile=(content,fileName='')=>{
if(content instanceof Array){
content.forEach(item=>{
let aLink = document.createElement('a')
aLink.download = fileName;
aLink.setAttribute('href',item)
// a.href = url
aLink.click()
})
}else{
let aLink = document.createElement('a')
aLink.download = fileName;
aLink.setAttribute('href',content)
// a.href = url
aLink.click()
}
},
// 计算时间差
Vue.prototype.$dayCha=(value,geshi='天-小时-分-秒',type='string')=>{
let geshiArray=geshi.split('-')
var chaTime=value;
var day=parseInt(chaTime/86400)
var yu=chaTime % 86400
var hour=parseInt(yu/3600)
var yuH=yu % 3600
var min=parseInt(yuH/60)
var yuM=yuH%60
var sec=yuM
if(type=='string'){
let str=''
if(day>0)str+=day+geshiArray[0]
if(hour>0)str+=hour+geshiArray[1]
if(min>0)str+=min+geshiArray[2]
if(sec>0)str+=sec+geshiArray[3]
if(str==''){
str='-'
}
return str
}else{
return {day:day,hour:hour,minute:min,second:sec}
}
}
// 复制
Vue.prototype.$copyToClipboard=(value, cb)=>{
const textarea = document.createElement("textarea");
textarea.value = value;
document.body.appendChild(textarea);
textarea.select();
document.execCommand("copy");
document.body.removeChild(textarea);
cb && cb();
}
// 页面跳转
// type跳转方式:push新增,back 返回,replace 替换,_blank 新开
// $toPage('/about') 或 $toPage({url:'/about',data:{},callbck:()=>{}})
Vue.prototype.$toPage=(toData,type='push',is_other=false)=>{
// console.log(toData,type)
if(is_other){
window.open(toData)
return false;
}else{
if(typeof(toData)=='string'){
if(type=='push'){
router.push({ path: toData})
}else if(type=='back'){
router.go(-1)
}else if(type=='_blank'){
let routeUrl = router.resolve({
path: toData,
});
window.open(routeUrl.href, '_blank');
}else{
router.replace({ path: toData})
}
}else{
const {url='/',data={}}=toData
const queryData=Object.assign({},data)
if(queryData.callbck)delete queryData.callbck;
if(type=='push'){
router.push({ path: url, query:queryData})
setTimeout(()=>{
if(data.callbck)data.callbck(true)
},0)
}else if(type=='back'){
router.go(-1)
setTimeout(()=>{
if(data.callbck)data.callbck(true)
},0)
}else if(type=='_blank'){
let routeUrl =router.resolve({
path: url,
query:queryData
});
window.open(routeUrl.href, '_blank');
setTimeout(()=>{
if(data.callbck)data.callbck(true)
},0)
}else{
router.replace({ path: url, query:queryData})
setTimeout(()=>{
if(data.callbck)data.callbck(true)
},0)
}
}
}
},
// 获取页面url参数
Vue.prototype.$getQueryVariable = (variable) => {
var vars = []
// 如果存在#号
if (window.location.hash != '') {
// 取消#号
let hashUrk= window.location.hash.replace('#','')
// 取值
var query0 = hashUrk.includes('?')?hashUrk.split('?')[1]:hashUrk;
let queryArray=query0.split("&").map(item=>{
if(item.includes('=')){
return item
}else{
return '#'+item+'='+item
}
})
if (query0) vars.push(...queryArray);
}
// 如果存在参数
if(window.location.search != '') {
var query = window.location.search.substring(1);
if (query)vars.push(...query.split("&"));
}
let queryObject = {}
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
queryObject[pair[0]] = pair[1]
}
if (variable) {
if (queryObject[variable] && queryObject[variable] != '') {
return queryObject[variable]
} else {
return false;
}
} else {
return queryObject
}
}
// 修改浏览器url链接和带的参数,不会刷新页面,同时修改route的参数,value不传就会清除当前参数
Vue.prototype.$setLocaUrlQuery = (key, value='') => {
let str_url = window.location.href.split('?')[0];
let data = Vue.prototype.$getQueryVariable()
if (value == '') {
delete data[key]
if (router) delete router.app._route.query[key]
} else {
data[key] = value
if (router) router.app._route.query[key]=value
}
let data_str = [];
Object.keys(data).forEach(item => {
data_str.push(`${item}=${data[item]}`)
})
if (data_str.length > 0) {
str_url = str_url + '?' + data_str.join('&')
} else {
str_url = str_url
}
history.replaceState({}, document.title, str_url);
}
// 生成唯一UUid
Vue.prototype.$uuid=()=>{
var d = new Date().getTime();
if (window.performance && typeof window.performance.now === "function") {
d += performance.now(); //use high-precision timer if available
}
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (d + Math.random() * 16) % 16 | 0; // d是随机种子
d = Math.floor(d / 16);
return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid;
}
//修改浏览器title
Vue.prototype.$ChangePageTitle = (title) => {
let userAgentObj = JSON.parse(localStorage.getItem('userAgentObj')) || null
if (userAgentObj && userAgentObj.isDingTalk) {//钉钉内
window.$dd.ready(function () {
window.$dd.biz.navigation.setTitle({
title: title,//控制标题文本,空字符串表示显示默认文本
onSuccess: function (result) {
},
onFail: function (err) { }
});
});
} else {//微信或浏览器内
document.title = title;//普通浏览器用这一句就可以修改了
//微信浏览器需要在页面添加一个 <iframe style="display: none"></iframe>
//加载成功后 立即删除
}
}
/**
* 高德/腾讯经纬度转百度地图经纬度
* @param {Object} lng
* @param {Object} lat
*/
Vue.prototype.$qgMapTransBMap=(lng, lat)=>{
let x_pi = (3.14159265358979324 * 3000.0) / 180.0
let x = lng
let y = lat
let z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi)
let theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi)
let lngs = z * Math.cos(theta) + 0.0065
let lats = z * Math.sin(theta) + 0.006
return {
lng: lngs,
lat: lats,
}
},
/**
* 百度地图经纬度转高德/腾讯地图经纬度
* @param {Object} lng
* @param {Object} lat
*/
Vue.prototype.$bMapTransqgMap=(lng, lat)=>{
let x_pi = (3.14159265358979324 * 3000.0) / 180.0
let x = lng - 0.0065
let y = lat - 0.006
let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi)
let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi)
let lngs = z * Math.cos(theta)
let lats = z * Math.sin(theta)
return {
lng: lngs,
lat: lats,
}
}
/**
* 获取当前时间
*/
Vue.prototype.$getTime=() => {
var now = new Date();
var year = now.getFullYear(); //得到年份
var month = now.getMonth(); //得到月份
var date = now.getDate(); //得到日期
var day = now.getDay(); //得到周几
var hour = now.getHours(); //得到小时
var minu = now.getMinutes(); //得到分钟
var sec = now.getSeconds(); //得到秒
var MS = now.getMilliseconds(); //获取毫秒
var week;
month = month + 1;
if (month < 10) month = "0" + month;
if (date < 10) date = "0" + date;
if (hour < 10) hour = "0" + hour;
if (minu < 10) minu = "0" + minu;
if (sec < 10) sec = "0" + sec;
if (MS < 100) MS = "0" + MS;
var arr_week = new Array("星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六");
week = arr_week[day];
var time = "";
time = year + "-" + month + "-" + date + " " + hour + ":" + minu + ":" + sec;
date = year + "-" + month + "-" + date;
return {time,date}
}
/**
* 跳转QQ
* value:qq号
*/
Vue.prototype.$toQQ=(value) => {
window.location.href=`tencent://message/?uin=${value}`
}
// 手机号隐藏中间四位
Vue.prototype.$geTel=(tel)=>{
var reg = /^(\d{3})\d{4}(\d{4})$/;
return tel.replace(reg, "$1****$2");
}
// 获取视频第一帧
Vue.prototype.$getVideoImg=(url, time = 0)=>{
return new Promise((r, j) => {
const video = document.createElement('video') // 创建video对象
video.src = url // url地址
const canvas = document.createElement('canvas') // 创建 canvas 对象
const ctx = canvas.getContext('2d') // 绘制2d
video.crossOrigin = 'anonymous' // 解决跨域问题,也就是提示污染资源无法转换视频
video.currentTime = 1 // 第一秒帧
video.oncanplay = () => {
canvas.width = video.videoWidth
canvas.height = video.videoHeight
// 利用canvas对象方法绘图
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
r(canvas.toDataURL('image/png'))
// 转换成base64形式
// canvas.toDataURL('image/png')
// 转换成blob
// canvas.toBlob(function(blob){
// console.log(blob,'--blob--')
// },'image/png')
}
})
}
// 是否存在
Vue.prototype.$isset=(list,name)=>{
if(Vue.prototype.$typeOf(list)=='object'){
if(Object.hasOwnProperty.call(list,name)){
return true;
}else{
return false;
}
// list.hasOwnProperty(name)
// var keys=Object.keys(list)
// if(keys.indexOf(name)!=-1){
// return true;
// }else{
// return false;
// }
}else{
try{
var value=list[name].toString()
if(value && value!='' && value!='NAN' && value!=undefined){
return true;
}else{
return false;
}
}catch(err){
return false;
}
}
}
}
export default install
自定义指令:
<span v-auth="'placeorder'">更多</span>
Vue.directive("auth", {
inserted: (el, binding) => {
el.style.display = "none";
let key = "";
let txt = "";
if (data instanceof Object) {
key = binding.value.key;
txt = binding.value.txt;
} else {
key = binding.value;
}
// 存在权限
if (key) {
el.style.display = "revert";
} else {
// 存在可替换的值,就实现替换
if (txt != "") {
// document.createTextNode
const Dom = document.createElement("div");
Dom.innerHTML = txt;
const styleObject = { display: "", width: "", height: "" };
const styleArray = [
...Object.entries(styleObject).map((item) => {
if (window.getComputedStyle) {
return `${item[0]}:${window
.getComputedStyle(el)
.getPropertyValue(item[0])}`;
} else {
return `${item[0]}:${el.currentStyle[item[0]]}`;
}
}),
"text-align:center",
];
Dom.style = styleArray.join(";");
el.parentNode.replaceChild(Dom, el);
} else {
// 没有可替换的,就删除
el.parentNode.removeChild(el);
}
}
},
});
自定义指令也像组件那样存在钩子函数:
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用
unbind:只调用一次,指令与元素解绑时调用
钩子函数的参数都有以下:
el:指令所绑定的元素,可以用来直接操作 DOM
binding:一个对象,包含以下 property:
`name`:指令名,不包括 v- 前缀。
`value`:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
`oldValue`:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
`expression`:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
`arg`:传给指令的参数,可选。例如 v-my-directive:xx中,参数为 "xx"。
`modifiers`:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
`vnode`:Vue 编译生成的虚拟节点
`oldVnode`:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用
使用:
import install from './assets/appConfig/install'
install(Vue)
uniapp返回页面方法以及判断:
/**
* 返回页面执行方法
* index 返回的页数,默认1 返回上一页
*/
export function navigateBack(index=1) {
return new Promise((r, j) => {
const pages = getCurrentPages();
const beforePage = pages[pages.length - (index+1)];
if (!beforePage) {
// uni.showToast({
// title: '前面没有页面啦~',
// icon: 'none'
// })
j()
}
// #ifdef H5
r({
beforePage,
navigateBack() {
uni.navigateBack({
delta:index
})
}
})
// #endif
// #ifndef H5
r({
beforePage: beforePage.$vm,
navigateBack() {
uni.navigateBack({
delta:index
})
}
})
// #endif
})
}
使用:
//可以传值 navigateBack(2),表示返回上两页
navigateBack().then(res => {
const {
beforePage,
navigateBack
} = res
//beforePage,返回页面的this,可以获取返回页面的数据和方法
navigateBack()//返回
})