常用js、css、小程序、VUE的方法(持续更新~)

常用js、css、小程序的方法

一、js部分

1.1 过滤HTML标签

function filterHTMLTag(str) {
    var msg = str.replace(/<\/?[^>]*>/g, ''); //去除HTML Tag
    msg = msg.replace(/[|]*\n/, ''); //去除行尾空格
    msg = msg.replace(/&nbsp;/ig, ''); //去掉npsp
    return msg;
}

1.2 input输入内容正则表达式校验

//只能输入数字
onkeyup="value=value.replace(/^(0+)|[^\d]+/g,'')"

//只能输入正整数,且最大80最小0
oninput="if(!/^[0-9]+(\.[0-9]{0,4})?$/.test(value)) value=value.replace(/\D/g,'');if(value>80)value=80;if(value<0)value=0"

//金额格式判断
function onlyNumber(obj){    
    
    //得到第一个字符是否为负号    
    var t = obj.value.charAt(0);      
    //先把非数字的都替换掉,除了数字和.和-号    
    obj.value = obj.value.replace(/[^\d\.\-]/g,'');       
    //前两位不能是0加数字      
    obj.value = obj.value.replace(/^0\d[0-9]*/g,''); 
    //必须保证第一个为数字而不是.       
    obj.value = obj.value.replace(/^\./g,'');       
    //保证只有出现一个.而没有多个.       
    obj.value = obj.value.replace(/\.{2,}/g,'.');       
    //保证.只出现一次,而不能出现两次以上       
    obj.value = obj.value.replace('.','$#$').replace(/\./g,'').replace('$#$','.');  
    //如果第一位是负号,则允许添加    
    obj.value = obj.value.replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3');  
   if(t == '-'){ return; }    

} 
//vue   
handleNumber(index){
   //先把非数字的都替换掉,除了数字和.s
    this.tableData[index].pressure = this.tableData[index].pressure.replace(/[^\d\.]/g,'');
    //前两位不能是0加数字
    this.tableData[index].pressure = this.tableData[index].pressure.replace(/^0\d[0-9]*/g,'');
    //必须保证第一个为数字而不是.
    this.tableData[index].pressure = this.tableData[index].pressure.replace(/^\./g,'');
    //保证只有出现一个.而没有多个. 
    this.tableData[index].pressure = this.tableData[index].pressure.replace(/\.{2,}/g,'.');
    //保证.只出现一次,而不能出现两次以上 
    this.tableData[index].pressure = this.tableData[index].pressure.replace('.','$#$').replace(/\./g,'').replace('$#$','.');
    this.tableData[index].pressure = this.tableData[index].pressure.replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3');
},
//多个判定优化
@input="handleNumber(form, 'wallThickness')"
handleNumber(obj, key){
  const original = obj[key].toString()
  let value = original

  // 处理流程
  value = value
    .replace(/[^\d.]/g, '')           // 清除非法字符
    .replace(/^0+(?=\d)/, '')         // 去除前导零
    .replace(/^\./, '0.')             // 处理.开头的情况
    .replace(/(\.\d*)\./g, '$1')     // 防止多个小数点
    .replace(/(\..*)\./g, '$1')      // 处理多个小数点(替代标记方案)
    .replace(/(\.\d{2})\d+/, '$1')   // 限制两位小数

  // 更新数据需要Vue.set保证响应式
  if (value !== original) {
    this.$set(obj, key, value)
  }
},

1.3 点击按钮使input标签获取焦点在文字末尾

$(".phoneclick").on("click",function(){
 	var $val = $("#userPhone").val();
 	$("#userPhone").val("").focus().val($val);
})

1.4 监听页面是否全屏及点击全屏

//监听是否全屏
window.onresize = function (){
  var isFull = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
  if(isFull){
    console.log('全屏')
  } else{
  	console.log('没有全屏')
  }
}
//点击全屏
let exitFullscreen = false;
// 全屏事件
function handleFullScreen() {
	let element = document.documentElement;
	if(this.fullscreen) {
		if(document.exitFullscreen) {
			document.exitFullscreen();
		} else if(document.webkitCancelFullScreen) {
			document.webkitCancelFullScreen();
		} else if(document.mozCancelFullScreen) {
			document.mozCancelFullScreen();
		} else if(document.msExitFullscreen) {
			document.msExitFullscreen();
		}
	} else {
		if(element.requestFullscreen) {
			element.requestFullscreen();
		} else if(element.webkitRequestFullScreen) {
			element.webkitRequestFullScreen();
		} else if(element.mozRequestFullScreen) {
			element.mozRequestFullScreen();
		} else if(element.msRequestFullscreen) {
			// IE11
			element.msRequestFullscreen();
		}
	}
}

1.5 获取元素的上一个、下一个兄弟元素

var chils= s.childNodes;  //得到s的全部子节点
var par=s.parentNode;   //得到s的父节点
var ns=s.nextSibling;   //获得s的下一个兄弟节点
var ps=s.previousSibling;  //得到s的上一个兄弟节点
var fc=s.firstChild;   //获得s的第一个子节点
var lc=s.lastChild;   //获得s的最后一个子节点

1.6 数组去除重复数据

