前端常用简单代码汇总

296 阅读6分钟

height: calc(100vh - 60px) 不生效

// 不生效
.demo {
  height: calc(100vh - 60px);
}

// 使用这种方式
.demo {
  height: calc(~"100vh - 60px");
}

禁止小程序自定义弹窗时滑动地下内容跟着滑动

<view wx:if="{{isShow}}" catchtouchmove="preventTouchMove">
  ...
</view>

/**
  * 阻止touchmove这样一个冒泡事件继续向下传递。防止屏幕滚动
  */
preventTouchMove() {},

使用URLSearchParams方法实现获取url参数

const urlSearchParams = new URLSearchParams(window.location.search); 
const params = Object.fromEntries(urlSearchParams.entries()); 
console.log(params) // {id: '2', isShare: 'true'} 
console.log(params.id) // 2

修复点击无效

在苹果系统上有些情况下非可点击元素监听click事件可能会无效,针对该情况只需对不触发click事件的元素声明cursor:pointer就能解决。

.elem {
    cursor: pointer;
}

禁止鼠标选中文本

* {
  -webkit-user-select: none;
  -moz-user-select: none;
  -o-user-select: none;
  user-select: none;
}

快速获取时间戳

console.log(+new Date) // 1636356622849

苹果X底部安全区留白

env()constant(),是IOS11新增特性,Webkit的css函数,用于设定安全区域与边界的距离,有4个预定义变量:

  • safe-area-inset-left:安全区域距离左边边界的距离
  • safe-area-inset-right:安全区域距离右边边界的距离
  • safe-area-inset-top:安全区域距离顶部边界的距离
  • safe-area-inset-bottom :安全距离底部边界的距离

env()constant()函数有个必要的使用前提,H5网页设置viewport-fit=cover的时候才生效,小程序里的viewport-fit默认是cover。

<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
height: calc(96rpx+ constant(safe-area-inset-bottom));//兼容 IOS<11.2

height: calc(96rpx + env(safe-area-inset-bottom));//兼容 IOS>11.2

padding-bottom: constant(safe-area-inset-bottom);//兼容 IOS<11.2

padding-bottom: env(safe-area-inset-bottom);//兼容 IOS>11.2

// 先constant再env

高精度权限控制 ——自定义指令directive

我们通常给一个元素添加 v-if / v-show 来做权限管理,但如果判断条件繁琐且多个地方需要判断,这种方式的代码不仅不优雅而且冗余。

针对这种情况,我们可以通过全局自定义指令来处理:我们先在新建个 array.js 文件,用于存放与权限相关的全局函数;

// array.js
export function checkArray(key) {
  let arr = ['1', '2', '3', '4', 'demo'];
  let index = arr.indexOf(key);
  if (index > -1) {
    return true; // 有权限
  } else {
    return false; // 无权限
  }
}

然后在将 array 文件挂载到全局中:

// main.js
import { checkArray } from './common/array';
Vue.directive('permission', {
  inserted(el, binding) {
    let permission = binding.value; // 获取到 v-permission的值
    if (permission) {
      let hasPermission = checkArray(permission);
      if (!hasPermission) {
        // 没有权限 移除Dom元素
        el.parentNode && el.parentNode.removeChild(el);
      }
    }
  },
});

最后我们在页面中就可以通过自定义指令 v-permission 来判断:

<div class="btns">
  <button v-permission="'1'">权限按钮1</button> // 会显示
  <button v-permission="'10'">权限按钮2</button> // 无显示
  <button v-permission="'demo'">权限按钮3</button> // 会显示
</div>

唤起qq

qq推广

<a
  target="_blank"
  href="http://wpa.qq.com/msgrd?v=3&uin=1354427009&site=qq&menu=yes"
>
    <img
        border="0"
        src="http://wpa.qq.com/pa?p=2:1354427009:52"
        alt="点击这里给我发消息"
        title="点击这里给我发消息"
    />
</a>

弹出数字键盘

<!-- 有"#" "*"符号输入 -->
<input type="tel">

<!-- 纯数字 -->
<input pattern="\d*">

调用系统的某些功能

<!-- 拨号 -->
<a href="tel:10086">打电话给: 10086</a>

<!-- 发送短信 -->
<a href="sms:10086">发短信给: 10086</a>

<!-- 发送邮件 -->
<a href="mailto:839626987@qq.com">发邮件给:839626987@qq.com</a>

<!-- 选择照片或者拍摄照片 -->
<input type="file" accept="image/*">

<!-- 选择视频或者拍摄视频 -->
<input type="file" accept="video/*">

<!-- 多选 -->
<input type="file" multiple>

打开原生应用

<a href="weixin://">打开微信</a>

<a href="alipays://">打开支付宝</a>

<a href="alipays://platformapi/startapp?saId=10000007">打开支付宝的扫一扫功能</a>

<a href="alipays://platformapi/startapp?appId=60000002">打开支付宝的蚂蚁森林</a>

禁止点击穿透

移动端浏览器里点击操作会存在300ms延迟,往往会造成点击延迟甚至点击无效,这个是众所周知的事情。

