Skip to content

SN

chrom 添加模拟 app 的设备

在 User agent string 一栏中填写

Mozilla/5.0 (iPod touch; CPU iPhone OS 9_2 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Mobile/13C75 2.0.24 CK 2.0

移动端横屏

css
@media screen and (orientation: landscape) {
  /*横屏*/
  main {
    width: 100vw;
    height: 100vh;
    background-color: #bfa;
  }
}

上拉加载分页

文件在旅行世界中/public_html/addons/ewei_shopv2/static/js/util.js

js
// 全局变量,两个函数
let getLog;
let bindScroller;
require(["tpl", "core"], function (tpl, core) {
  // 页码数
  var page = 1;
  // 滚动加载
  /**
   * author: gauharchan  http://person.gauhar.top
   * @param {sting} url      请求地址
   * @param {object} obj     请求数据对象
   * @param {string} container     内容容器,jq选择器,如:.container
   * @param {string} dataTemplate  数据‘不’为空时的模板,id,如:tpl-goods
   */
  bindScroller = function (url, obj, container, dataTemplate) {
    var loaded = false; // 加载状态
    var stop = true; // 双重保险
    $(window).scroll(function () {
      if (loaded) {
        // true的时候代表加载中
        return;
      }
      totalheight =
        parseFloat($(window).height()) + parseFloat($(window).scrollTop());
      if ($(document).height() - totalheight <= 30) {
        if (stop == true) {
          stop = false;
          // 加载提示
          core.loading();
          // 节流
          loaded = true;
          obj.page++;
          core.json(
            url,
            obj,
            function (json) {
              var morejson = json;
              stop = true;
              // 删除加载提示
              core.removeLoading();
              // $("#container").append(tpl('tpl_log', morejson));

              // 加载渲染完成
              loaded = false;
              // 渲染
              $(container).append(tpl(dataTemplate, json));
              if (!morejson.result || morejson.result.length < 20) {
                $(container).append(
                  '<div id="credit_loading" style="width:100%;text-align:center;margin:10px 0;">已经全部加载完成</div>'
                );
                loaded = true;
                $(window).scroll = null;
                return;
              }
            },
            true,
            true
          );
        }
      }
    });
  };
  /**
   * author: gauharchan  https://gauhar.gitee.io/
   * @param {sting} url      请求地址
   * @param {object} obj     请求数据对象
   * @param {string} container     内容容器,jq选择器,如:.container
   * @param {string} empty         数据为空时的模板,id,如:tpl_empty
   * @param {string} dataTemplate  数据‘不’为空时的模板,id,如:tpl-goods
   */
  getLog = function (url, obj, container, empty, dataTemplate) {
    // 去除浏览器滚动监听
    $(window).off("scroll");
    obj.page = page;
    core.json(
      url,
      obj,
      function (json) {
        console.log(json);
        if (!json.result || json.result.length <= 0) {
          $(container).html(tpl(empty));
          return;
        }
        $(container).html(tpl(dataTemplate, json));
        if (!json.result || json.result.length < 20) {
          $(container).append(
            '<div id="credit_loading" style="width:100%;text-align:center;margin:10px 0;">已经全部加载完成</div>'
          );
          return;
        }
        bindScroller(url, obj, container, dataTemplate);
      },
      true,
      true
    );
  };
});

记住密码

html

html
<!-- 记住密码 -->
<div class="password-box">
  <div class="right-box flex flex-ver">
    <div class="img-box">
      <img
        class="img-remeber"
        src="..//addons/sz_yi/template/mobile/style1/static/images/newImage/btn_xuanze.png"
        alt=""
      />
    </div>
    <span>记住密码</span>
  </div>
</div>

css

css
.password-box {
  display: flex;
  justify-content: flex-end;
  margin: 2% 10% 8%;
}

.img-box {
  display: flex;
  align-items: center;
  width: 20%;
}

.img-box .img-remeber {
  width: 100%;
}

.right-box span {
  color: #fff;
  margin-left: 3px;
}

js

js
let remeber = true;
// 記住密碼
$(".img-remeber").click(function () {
  remeber = !remeber;
  let src = remeber
    ? "..//addons/sz_yi/template/mobile/style1/static/images/newImage/btn_xuanze.png"
    : "..//addons/sz_yi/template/mobile/style1/static/images/newImage/btn_weixuanze.png";
  $(this).attr("src", src);
});

// 检测是否有记录密码
let pass = localStorage.getItem("password");
let pho = localStorage.getItem("phone");
if (pass && pho) {
  $("#mobile").val(pho);
  $("#password").val(pass);
}

// 登录按钮的请求
$(".info_sub").click(function () {
  if (!$("#mobile").isMobile()) {
    core.tip.show("请输入正确手机号码!");
    return;
  }
  if ($("#password").isEmpty()) {
    core.tip.show("请输入密码!");
    return;
  }
  let pass = $("#password").val();
  let pho = $("#mobile").val();
  core.json(
    "member/login",
    {
      memberdata: {
        mobile: $("#mobile").val(),
        password: pass,
      },
    },
    function (json) {
      if (json.status == 1) {
        // 記住密碼
        if (remeber) {
          localStorage.setItem("password", pass);
          localStorage.setItem("phone", pho);
        } else {
          localStorage.removeItem("password");
          localStorage.removeItem("phone");
        }
        core.tip.show("登录成功");
        location.href = json.result.preurl;
      } else {
        core.tip.show("用户不存在或密码错误!");
      }
    },
    true,
    true
  );
});

密码是否可见

js
/// 密码的显示和隐藏
let open =
  "../addons/ewei_shopv2/template/mobile/default/static/images/newImage/login/icon3-d.png";
let close =
  "../addons/ewei_shopv2/template/mobile/default/static/images/newImage/login/closeeye.png";

// 眼的点击方法
$(".eye").on("click", function () {
  let user = $(this).data("status");
  user = !user;
  user ? $(".eye").attr("src", open) : $(".eye").attr("src", close);
  user ? $("#pwd").attr("type", "text") : $("#pwd").attr("type", "password");
  $(this).data("status", user);
});

验证码

html:

html
<canvas id="canvas" width="100" height="40"></canvas>

js:

js
var show_num = [];
draw(show_num);

$("#canvas").on("click", function () {
  draw(show_num);
});

function draw(show_num) {
  var canvas_width = $("#canvas").width();
  var canvas_height = $("#canvas").height();
  var canvas = document.getElementById("canvas"); //获取到canvas的对象,演员
  var context = canvas.getContext("2d"); //获取到canvas画图的环境,演员表演的舞台
  canvas.width = canvas_width;
  canvas.height = canvas_height;
  var sCode = "A,B,C,E,F,G,H,J,K,L,M,N,P,Q,R,S,T,W,X,Y,Z";
  // var sCode = "1,2,3,4,5,6,7,8,9,0";
  var aCode = sCode.split(",");
  var aLength = aCode.length; //获取到数组的长度

  for (var i = 0; i <= 3; i++) {
    var j = Math.floor(Math.random() * aLength); //获取到随机的索引值
    var deg = (Math.random() * 30 * Math.PI) / 180; //产生0~30之间的随机弧度
    var txt = aCode[j]; //得到随机的一个内容
    show_num[i] = txt.toLowerCase();
    var x = 10 + i * 20; //文字在canvas上的x坐标
    var y = 20 + Math.random() * 8; //文字在canvas上的y坐标
    context.font = "bold 23px 微软雅黑";

    context.translate(x, y);
    context.rotate(deg);

    context.fillStyle = randomColor();
    context.fillText(txt, 0, 0);

    context.rotate(-deg);
    context.translate(-x, -y);
  }
  for (var i = 0; i <= 5; i++) {
    //验证码上显示线条
    context.strokeStyle = randomColor();
    context.beginPath();
    context.moveTo(Math.random() * canvas_width, Math.random() * canvas_height);
    context.lineTo(Math.random() * canvas_width, Math.random() * canvas_height);
    context.stroke();
  }
  for (var i = 0; i <= 30; i++) {
    //验证码上显示小点
    context.strokeStyle = randomColor();
    context.beginPath();
    var x = Math.random() * canvas_width;
    var y = Math.random() * canvas_height;
    context.moveTo(x, y);
    context.lineTo(x + 1, y + 1);
    context.stroke();
  }
}

function randomColor() {
  //得到随机的颜色值
  var r = Math.floor(Math.random() * 256);
  var g = Math.floor(Math.random() * 256);
  var b = Math.floor(Math.random() * 256);
  return "rgb(" + r + "," + g + "," + b + ")";
}

文件上传

ajaxfileupload.js

js
/*图片上传*/
$("#imgFile0").change(function () {
  // 加载提示
  FoxUI.loader.show("mini");
  $.ajaxFileUpload({
    url: core.getUrl("util/uploader"), // 请求地址
    data: { file: "qrcode" }, // input框的name属性
    secureuri: false, // 启用安全模式
    fileElementId: "imgFile0", // input id
    dataType: "json", // 响应数据格式
    success: function (res, status) {
      FoxUI.loader.hide();
      $("#image").attr("src", res.url);
      $("#qcode").val(res.filename);
    },
    error: function (data, status, e) {
      FoxUI.loader.hide();
      FoxUI.toast.show("上传失败!");
    },
  });
});
/*图片上传*/

模板语法

html
<!-- 有数据的模板 -->
<script type="text/html" id="tpl-goods">
  <%each result as log%>
  <div class="list-box gh-between">
    <div class="ball"></div>
    <div class="list-text">
      <div class="num-text"><%log.title%></div>
      <!-- <div class="info-text">颜色随机设置自动出价1次,扣除购物币5</div> -->
    </div>
    <div class="right-box">
      <%if log.in_or_out == 'in'%>+<%else%>-<%/if%><%log.money%>佣金
    </div>
  </div>
  <%/each%>
</script>

workman

PHP webscoket

js
/**
 *
 * @param {sting} container  商品item容器选择器
 * @param {sting} time       商品倒计时
 * @param {sting} price      商品价格
 * @param {sting} status     商品状态,是否结束
 */
function getSecond(container, time, price, status) {
  require(["socket.io.js"], function (io) {
    $(() => {
      // 初始化io对象
      var socket = io("http://" + document.domain + ":2120");
      // uid 可以为网站用户的uid,作为例子这里用session_id代替
      var uid = '{php echo  $_W["openid"]}';
      // 当socket连接后发送登录请求
      socket.on("connect", function () {
        socket.emit("login", uid);
      });
      // 当服务端推送来消息时触发,这里简单的aler出来,用户可做成自己的展示效果
      socket.on("new_msg", function (msg) {
        let message = JSON.parse(msg);
        // console.log(message);
        // 获取当前页面商品id
        let arr = [];
        $(container).each(function (i, e) {
          // message.forEach(item => {
          //     if (item.goods_id == $(e).data('goods_id')) {
          //         $(e).find(time).text(item.second.padStart(2, '0'))
          //         $(e).find(price).text(item.price)
          //     }
          // });
          for (let i = 0; i < message.length; i++) {
            if (message[i].goods_id == $(e).data("goods_id")) {
              $(e).find(time).text(message[i].second.padStart(2, "0"));
              $(e).find(price).text(message[i].price);
              message[i].status == 0
                ? $(e).find(status).show()
                : $(e).find(status).hide();
              break; // break 用于原生for循环中
            }
          }
        });
      });
    });
  });
}

/**
 *
 * @param {sting} name        请求服务端(方法)的名称
 * @param {sting} callback    处理的回调函数
 */
function getDetail(name, callback) {
  require(["socket.io.js"], function (io) {
    $(() => {
      // 初始化io对象
      var socket = io("http://" + document.domain + ":2120");
      // uid 可以为网站用户的uid,作为例子这里用session_id代替
      var uid = '{php echo  $_W["openid"]}';
      // 当socket连接后发送登录请求
      socket.on("connect", function () {
        socket.emit("login", uid);
      });
      // 当服务端推送来消息时触发,这里简单的aler出来,用户可做成自己的展示效果
      socket.on(name, function (msg) {
        callback(msg);
      });
    });
  });
}

复制文本

clipboard.js

html
<div class="copy-btn" data-clipboard-text="123">复制</div>
js
const btnCopy = new ClipboardJS(".copy-btn");
btnCopy.on("success", () => {
  core.tip.show("复制成功");
});

全选与全不选

js
$(".all_check").on("change", function () {
  // 全选按钮
  const status = $(this).prop("checked");
  $(".checkone").prop("checked", status);
});

$(".checkone").on("change", function () {
  // 每一个子按钮
  const temp = Array.from($(".checkone"));
  const status = temp.every((ele) => {
    return $(ele).prop("checked");
  });
  $(".all_check").prop("checked", status);
});

moment.js

时间戳转换格式

js
moment(time).format("YYYY-MM-DD HH:mm:ss");

高仿 ios 数量选择器

文档

css

js

js
// 数量选择器
var picker1 = myPicker({
  cols, // 数量数组 [1000,2000...]
  title: "",
  onOkClick: function (values) {
    document.querySelector("#number").textContent = values[0]; // 将选择的数量写入dom节点
    // 项目逻辑代码
    let selector = values[0];
    let num = selector * box77;
    $(".price").text(num.toFixed(8));
  },
});
document.querySelector(".selector").addEventListener("click", function () {
  picker1.show();
});

滑动切换

html

html
<main>
  <nav class="tab gh-around">
    <div class="tab-text tab-active" data-type="1">预热中</div>
    <div class="tab-text" data-type="2">进行中</div>
    <div class="tab-text" data-type="3">已结束</div>
  </nav>
</main>

<div class="container"></div>

js

js
let start = null;
let endPos = { x: 0, y: 0 };
let isScrolling = 0; //这个参数判断是垂直滚动还是水平滚动
document.body.addEventListener("touchstart", function (e) {
  let touch = e.targetTouches[0];
  start = {
    // 记录开始的位置
    x: touch.clientX,
    y: touch.clientY,
  };
});
document.body.addEventListener("touchmove", function (e) {
  let touch = e.targetTouches[0];
  endPos = { x: touch.clientX - start.x, y: touch.clientY - start.y }; // 记录偏差值,判断移动
  // Math.abs 取绝对值
  // isScrolling = Math.abs(endPos.x) > Math.abs(endPos.y) ? 0 : 1; //isScrolling为1时,表示纵向滑动,0为横向滑动
  // 如果上下滑动超过100就是纵向
  isScrolling = Math.abs(endPos.y) > 100 ? 1 : 0; //isScrolling为1时,表示纵向滑动,0为横向滑动
});
document.body.addEventListener("touchend", function (e) {
  let type = $(".tab-active").data("type");
  if (isScrolling === 0) {
    //当为水平滚动时
    //判断是左移还是右移,当偏移量大于10时执行
    if (endPos.x > 10) {
      // 右移手势
      // 业务逻辑
      if (type == 1) {
        return;
      } else {
        type--;
        $(".tab-text")
          .eq(type - 1)
          .siblings()
          .removeClass("tab-active");
        $(".tab-text")
          .eq(type - 1)
          .addClass("tab-active");
        getLog(
          "member/gongzhen",
          {
            op: "getlist",
            page: 1,
            type,
          },
          ".container",
          "tpl_empty",
          "tpl_data"
        );
      }
    } else if (endPos.x < -10) {
      // 左移手势
      if (type == 3) {
        return;
      } else {
        $(".tab-text").eq(type).siblings().removeClass("tab-active");
        $(".tab-text").eq(type).addClass("tab-active");
        type++;
        getLog(
          "member/gongzhen",
          {
            op: "getlist",
            page: 1,
            type,
          },
          ".container",
          "tpl_empty",
          "tpl_data"
        );
      }
    }
  }
});

进度条

添加类名progress-bar

css
.progress-bar {
  width: 40%;
  height: 6px;
  border-radius: 25px;
  background: linear-gradient(#ffa800, #ffa800) no-repeat #fff;
  /*控制进度条进度*/
  background-size: 80% 100%;
  margin-left: 0.5rem;
}

禁止用户打开控制台

通过修改 get,得知是否有在控制台打印

兼容性不太好

js
//  阻止用户
document.oncontextmenu = (e) => {
  e.preventDefault();
};
document.onkeydown =
  document.onkeyup =
  document.onkeypress =
    (e) => {
      if (e.which == 123) {
        e.preventDefault();
        // alert('没事别老研究别人的接口,好好做站去吧')
      }
    };
let element = document.createElement("checkDevTools");
Object.defineProperty(element, "id", {
  get: function () {
    /* TODO */
    // 死循环
    // while(true){}
  },
});
console.debug(element); //使用console.debug()使打印出的辅助信息默认隐藏

文字滚动

marquee 标签

html
<!-- 公告 -->
<div class="gonggao gh-between">
  <img
    src="../addons/sz_yi/template/mobile/style1/static/images/newImage/home_icon_a3.png"
    alt=""
  />
  <marquee
    height="40"
    direction="up"
    scrolldelay="200"
    class="bd"
    style="padding-left: 1rem;"
  >
    <?php foreach ($notice_list as $k =>
    $row): ?>
    <div style="height: 100%;">{php echo $row['content']}</div>
    <?php endforeach ?>
  </marquee>
</div>

倒计时

fnTimeCountDown(结束时间,{sec, mini, hour, month, year, day})

第一个参数,是一个毫秒数时间

第二个参数是一个对象,存放想要显示的 dom 节点。如只想要时分秒,如下代码

js
var obj = {
  sec: document.getElementById("sec"), // 秒
  mini: document.getElementById("mini"), // 分
  hour: document.getElementById("hour"), // 时
};
fnTimeCountDown(adopt_begin_time * 1000, obj);

修改placeholder样式

css
::-webkit-input-placeholder {
  color: #09d9ec;
}

:-moz-placeholder {
  /* Firefox 18- */
  color: #09d9ec;
}

::-moz-placeholder {
  /* Firefox 19+ */
  color: #09d9ec;
}

:-ms-input-placeholder {
  color: #09d9ec;
}

emmet 语法生成无意义文字

tex
lorem

文本溢出,以...表示

单行

html
<style>
  div {
    width: 40px;
    overflow: hidden;
    white-space: nowrap; /*不换行*/
    text-overflow: ellipsis; /*省略号*/
  }
</style>
<div>
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus facilis
  iure quos aliquam, tempore repellat explicabo officiis ducimus ullam
  voluptatum assumenda voluptate mollitia sapiente pariatur. Labore laboriosam
  reprehenderit placeat possimus?
</div>

多行

css
div {
  display: -moz-box; /* Mozilla */
  display: -webkit-box; /* WebKit */
  display: box; /* As specified */
  overflow: hidden;
  white-space: normal !important;
  text-overflow: ellipsis;
  word-wrap: break-word; /*单词断句*/
  -webkit-line-clamp: 2; /*第几行省略*/
  -webkit-box-orient: vertical; /*水平布局*/
  -moz-box-orient: vertical; /* Mozilla */
  box-orient: vertical; /* As specified */
}

判断对象有无指定属性

hasOwnProperty()方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是是否有指定的键)

js
/**
 * 判断对象有无指定属性
 * @param {Object} obj 判断的对象
 * @param {String} key 判断的属性名(键名)
 */
function hasKey(obj, key) {
  let status = obj.hasOwnProperty(key) && key in obj ? true : false;
  return status;
}

判断手机(安卓,苹果)

返回true为 ios 系统

js
function checkPhone() {
  if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {
    return true;
  } else if (/(Android)/i.test(navigator.userAgent)) {
    return false;
  }
}

LC

权限

开发的时候遇到,sideBar新增了东西,但要等后端配置增加权限(单单前端初始化加了,在checkPermission方法会被重新赋值),索性不执行checkPermission,自己写个递归把所有的auth都设置为true

js
// 初始化
init () {
  this.initTab()
  this.recursion()
  // this.checkPermission()
},
recursion (arr = this.tabsList) {
  arr.forEach((item) => {
    item.auth = true
    if (!item.children || item.children.length === 0) return
    this.recursion(item.children)
  })
},

element

table

使用展开行的表格时,默认使用 id 作为标识。如果 tableData 中没有 id,或者是别的名字,会报错

Duplicate keys detected: 'expanded-row__undefined'. This may cause an update error.

HONGDU

禁止开发者工具调试

js
(() => {
  function block() {
    if (
      window.outerHeight - window.innerHeight > 200 ||
      window.outerWidth - window.innerWidth > 200
    ) {
      document.body.innerHTML = "检测到非法调试,请关闭后刷新重试!";
    }
    setInterval(() => {
      (function () {
        return false;
      })
        ["constructor"]("debugger")
        ["call"]();
    }, 50);
  }
  try {
    block();
  } catch (err) {}
})();

获取当前日期的一周时间

示例

image-20221227180156364

js
import dayjs from 'dayjs'

const zhCn = require('dayjs/locale/zh-cn')
// 设置中文
dayjs.locale(zhCn)
/**
 * @description 获取当前日期的一周
 * @param {string | Date} date 能够转化的日期
 */
getWeek(date) {
  // 中文包一周的开始是周一,因此这里要减去一天
  const sunday = dayjs(date).startOf('week').subtract(1, 'day')
  const week = Array.from({ length: 7 }).map((item, index) => {
    const current = sunday.add(index, 'day')
    return {
      day: current.format('YYYY-MM-DD'),
      week: current.format('dddd'),
      current
    }
  })
  return week
}

通过 Blob 下载文件

初始化 api 要设置一下

ts
export const postExportPushRecord = (params: IFailRecordParams) => {
  return attendanceHttp.post<object>(
    {
      url: "/",
      params,
      responseType: "blob",
    },
    { isExport: true }
  );
};

具体方法

警告 ⚠️

我们需要拿到响应头的Content-Disposition,并解析出文件名;因此要注意接口返回响应头的Access-Control-Expose-Header字段有没有指定Content-Disposition,如果没有指定,客户端是获取不到的

ts
/**
 * @author GauharChan
 * @description 把文档数据流下载,api接口需特殊处理(包括responseType: 'blob',isExport: false)
 * @param { object } res 完整的响应信息,包括header、data
 */
export function downLoadByBlob(res) {
  if (
    !res.headers["content-disposition"] &&
    !res.headers["Content-Disposition"]
  ) {
    createMessage.error("下载失败");
    return;
  }
  const contentDisposition = decodeURIComponent(
    res.headers["content-disposition"] || res.headers["Content-Disposition"]
  ); // 从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名;
  const patt = new RegExp("filename\\*?=([^;]+\\.[^\\.;]+);*");
  const result: any = patt.exec(contentDisposition);
  const params = result[1].split("'");
  const filename: string = params[params.length - 1];
  const fileNameList = filename.split(".");
  const suffix = fileNameList[fileNameList.length - 1];
  const typeEumn = {
    xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8",
    xls: "application/vnd.ms-excel;charset=utf-8",
    doc: "application/msword",
    docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  };
  const blob = new Blob([res.data], {
    type: typeEumn[suffix],
  });
  const downloadElement = document.createElement("a");
  const href = window.URL.createObjectURL(blob);
  downloadElement.style.display = "none";
  downloadElement.href = href;
  downloadElement.download = filename; // 下载后文件名
  document.body.appendChild(downloadElement);
  downloadElement.click(); // 点击下载
  document.body.removeChild(downloadElement); // 下载完成移除元素
  window.URL.revokeObjectURL(href); // 释放掉blob对象
}

微信 H5 打开小程序

https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_Open_Tag.html#21

web 获取 dpr

传递canvascontext

ts
function getRatio(context: any): number {
  if (!context) {
    return 1;
  }
  const backingStore =
    context.backingStorePixelRatio ||
    context.webkitBackingStorePixelRatio ||
    context.mozBackingStorePixelRatio ||
    context.msBackingStorePixelRatio ||
    context.oBackingStorePixelRatio ||
    context.backingStorePixelRatio ||
    1;
  return (window.devicePixelRatio || 1) / backingStore;
}