//遍历数组法
let oldArr = [1, 2, 3, 4, 5, 5 , 6, 7, 8, 2, 3];
let newArr = unique(oldArr);
function unique(arr){
	let hash=[];
	for (let i = 0; i < arr.length; i++) {
		if(hash.indexOf(arr[i]) === -1){
			hash.push(arr[i]);
		}
	}
	return hash;
}
//数组下标判断法
let oldArr = [1, 2, 3, 4, 5, 5 , 6, 7, 8, 2, 3];
let newArr = unique(oldArr);
function unique(arr){
	let hash=[];
	for (let i = 0; i < arr.length; i++) {
		if(arr.indexOf(arr[i]) === i){
			hash.push(arr[i]);
		}
	}
	return hash;
}
//排序后判断
function unique(arr){
	arr.sort();
	let hash = [arr[0]];
	for (let i = 1; i < arr.length; i++) {
		if (arr[i] != hash[hash.length-1]) {
			hash.push(arr[i]);
		}
	}
	return hash;
}

1.7 文本输入时禁用粘贴

<div id="outer">
  <textarea id="test"></textarea>
</div>
<script>
 	var test = document.getElementById('test');
	//禁止粘贴
	test.onpaste = function () {
	  return false;
	};
	//禁止拖拽文字进入文本框
	test.ondrop = function () {
	  return false;
	};
</script>

1.8 js给静态文件增加时间戳

<script>
    document.write('<link href="../css/main.css?v=' + new Date().getTime() + '" rel="stylesheet" type="text/css"/>');
	document.write('<script src="js/textarea.js?' + new Date().getTime() + '"><\/script\>');
	document.write('<img style="height: 200px; width: 200px" src="${pageContext.request.contextPath}/img/page.jpg?time=' + new Date().getTime() + '"class="a b" />');
</script>

1.9 根据数组属性值把一个数组拆分为多个数组

//第一种方法
//原始数组
let arr = [
     { date: '2018-01-06',SW: '90.95', LL: '136', XXSW: '80.22',CKLL: '500' },
     { date: '2018-01-06', SW: '164.95', LL: '137', XXSW: '99.22', CKLL: '93' },
     { date: '2018-01-07', SW: '176.95', LL: '236', XXSW: '99.22', CKLL: '93' },
     { date: '2018-01-07', SW: '178.95', LL: '236', XXSW: '99.22', CKLL: '93' },
     { date: '2018-01-07', SW: '182.95', LL: '236', XXSW: '99.22', CKLL: '93' },
     { date: '2018-01-08', SW: '187.95', LL: '366', XXSW: '99.22', CKLL: '93' },
     { date: '2018-01-09', SW: '197.95', LL: '466', XXSW: '99.22', CKLL: '93' }
   ]
//调用方法
let dataArr = [];
arr.map(mapItem => {
  if (dataArr.length == 0) {
      dataArr.push({ date: mapItem.date, List: [mapItem] })
  } else {
     let res = dataArr.some(item=> {//判断相同日期,有就添加到当前项
      if (item.date == mapItem.date) {
        item.List.push(mapItem)
        return true
      }
    })
    if (!res) {//如果没找相同日期添加一个新对象
      dataArr.push({ date: mapItem.date, List: [mapItem] })
    }
  }
})
//结果
dataArr = [
        {
            date:'2018-01-06',
            List: [
                { date: '2018-01-06', SW: '90.95', LL: '136', XXSW: '80.22', CKLL: '500' },
                { date: '2018-01-06', SW: '164.95', LL: '137', XXSW: '99.22', CKLL: '93' }
            ]
        },
        {
            date:'2018-01-07',
            List: [
                { date: '2018-01-07', SW: '176.95', LL: '236', XXSW: '99.22', CKLL: '93' },
                { date: '2018-01-07', SW: '178.95', LL: '236', XXSW: '99.22', CKLL: '93' },
                { date: '2018-01-07', SW: '182.95', LL: '236', XXSW: '99.22', CKLL: '93' },
            ]
        },
        {
            date:'2018-01-08',
            List: [
                 { date: '2018-01-08', SW: '187.95', LL: '366', XXSW: '99.22', CKLL: '93' },
            ]
        },
        {
            date:'2018-01-09',
            List: [
                { date: '2018-01-09', SW: '197.95', LL: '466', XXSW: '99.22', CKLL: '93' }
            ]
        }
    ]

//第二种方法
var arr=[{name:2,id:3},{name:2,id:4},{name:3,id:5},{name:3,id:6},{name:1,id:1},{name:1,id:2}];
// 传入一个数组
// 按照特定方式格式化
function sortArr(arr, str) {
    var _arr = [],
        _t = [],
        // 临时的变量
        _tmp;
 
    // 按照特定的参数将数组排序将具有相同值得排在一起
    arr = arr.sort(function(a, b) {
        var s = a[str],
            t = b[str];
 
        return s < t ? -1 : 1;
    });
 
    if ( arr.length ){
        _tmp = arr[0][str];
    }
    // console.log( arr );
    // 将相同类别的对象添加到统一个数组
    for (var i in arr) {
        console.log( _tmp);
        if ( arr[i][str] === _tmp ){
            console.log(_tmp)
            _t.push( arr[i] );
        } else {
            _tmp = arr[i][str];
            _arr.push( _t );
            _t = [arr[i]];
        }
    }
    // 将最后的内容推出新数组
    _arr.push( _t );
    return _arr;
}
var kk = sortArr( arr, 'name');
kk = [
	    [
	        {
	            "name": 1,
	            "id": 1
	        },
	        {
	            "name": 1,
	            "id": 2
	        }
	    ],
	    [
	        {
	            "name": 2,
	            "id": 3
	        },
	        {
	            "name": 2,
	            "id": 4
	        }
	    ],
	    [
	        {
	            "name": 3,
	            "id": 5
	        },
	        {
	            "name": 3,
	            "id": 6
	        }
	    ]
	]

1.10 判断电脑还是手机登录

//第一种
window.location.href = /Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent) ? "https://www.honestdo.com/" :  "http://news.baidu.com/";
		