2007年苹果发布首款iPhone搭载的Safari为了将桌面端网站能较好地展示在移动端浏览器上而使用了双击缩放。该方案就是上述300ms延迟的主要原因,当用户执行第一次单击后会预留300ms检测用户是否继续执行单击,若是则执行缩放操作,若否则执行点击操作。鉴于该方案的成功,其他移动端浏览器也复制了该方案,现在几乎所有移动端浏览器都配备该功能。而该方案引发的点击延迟被称为点击穿透

在前端领域里最早解决点击穿透是jQuery时代zepto,估计现在大部分同学都未使用过zepto,其实它就是移动端版本的jqueryzepto封装tap事件能有效地解决点击穿透,通过监听document上的touch事件完成tap事件的模拟,并将tap事件冒泡到document上触发。

移动端浏览器上不使用click事件而使用touch事件是因为click事件有着明显的延迟,后续又出现fastclick。该解决方案监听用户是否做了双击操作,可正常使用click事件,而点击穿透就交给fastclick自动判断。更多fastclick原理可自行百度,在此不作过多介绍。

fastclick有现成的NPM包,可直接安装到项目里。引入fastclick可使用click事件代替tap事件,接入方式极其简单。

import Fastclick from "fastclick";

FastClick.attach(document.body);

禁止滑动穿透

移动端浏览器里出现弹窗时,若在屏幕上滑动能触发弹窗底下的内容跟着滚动,这个是众所周知的事情。

首先明确解决滑动穿透需保持哪些交互行为,那就是除了弹窗内容能点击或滚动,其他内容都不能点击或滚动。目前很多解决方案都无法做到这一点,全部解决方案都能禁止<body>的滚动行为却引发其他问题。

  • 弹窗打开后内部内容无法滚动
  • 弹窗关闭后页面滚动位置丢失
  • Webview能上下滑动露出底色

当打开弹窗时给<body>声明position:fixed;left:0;width:100%并动态声明top。声明position:fixed会导致<body>滚动条消失,此时会发现虽然无滑动穿透,但页面滚动位置早已丢失。通过scrollingElement获取页面当前滚动条偏移量并将其取负值且赋值给top,那么在视觉上就无任何变化。当关闭弹窗时移除position:fixed;left:0;width:100%和动态top

scrollingElement可兼容地获取scrollTopscrollHeight等属性,在移动端浏览器里屡试不爽。document.scrollingElement.scrollHeight可完美代替曾经的document.documentElement.scrollHeight || document.body.scrollHeight,一眼看上去就是代码减少了。

该解决方案在视觉上无任何变化,完爆其他解决方案,其实就是一种反向思维和障眼法。该解决方案完美解决固定弹窗滚动弹窗<body>全局滚动的影响,当然也可用于局部滚动容器里,因此很值得推广。

body.static {
    position: fixed;
    left: 0;
    width: 100%;
}
const body = document.body;
const openBtn = document.getElementById("open-btn");
const closeBtn = document.getElementById("close-btn");
openBtn.addEventListener("click", e => {
    e.stopPropagation();
    const scrollTop = document.scrollingElement.scrollTop;
    body.classList.add("static");
    body.style.top = `-${scrollTop}px`;
});
closeBtn.addEventListener("click", e => {
    e.stopPropagation();
    body.classList.remove("static");
    body.style.top = "";
});

VUE中导出excel表格数据

npm install vue-json-excel -S

// main.js
import JsonExcel from "vue-json-excel";
Vue.component("downloadExcel", JsonExcel);

// 组件内使用
<download-excel
  class = "export-excel-wrapper"
  :data = "json_data"
  :fields = "json_fields"
  name = "filename.xls">
  <!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
  <!-- <el-button type="primary" size="small">导出EXCEL</el-button> -->
</download-excel>

[图片上传失败...(image-a9e6ad-1642126553669)]

element-ui DateTimePicker设置只能选择当前时间之前或之后的时间

<el-date-picker
  v-model="form.timeValue"
  type="daterange"
  :picker-options="pickerOptions" // 配置这里
  :clearable="false"
  value-format="yyyy-MM-dd"
  range-separator="至"
  start-placeholder="开始日期"
  end-placeholder="结束日期">
</el-date-picker>

data() {
  return {
    pickerOptions: {
      disabledDate (time) {
        return time.getTime() < Date.now() // 选当前时间之后的时间
        return time.getTime() > Date.now() // 选当前时间之前的时间
      }
    },
  }
}

vue移动端适配不同手机(使用vant)

yarn add amfe-flexible postcss-pxtorem

// main.js
import 'amfe-flexible/index.js'

// index.html
<script>
  document.documentElement.style.fontSize = document.documentElement.clientWidth / 3.75 + 'px';
</script>

// postcss.config.js
module.exports = {
  plugins: {
    'autoprefixer': {},
    'postcss-pxtorem': {
      rootValue: 37.5,
      propList: ['*']
    }
  }
}

Vue实现点击按钮复制文本内容

import Clipboard from 'clipboard'

<section
    class='tag-read'
    data-clipboard-text="我是要复制的内容"
    @click="handleCopy"
></section>

handleCopy () {
    const clipboard = new Clipboard('.tag-read')
    clipboard.on('success', e => {
        console.log('复制成功')
        // 释放内存
        clipboard.destroy()
    })
    clipboard.on('error', e => {
        // 不支持复制
        console.log('该浏览器不支持自动复制')
        // 释放内存
        clipboard.destroy()
    })
}