//第二种办法
function browserRedirect() {
		var sUserAgent = navigator.userAgent.toLowerCase();
		var bIsIpad = sUserAgent.match(/ipad/i) == "ipad";
		var bIsIphoneOs = sUserAgent.match(/iphone os/i) == "iphone os";
		var bIsMidp = sUserAgent.match(/midp/i) == "midp";
		var bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4";
		var bIsUc = sUserAgent.match(/ucweb/i) == "ucweb";
		var bIsAndroid = sUserAgent.match(/android/i) == "android";
		var bIsCE = sUserAgent.match(/windows ce/i) == "windows ce";
		var bIsWM = sUserAgent.match(/windows mobile/i) == "windows mobile";
		if (bIsIpad || bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM) {
				document.writeln("phone");
		} else {
				document.writeln("pc");
		}
}

1.11 循环创建layui时间控件

layui.use(['form', 'layer', 'jquery', 'laydate'], function () {
     var form = layui.form
         , $ = layui.jquery
         , layer = layui.layer
         , laydate = layui.laydate;

     //渲染时间控件
     function timeRender(){
         lay('.meetingTime').each(function() {//循环渲染
             laydate.render({
                 elem : this
                 , type : 'datetime'
                 , trigger : 'click'
             });
         });
         //在每次动态生成laydate组件时, laydate框架会给input输入框增加一个lay-key="1",
         //这样就导致了多个laydate 的inpute框都有lay-key="1"这个属性。导致时间控件不起作用,
         //需要把动态生成的lay-key属性删除
         $(".meetingTime").removeAttr("lay-key");
     }
	 //页面加载的时候对已经有的控件进行初始化
     timeRender();
});

1.12 监听视频播放

//视频加载后获取视频的长度
var elevideo = document.getElementById("video");
elevideo.addEventListener('loadedmetadata', function () { //加载数据
    //视频的总长度
    console.log(elevideo.duration);
    //currentTime在谷歌浏览器上无法成功,因为谷歌浏览器的视频必须是http开头的src,否则无法设置currentTime
    // elevideo.currentTime = 20;
    //elevideo.play();
});

//视频开始播放
elevideo.addEventListener('play', function () { //播放开始执行的函数
    console.log("开始播放");
});
// 视频正在播放中
elevideo.addEventListener('playing', function () { //播放中
   console.log("播放中");
});
//视频加载中
elevideo.addEventListener('waiting', function () { //加载
    console.log("加载中");
});
//视频暂停播放
 elevideo.addEventListener('pause', function () { //暂停开始执行的函数
    console.log("暂停播放");
    
});
//视频结束播放
elevideo.addEventListener('ended', function () { //结束
    console.log("播放结束");
}, false);

$("#btn").click(function(){
	//elevideo.currentTime = 5;
})
$("#video").on("timeupdate",function(){
	$("#textInfo").text("当前播放时间:"+parseInt(this.currentTime) + "s");
	//console.log(this.currentTime);
	//console.log(this.duration);
})
//禁止视频的右键功能
$('#video').bind('contextmenu',function() { return false; });
//禁止页面右键及F12,但是浏览器也有办法打开F12,此方法只能对不懂的人又用,懂得都知道这个没什么用
document.oncontextmenu = function () { return false; };
document.onkeydown = function () {
       if (window.event && window.event.keyCode == 123) {
           event.keyCode = 0;
           event.returnValue = false;
           return false;
       }
   };

1.13 浏览器窗口获取、失去焦点监听(附带是否切屏代码)

window.onblur = function () {
  document.title = "小伙不要走,我要和你对决";
}

window.onfocus = function () {
  document.title = "亲,欢迎你回来";
}

//切屏判断代码
var hiddenProperty = 'hidden' in document ? 'hidden' : 
           'webkitHidden' in document ? 'webkitHidden' : 
            'mozHidden' in document ? 'mozHidden' : 
           null;
var g_num = 0;//时间
var g_index = 0;//次数
var g_time;
var visibilityChangeEvent = hiddenProperty.replace(/hidden/i, 'visibilitychange');
var onVisibilityChange = function(){
  if (!document[hiddenProperty]) { 
			g_index++;
			clearInterval(g_time);
			if(g_index == 3){
				alert("切出次数达到3次,已自动提交。");
			}else{
				alert("你已经切出去"+g_index+"次,本次切出去时间为"+g_num+"s,达到3次将自动提交。");   
			}
   }else{
 		g_num = 0;
		g_time = setInterval(function(){
				g_num++;
				},1000)   
  }
}
 document.addEventListener(visibilityChangeEvent, onVisibilityChange);

1.14 身份证格式校验

function isCnNewID(cid){
    var arrExp = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];//加权因子
    var arrValid = [1, 0, "X", 9, 8, 7, 6, 5, 4, 3, 2];//校验码
    if(/^\d{17}\d|x$/i.test(cid)){
        var sum = 0, idx;
        for(var i = 0; i < cid.length - 1; i++){
            // 对前17位数字与权值乘积求和
            sum += parseInt(cid.substr(i, 1), 10) * arrExp[i];
        }
        // 计算模(固定算法)
        idx = sum % 11;
        // 检验第18为是否与校验码相等
        return arrValid[idx] == cid.substr(17, 1).toUpperCase();
    }else{
        return false;
    }
}

1.15 微信浏览器校验

function userAgentWx() {
 var useragent = navigator.userAgent;
 if (useragent.match(/MicroMessenger/i) != 'MicroMessenger') {
     // 这里警告框会阻塞当前页面继续加载
     alert('请在微信客户端访问本页面');
 }
}

二、css部分

2.1 屏蔽标签的选中效果

.main{
	-webkit-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    user-select:none;
}

2.2 滚动条样式修改

.menuList::-webkit-scrollbar{ 
	height:8px !important
}
.menuList::-webkit-scrollbar{
	width:10px;
	height:10px;
}
.menuList::-webkit-scrollbar-thumb{
	border-radius:10px;
	background-color:#02adf7;
}
.menuList::-webkit-scrollbar-track{
	background-color:#02adf7;
	-webkit-box-shadow:inset 0 0 5px rgba(0,0,0,0.2);
}

2.3 翻转效果

<div class="par">
    <div class="container">
        <div class="one hide">隐藏在背后的元素</div>
        <div class="two show">初始显示在前面的元素</div>
    </div>
</div>
//js
setInterval(function(){
 		if($(".container").css("transform") != "none"){
 			$(".container").attr("style","transform");
 		}else{
 			$(".container").css("transform","rotateX(180deg)");
 		}
 		
 	},1000)
//css
*{ margin: 0; padding: 0; box-sizing: border-box; }
.container, .one, .two{ width: 100px; height: 100px; }
.container{ position: relative; transition: 1s; transform-style: preserve-3d; }
.container:hover { transform: rotateX(180deg); }
.one{ position: absolute; top: 0; background: red; transform: rotateX(180deg);backface-visibility: hidden;}/*两个元素的位置一致,把背面隐藏起来,背面的元素翻转过来*/
.two{ position: absolute; top: 0; background: yellow;backface-visibility: hidden;}

2.4 文本内容超出多行隐藏

.title{
	width: 100%;
	overflow: hidden; 
	text-overflow: ellipsis; //溢出用省略号显示
	display: -webkit-box; // 将对象作为弹性伸缩盒子模型显示。
	-webkit-line-clamp: 2; //超出两行隐藏
	-webkit-box-orient: vertical; // 从上到下垂直排列子元素
}

2.5 文字渐变&阴影

<span class="title" text="测试内容">测试内容</span>

.title{
	text-shadow: 0px 0.3125rem 0.1875rem #000000;//阴影
    margin-top: 0.625rem;
    display: inline-block;
}
.title::before{
	content: attr(text);
    text-shadow: none;
    background: linear-gradient(to bottom, #ffffff 40%, #93d8ff 100%);//渐变色
    -webkit-text-fill-color: transparent;
    background-clip: text;
    position: absolute;
    left: 0;
    top: 0;
}

2.6 边框渐变

<div class="companySearchBlock">
	<el-input v-model="companyName" placeholder="请输入名称进行搜索" @change="search" maxlength="50" clearable></el-input>
</div>
//这种带圆角的边框渐变 效果不是很准确
.companySearchBlock{
	.el-input{
		:deep(.el-input__wrapper){
              background-color: transparent;
              border-radius: 1.25rem;
              position: relative;
              overflow: hidden;
              box-shadow:0 0 0 1px #0cc7f4;
          }
          :deep(.el-input__inner){
              color: #ffffff;
          }
          :deep(.el-input__wrapper::before){
              content: '';
              position: absolute;
              top: 0;
              right: 0;
              bottom: 0;
              left: 0;
              border: 1px solid;
              border-image: linear-gradient(to bottom,#0cc7f4, #4861f9) 1;
          }
	}
}

三、小程序

3.1 获取元素节点信息

//创建SelectorQuery查询对象
let query = wx.createSelectorQuery()
//第一个匹配节点
query.select(queryString)
//所有匹配节点
query.selectAll(queryString)
//queryString 类型
	ID选择器:#the-id
	class选择器(可以连续指定多个):.a-class.another-class
	子元素选择器:.the-parent > .the-child
	后代选择器:.the-ancestor .the-descendant
	跨自定义组件的后代选择器:.the-ancestor >>> .the-descendant
	多选择器的并集:#a-node, .some-other-nodes

3.2 下拉刷新配置

//json中配置
"enablePullDownRefresh": true  // 请注意是true,不是"true"字符串,
                               // 部分开发者发现设置了还是无效,
                               // 可能是因为设置的"enablePullDownRefresh": "true"
//backgroundTextStyle配置 支持 dark/light  下拉刷新时显示的三个点闪烁的动画
"backgroundTextStyle": "dark"
//停止刷新动效 
wx.stopPullDownRefresh();
//下拉刷新回调方法 js中一般都有这个方法定义
onPullDownRefresh: function () {
  console.log('onPullDownRefresh')
},

3.3 动态修改数组对象的值

// pages/nav/nav.js
Page({
 
  /**
   * 页面的初始数据
   */
  data: {
    students: [
      {
        name: '张三',
        number: '1234'
      },
      {
        name: '李四',
        number: '1111'
      },
      {
        name: '王二狗',
        number: '6666'
      }
    ]
  },
 
  changeNumber: function (e) {
    let index = 2;
    let change = "students["+ index +"].number";
    this.setData({
      [change]: '9999'
    })
  }
})

3.4 tabBar菜单右上角显示内容

//添加内容显示
wx.setTabBarBadge({ 
   index: 1,						//标志添加位置 代表哪个tabbar(从0开始)
   text: "" + num + ""				//显示的内容
})
//移除内容显示
wx.removeTabBarBadge({    //移除指定位置的tabbar右上角的标志
   index: 1,
})

3.5 跳转带参过长加密与解密

var str = 'https://www.baidu.com/123?id=111'
 
//父组件加密
var encodeUrlParameter = encodeURIComponent(str) 
console.log(encodeUrlParameter);
 
//子组件解密
var urlParameter = decodeURIComponent(encodeUrlParameter);
console.log(urlParameter);

3.6 微信小程序显示富文本编辑器内容且支持内容中的a标签点击事件

//如果只显示富文本编辑器内容使用小程序的rich-text标签
<rich-text :nodes="html"></rich-text>


//如果要保留a标签点击事件使用mp-html组件
<mpHtml :content="html" @linktap="linkTap"></mpHtml>
//通过npm install mp-html下载依赖 然后引入依赖
import mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html'
//如果主包过大,建议把依赖里面的uni-app/components/mp-html/mp-html放入分包进行引入

四、VUE

4.1 表单rules校验手机号,邮箱等

rules: {
   mobile: [
     { required: true, message: "手机号不能为空", trigger: "blur" },
     {
       pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
       message: "请输入正确的手机号码",
       trigger: "blur"
     }
   ],
   password: [
     { required: true, message: "密码不能为空", trigger: "blur" },
     { min: 5, max: 20, message: '密码长度必须介于 5 和 20 之间', trigger: 'blur' }
   ],
   email: [
     {
       type: "email",
       message: "'请输入正确的邮箱地址",
       trigger: ["blur", "change"]
     }
   ],
 }

4.2 清除rules表单校验提示文字(切换登录方式)

this.$refs['loginForm'].clearValidate();

4.3 点击按钮复制文字或图片

//复制文字
copyLinkAddress(){
    const ele = document.createElement('input')
    // 设置元素内容
    ele.setAttribute('value', '复制的内容')
    // 将元素插入页面进行调用
    document.body.appendChild(ele)
    // 复制内容
    ele.select()
    // 将内容复制到剪贴板
    document.execCommand('copy')
    // 删除创建元素
    document.body.removeChild(ele)
    this.$message.success("内容已复制到剪切板")
}

//复制图片 
copyQrCode(){
    let container = this.$refs.qrCodeDiv.childNodes[1]
    let myBlob = this.base64ToBlob(container.getAttribute('src'))
    //navigator.clipboard只能在本地localhost 、127.0.0.1 或者 https 协议下使用,否则navigator没有clipboard方法。
    if (navigator.clipboard == undefined){
        this.$message.error("请在https协议下操作");
    }else{
        navigator.clipboard.write([new window.ClipboardItem({ [myBlob.type]: myBlob })])
        this.$message.success("复制二维码成功")
    }
},
//base64转Blob
base64ToBlob(dataurl) {
    var arr = dataurl.split(','),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], { type: mime });
}

注意:上面container 是qrcodejs2生成的二维码,看结构通过childNodes[1]直接获取img标签
在这里插入图片描述

4.4 el-table序号处理显示

<el-table-column label="序号" type="index" align="center">
    <template slot-scope="scope">
        <span v-text="getIndex(scope.$index)"> </span>
    </template>
</el-table-column>

//方法pageNum:第几页  pageSize:每页显示数量 $index:当前页第几个
getIndex($index){
    return (this.queryParams.pageNum - 1) * this.queryParams.pageSize + $index + 1
},

4.5 el-table固定表头无线滑动加载

//需要使用到el-table-infinite-scroll滑动组件
//命令:npm install --save el-table-infinite-scroll@1.0.10 最新版本引入有问题,需要固定版本号
//全局引入 main.js里面
import Vue from "vue"
import elTableInfiniteScroll from 'el-table-infinite-scroll'
Vue.use(elTableInfiniteScroll);
//页面
<el-table :data="userList" 
        v-el-table-infinite-scroll="load" 
        :infinite-scroll-disabled="isDisabled"
        height="210px" 
        style="overflow:auto;">
    <el-table-column type="selection" width="55" align="center" />
    <el-table-column label="试卷名称" align="center" key="userName" prop="userName"
        :show-overflow-tooltip="true" />
    <el-table-column label="试卷类型" align="center" key="testType" prop="testType"
        :show-overflow-tooltip="true" />
    <el-table-column label="创建人" align="center" key="phonenumber" prop="phonenumber" width="120" />
</el-table>
//方法
data() {
    return {
        // 总条数
        total: 20,
        userList: [],
        isDisabled:false,
    }
},
created() {
   this.getList()
},
methods: {
    //获取数据
    getList() {
        for(let i = 0;i<5;i++){
            var mm = {
                userName: "张三"+i,
                testType: "考试试卷"+i
            }
            this.userList.push(mm)
        }
    },
    //监听滚动
    load(){
        if (this.isDisabled) return;
        if (this.userList.length > this.total) {//最后一页
            this.isDisabled = true
        } else {
            this.getList()
        }
    },
},

4.6 el-table数据回显勾选

//回复勾选
setTimeout(function () {//加载数据方法中调用,延时是当数据渲染完成后才能勾选
    that.checkFunction()
}, 500)
checkFunction() {
    let list = []
    this.userList.forEach(val => {
        if (val.examinerExaminationPaperId != null) {
            list.push(val)
        }
    })
    if (list) {
        list.forEach((row) => {
            this.$refs.dataTable.toggleRowSelection(row, true)
        })
    }
},

4.7 el-table勾选调用接口及翻页显示已勾选的

//表格
<el-table ref="alloatUserTable" v-loading="loading" :data="recordList" @select="handleSelectionChange" @select-all="handleSelectAll">
    <el-table-column type="selection" width="55" align="center" />
    <el-table-column label="姓名" align="center" prop="nickName" />
    <el-table-column label="电话" align="center" prop="phonenumber" />
    <el-table-column label="性别" align="center" key="sex" prop="sex">
        <template slot-scope="scope">
            <span>{{ scope.row.sex == 0 ? '男' : '女' }}</span>
        </template>
    </el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
    :limit.sync="queryParams.pageSize" @pagination="getList" />

//-------js
/** 查询列表数据 */
getList() {
    this.loading = true;
    listExaminationAllotUser(this.queryParams).then(response => {
        this.recordList = response.rows;
        this.total = response.total;
        this.loading = false;
        this.ids = []
        this.$nextTick(() => {
            for (let i = 0; i < this.recordList.length; i++) {//当前页数据是否需要勾选
                if (this.recordList[i].examinationId != null) {
                    this.$refs.alloatUserTable.toggleRowSelection(this.recordList[i], true)
                    this.ids[this.ids.length] = this.recordList[i].userId//存入ids
                }
            }
        })
    });
},
// 多选框选中数据
handleSelectionChange(rows, row){
    if (this.ids.find((item) => item == row.userId)){//勾选的是否在ids中
        cancelAssignedExaminees({ userId: row.userId, examinationId: this.queryParams.examinationId }).then(response => {
            this.msgSuccess("取消分配成功");
             this.getList();
        });
    }else{
        assignedExaminees({ userId: row.userId, examinationId: this.queryParams.examinationId }).then(response => {
            this.msgSuccess("分配成功");
            this.getList();
        });
    }
},
//全选
handleSelectAll(rows){
    if (rows.length){
        for (var i = 0; i < rows.length;i++){
            assignedExaminees({ userId: rows[i].userId, examinationId: this.queryParams.examinationId }).then(response => {
                this.msgSuccess("分配成功");
                
            });
        }
        this.getList();
    }else{
        for (var i = 0; i < this.ids.length; i++ ){
            cancelAssignedExaminees({ userId: this.ids[i], examinationId: this.queryParams.examinationId }).then(response => {
                this.msgSuccess("取消分配成功");
                
            });
        }
        this.getList();
    }
},

4.8 子组件监听父组件传值更新

//监听函数
watch: {
    examinationPaperId(newValue, oldValue) {//examinationPaperId为监听的值
        this.queryParams.examinationPaperId = newValue
        this.handleQuery()
    },
    examinerUserId(newValue, oldValue) {
        this.queryParams.examinerUserId = newValue
        this.handleQuery()
    }
}

4.9 el-table实现单选

<el-table ref="dataTable"
         :data="userList" 
         @select="handleSelectionChange">
     <el-table-column type="selection" width="55" align="center" />
     <el-table-column label="试卷名称" align="center" prop="examinationPaperName"
         :show-overflow-tooltip="true"/>
     <el-table-column label="试卷类型" align="center" prop="examinationPaperClassifyName"
         :show-overflow-tooltip="true" />
     <el-table-column label="总分" align="center" prop="totalScore" :show-overflow-tooltip="true" />
     <!-- <el-table-column label="创建人" align="center" prop="createBy" width="120" /> -->
 </el-table>
//单选处理
methods:{
	//selection为勾选的内容数组,row为当前勾选或取消的对象
	handleSelectionChange(selection, row) {
         if (selection.length > 1) {
         	//清除前面勾选的
             this.$refs.dataTable.clearSelection()
             this.$refs.dataTable.toggleRowSelection(selection.pop())
             this.ids = row.examinationPaperId
         } else if (selection.length == 1){
             this.ids = row.examinationPaperId
         }else{
             this.ids = ''
         }
     },
}
//css 隐藏头部全选框  因为使用的scoped(样式只在当前页面生效),需要使用深度选择器/deep/ 
<style lang="less" scoped>
	/deep/ thead .el-table-column--selection .cell {
	    display: none;
	}
</style>

4.10 el-tree回显选中效果

//获取tree数据后,需要根据条件默认勾选某一结点,并高亮显示
<el-tree :load="data" 
		:props="defaultProps"
		node-key="id"
		ref="tree"
		:check-on-click-node="true"
		:default-expanded-keys="treeExpandelKeys"
		highlight-current="true"
		check-strictly="true" lazy></el-tree>
//获取数据方法中使用setCurrentKey(通过 key 设置某个节点的当前选中状态,使用此方法必须设置 node-key 属性)进行高亮设置
setTimeout(function(){//高亮需要延时处理
	this.$nextTick(function(){
		//setCurrentKey是必须设置node-key;对应数据中的属性
		this.$refs.tree.setCurrentKey(this.processId)
	})
},600)
//**注意**
// 此处使用的是懒加载存在一个问题,首次加载的是一级节点,如果需要二级三级选中,需要设置treeExpandelKeys(默认展开的节点的 key 的数组),通过push循环把一级节点的数据push进入treeExpandelKeys中(只支持了一二级节点高亮回显)展开二级。然后加入上面的代码。

4.11 动态table输入框必填校验

//meterReadingRecords为表格数据对应的对象名
<el-table-column
    label="*本次读数">
    <template v-slot="{$index,row}">
        <el-form-item :prop="'meterReadingRecords.' + $index + '.thisTimeRead'" :rules="{
                required: true,
                message: '值不能为空',
                trigger: 'blur',
            }">
             <el-input v-model="row.thisTimeRead" placeholder="请输入" style="width:100%;"></el-input>
        </el-form-item>
    </template>
</el-table-column>

4.12 el-table勾选框实现单选效果

<el-table
    ref="multipleTable"
    :data="tableData"
    highlight-current-row
    style="width: 100%"
    @select="handleSelectionChange">
</el-table>

//选择
handleSelectionChange(val,row){
    let that = this;
    let obj = []
    if (val) {
        if (val.length > 1) {
            that.$refs.multipleTable.clearSelection();
            that.$refs.multipleTable.toggleRowSelection(val.pop());
        }
        obj[0] = row;
    } else {
        that.$refs.multipleTable.clearSelection();
        obj = null;
    }
    this.$emit("select",obj)
},
//css隐藏全选框
:deep(){
    .el-table__header-wrapper .el-checkbox {
        display: none !important;
    }
}

4.13 element plus 的日期范围控件限制选择区间

<el-date-picker
  v-model="time"
  type="daterange"
  value-format="YYYY-MM-DD"
  range-separator="至"
  :disabled-date="disabledDate"
  @calendar-change="handleChange"
  @focus="handleFocus"
  start-placeholder="开始日期"
  end-placeholder="结束日期">
</el-date-picker>

handleChange(val){
    const [pointDay] = val
    this.pickDay = pointDay //点击的第一个时间
},
handleFocus(){
    this.pickDay = null //清空
},
disabledDate(time){
    const limitTime = 1000 * 60 * 60 * 24 * 30
    if(this.pickDay){
        return (
            // time.getTime() < this.pickDay.getTime() - limitTime ||
            time.getTime() > this.pickDay.getTime() + limitTime //限制30天
            // || time.getTime() > Date.now()
        )
    }else{
        // return time.getTime() > Date.now() //未选择时间时只能选择不超过当天的日期
    }
},

4.14 el-upload自定义上传

//vue2
<el-upload 
    :file-list="form.paymentCertificate"
    class="upload-demo"
    acton="#"
    :limit="10"
    :before-upload="beforeUploadFile"
    :http-request="fileInput"
    :before-remove="removeFile"
>
    <el-button type="text">上传</el-button>
</el-upload>
//vue3
<el-upload ref="uploadRef" class="upload-demo" drag action="" multiple
   v-model:file-list="form.fileList" :before-upload="beforeUpload" :http-request="fileInput"
   @remove="removeFile" style="width: 100%;" :limit="20">
   <div class="flex flex-row items-center">
       <el-icon class="el-icon--upload"><upload-filled /></el-icon>
       <div class="el-upload__text ml-2">
           将文件拖到此处,或<em>点击上传</em>
       </div>
   </div>
   <template #tip>
       <div class="el-upload__tip">
           单个文件不超过20MB,支持的文件类型:doc、docx、pdf、txt
       </div>
   </template>
</el-upload>

//附件上传
fileInput(file){
    let formDate = new FormData() 
    formDate.append('file', file.file)
    filesSubmit(formDate).then((row) => {
       //vue2
       this.form.paymentCertificate.push(row.data)
       //vue3
      form.value.fileList = form.value.fileList.map((item) => {
           if (item.uid && item.uid == file.file.uid) {//查到上传的附件
               return {
                   ...res.data,
                   uid:file.file.uid,
                   name:file.file.name
               }
           }else{
               return item
           }
        })
    })
},
//移除附件
removeFile(file,fileList){
	//vue2
    this.form.paymentCertificate.splice(fileList.indexOf(file),1)
    //vue3
    form.value.paymentCertificate = form.value.paymentCertificate.filter(
        item => item.uid !== file.uid
    );
},
beforeUploadFile(file){
    if((file.size / 1024 / 1024) > 10){
        this.$message.warning("文件不能大于10M");
        return false
    }
    let fileType = file.name.substring(file.name.lastIndexOf('.') + 1);
    if(fileType !== "jpeg" && fileType !== "png"){
        this.$message.warning("只能上传jpeg、png格式的文件")
        return false
    }
},
//针对要获取点击的是第几个上传附件按钮 通过on-change来处理
<el-upload 
    :file-list="row.contractFileList"
    class="upload-demo"
    acton="#"
    :limit="10"
    :before-upload="beforeUploadFile"
    :http-request="fileInput"
    :before-remove="removeFile"
    :on-change="(file, fileList)=> {return onChange(file, fileList, $index)}"
    v-if="!isShowText"
>
    <el-button type="text">上传</el-button>
</el-upload>

onChange(file, fileList, index){
    this.index = index
},

4.15 动态控制下拉框(级联下拉框)宽度

<el-cascader
	ref="cascader"
    v-model="location"
    :options="options"
    placeholder=" "
    :props="{ expandTrigger: 'hover' }"
    :teleported="false"
    :show-all-levels="false"
    @change="handleChange"
    :style="{width: width}"
>
</el-cascader>

const cascader = ref();
//获取location文字的长度
const labelWidth = cascader.value.getCheckedNodes()[0].text.split("/").join("").length;
//根据字体大小控制下方的14;48是组件的padding,根据实际情况调整
width.value = (labelWidth * 14+48)+ "px";

4.16 自定义可拖拽弹窗

<div class="popup" v-if="popupShow" @mousedown="startDrag" :style="{right:`${x}rem`,bottom:`${y}rem`}">
	弹窗内容
</div>

const popupShow = ref(false);
const x = ref(100);
const y = ref(200);
//拖动
const startDrag = (event) => {
 // 记录初始鼠标位置
  const initialMouseX = event.clientX;
  const initialMouseY = event.clientY;
  //如果是大屏rem布局,根字体16px,做适配
  const zoon = (document.documentElement.clientWidth / 1920)*16;
  // 记录初始元素位置
  const initialX = (x.value)*zoon;
  const initialY = (y.value)*zoon;

  // 开始拖动,设置为true
  isDragging.value = true;

  // 当鼠标移动时执行的函数
  const dragging = (moveEvent) => {
    // 只有在拖动时才执行
    if (isDragging.value) {
      // 计算鼠标移动的距离
      const deltaX = moveEvent.clientX - initialMouseX;
      const deltaY = moveEvent.clientY - initialMouseY;

      // 更新元素的位置  left和top是加,right和bottom是减
      x.value = (initialX - deltaX)/zoon;
      y.value = (initialY - deltaY)/zoon;
    }
  };

  // 鼠标释放时停止拖动的函数
  const stopDrag = () => {
    // 结束拖动,设置为false
    isDragging.value = false;

    // 移除事件监听器
    document.removeEventListener('mousemove', dragging);
    document.removeEventListener('mouseup', stopDrag);
  };

  // 添加鼠标移动和释放时的事件监听器
  document.addEventListener('mousemove', dragging);
  document.addEventListener('mouseup', stopDrag);
}

4.17 自定义下拉框点击空白关闭下拉选项

//在弹框和按钮处加一个@click.stop 就相当于点击除了弹框和按钮的地方其他的地方都会关闭弹框
<div class="searchCondition">
    <span @click="openCondition" @click.stop>{{searchName}}</span>
    <div class="conditionList" v-if="conditionShow" @click.stop>
        <ul>
            <template v-for="(item,index) in conditionList" :key="index">
                <li :class="searchName == item.label?'active': ''" @click="checkCondition(item.label)">{{item.label}}</li>
            </template>
        </ul>
    </div>
</div>

onMounted(() => {
	window.addEventListener('click', closePopup)
})
const closePopup = (e) => {
    if(!e.target.classList.contains("companyInfo")){
        conditionShow.value = false;
    }
}
onUnmounted(() => {
  	window.removeEventListener('click', closePopup)
})

4.18 获取slot(插槽)的信息

<slot></slot>

import {useSlots,ref}  from 'vue'
const slots = useSlots();
const length = ref(slots?.default ? slots.default().length : 0);
const array = ref(slots?.default ? slots.default() : [])

4.19 自定义时间范围限制输入

示例

//vue3
 <el-date-picker v-model="start" type="date" value-format="YYYYMMDD" :disabled-date="disabledDate"
            placeholder="开始日期" />
 <span class="mx-1"></span>
 <el-date-picker v-model="end" type="date" :disabled="!start" :disabled-date="filterDate" value-format="YYYYMMDD"
            placeholder="结束日期" />

import { ref, watch } from "vue";
import dayjs from "dayjs";

const start = ref();
const end = ref();
const rangeValue = defineModel({ type: Array, default: [] });
const filterDate = time => {
    if (!start.value) return disabledDate(time);
    return  disabledDate(time) || dayjs(start.value).add(1, 'day') > dayjs(time)
}

const disabledDate = (time) => {
    return time.getTime() > Date.now()
}

watch(start, s => {
    if (!s) end.value = undefined;
    rangeValue.value = [s, end.value]
})
watch(end, e => {
    rangeValue.value = [start.value, e]
})
watch(rangeValue, v => {
    [start.value, end.value] = v || [];
})


//vue2
<el-date-picker v-model="requestStartTime" type="date" value-format="yyyy-MM-dd"
 :picker-options="pickerOptions()" class="el-date-picker" style="width: 130px !important;" placeholder="开始日期" />
 <span class="mx-1"></span>
 <el-date-picker v-model="requestEndTime" type="date" :disabled="!requestStartTime"
 style="width: 130px !important;" :picker-options="filterDate()" value-format="yyyy-MM-dd" placeholder="结束日期" />

pickerOptions() {
     return {
         disabledDate(time) {
             return time.getTime() > Date.now();
         },
     }
 },
filterDate() {
    let that = this;
    return {
        disabledDate(time) {
            if (!that.requestStartTime) return false;
            return time.getTime() < new Date(that.requestStartTime).getTime() || time.getTime() > Date.now();

        }
    }
},
watch:{
requestStartTime: function (newVal) {
    if (!newVal) this.requestEndTime = null;
         if (new Date(this.requestStartTime).getTime() > new Date(this.requestEndTime).getTime()) this.requestEndTime = null;
    },
},

4.20 VUE2 配置静态图片和字体文件自动转base64

//vue.config.js
chainWebpack: (config) => {
    config.module
      .rule('images')
      .use('url-loader')
      .loader('url-loader')
      .tap((options) => ({
        ...options,
        limit: 15360, // 15KB,超过此大小的图片转为文件
      }));
      config.module
      .rule('fonts')
      .test(/\.(woff|woff2?|eot|ttf)(\?.*)?$/)
      .use('url-loader')
      .loader('url-loader')
      .options({
        limit: 102400, // 4KB以下转base64
        name: 'fonts/[name].[hash:8].[ext]',
       // publicPath: process.env.NODE_ENV === 'production' 
        //  ? '/znyw-app/' // 强制指定生产环境路径
        //  : '/znyw-app/'
      })
  },
  //页面通过require引入图片
  data() {
    return {
      icon1: require("@/assets/icon1.png"),
      icon2: require("@/assets/icon2.png"),
      icon3: require("@/assets/icon3.png"),
      icon4: require("@/assets/icon4.png"),
      icon5: require("@/assets/icon5.png"),
    };
  },

4.21 根据后台返回的url下载文件(支持跨域),而不是PDF和text默认预览

const downloadFile = async (row) => {
    // 1. 发起跨域请求
    const response = await fetch(row.link, {
        mode: 'cors',
        credentials: 'include'
    })
    if (!response.ok) throw new Error(`下载失败: ${response.status}`)
    const blob = await response.blob()
    // 3. 创建临时链接
    const link = document.createElement('a')
    const objectUrl = URL.createObjectURL(blob)
    // 4. 配置下载参数
    link.href = objectUrl
    link.download = row.name || 'download'
    link.style.display = 'none'

    // 5. 触发下载
    document.body.appendChild(link)
    link.click()

    // 6. 清理资源
    setTimeout(() => {
        URL.revokeObjectURL(objectUrl)
        document.body.removeChild(link)
    }, 100)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值