前端开发技巧


作者:乐天派的普通人
链接:https://www.jianshu.com/p/f2a934d48a64
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Vue文章部分引用于:https://www.jianshu.com/p/baedcedc3191

css文章部分引用于:https://segmentfault.com/a/1190000020899202

JavaScript 篇

1.格式化金钱

const ThousandNum = num => num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
const money = ThousandNum(20190214);
// money => "20,190,214"

2.取整

代替正数的 Math.floor(),代替负数的 Math.ceil()

const num1 = ~~ 1.69;
const num2 = 1.69 | 0;
const num3 = 1.69 >> 0;
// num1 num2 num3 => 1 1 1

3.转数值

只对 null""false数值字符串 有效

const num1 = +null;
const num2 = +"";
const num3 = +false;
const num4 = +"169";
// num1 num2 num3 num4 => 0 0 0 169

4.精确小数

const RoundNum = (num, decimal) => Math.round(num * 10 ** decimal) / 10 ** decimal;
const num = RoundNum(1.69, 1);
// num => 1.7

5.取最小最大值

const arr = [0, 1, 2];
const min = Math.min(...arr);
const max = Math.max(...arr);
// min max => 0 2

6.判断数据类型

function DataType(tgt, type) {
    const dataType = Object.prototype.toString.call(tgt).replace(/\[object (\w+)\]/, "$1").toLowerCase();
    return type ? dataType === type : dataType;
}
DataType("young"); // "string"
DataType(20190214); // "number"
DataType(true); // "boolean"
DataType([], "array"); // true
DataType({}, "array"); // false

7.是否为空对象

const obj = {};
const flag = DataType(obj, "object") && !Object.keys(obj).length;
// flag => true

8.克隆数组

const _arr = [0, 1, 2];
const arr = [..._arr];
// arr => [0, 1, 2]

9.合并数组

const arr1 = [0, 1, 2];
const arr2 = [3, 4, 5];
const arr = [...arr1, ...arr2];
// arr => [0, 1, 2, 3, 4, 5];

10.去重数组

const arr = [...new Set([0, 1, 1, null, null])];
// arr => [0, 1, null]

11.截断数组

const arr = [0, 1, 2];
arr.length = 2;
// arr => [0, 1]

12.交换赋值

let a = 0;
let b = 1;
[a, b] = [b, a];
// a b => 1 0

13.创建指定长度且值相等的数组

const arr = new Array(3).fill(0);
// arr => [0, 0, 0]

14.克隆对象

const _obj = { a: 0, b: 1, c: 2 }; // 以下方法任选一种
const obj = { ..._obj };
const obj = JSON.parse(JSON.stringify(_obj));
// obj => { a: 0, b: 1, c: 2 }

15.合并对象

const obj1 = { a: 0, b: 1, c: 2 };
const obj2 = { c: 3, d: 4, e: 5 };
const obj = { ...obj1, ...obj2 };
// obj => { a: 0, b: 1, c: 3, d: 4, e: 5 }

16.创建纯空对象

const obj = Object.create(null);
Object.prototype.a = 0;
// obj => {}

17.优雅处理 Async/Await 参数

function AsyncTo(promise) {
    return promise.then(data => [null, data]).catch(err => [err]);
}
const [err, res] = await AsyncTo(Func());

Vue 篇

1.路由懒加载

import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)

const router = new Router({
  routes: [
    {
      path: '/',
      component: () => import("xxx")
    }
]
})

2.页面需要导入多个组件

原来的写法

import titleCom from '@/components/home/titleCom'
import bannerCom from '@/components/home/bannerCom'
import cellCom from '@/components/home/cellCom'
components:{titleCom,bannerCom,cellCom}

利用 require.context 可以写成

const path = require('path')
const files = require.context('@/components/home', false, /\.vue$/)
const modules = {}
files.keys().forEach(key => {
  const name = path.basename(key, '.vue')
  modules[name] = files(key).default || files(key)
})
components:modules

API 说明

实际上是 webpack 的方法,vue 工程一般基于 webpack,所以可以使用
require.context(directory,useSubdirectories,regExp) >
接收三个参数:

directory:说明需要检索的目录

useSubdirectories:是否检索子目录

regExp: 匹配文件的正则表达式,一般是文件名

3.动态组件

做一个 tab 切换时就会涉及到组件动态加载

<component v-bind:is="currentTabComponent"></component>

但是这样每次组件都会重新加载,会消耗大量性能,所以 <keep-alive> 就起到了作用

<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

这样切换效果没有动画效果,这个也不用着急,可以利用内置的 <transition>

<transition>
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>
</transition>

4.mixins

有些组件有些重复的 js 逻辑,如校验手机验证码,解析时间等,mixins 就可以实现这种混入

const mixin={
    created(){
      this.dealTime()
    },
    methods:{
      dealTime(){
        console.log('这是mixin的dealTime里面的方法');
      }
  }
}

export default{
  mixins:[mixin]
}

5.为路径设置别名

在开发过程中,我们经常需要引入各种文件,如图片、CSS、JS 等,为了避免写很长的相对路径(../),我们可以为不同的目录配置一个别名

// vue-cli 2.x 配置
// 在 webpack.base.config.js中的 resolve 配置项,在其 alias 中增加别名
resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },

// vue-cli 3.x 配置
// 在根目录下创建vue.config.js
var path = require('path')
function resolve (dir) {
  console.log(__dirname)
  return path.join(__dirname, dir)
}
module.exports = {
  chainWebpack: config => {
    config.resolve.alias
      .set(key, value) // key,value自行定义,比如.set('@@', resolve('src/components'))
  }
}

6.img 加载失败

有些时候后台返回图片地址不一定能打开,所以这个时候应该加一张默认图片

// page 代码
<img :src="imgUrl" @error="handleError" alt="">
<script>
export default{
  data(){
    return{
      imgUrl:''
    }
  },
  methods:{
    handleError(e){
      e.target.src=reqiure('图片路径')
    }
  }
}
</script>

7.页面统一判断

在开发中经常会遇到权限判断的问题,我们又不可能在每一个页面的生命周期中去判断一下,那样太消耗时间了,处理方式:

router.beforeEach((to, from, next) => {
  myAccess.checkhaveAccess(to.path) === true ? next() : next('/forbid')
})

8.路由的项目启动页和 404 页面

404 页面指的是: 当进入一个没有 声明/没有匹配 的路由页面时就会跳转到 404 页面

export default new Router({
  routes: [
    {
      path: '/', // 项目启动页
      redirect:'/login'  // 重定向到下方声明的路由
    },
    {
      path: '*', // 404 页面
      component: () => import('./notfind')
    },
  ]
})

9.js适配经验:

我们在写代码的时候,很有可能写到这种代码:

[1,2,3,4,5].includes(1)

或者是使用promise等es6的方法,但是我们的需求是在Android4.4上面完美运行。这样就会出现includes is not undefied等错误提示。如果看了我之前谈到webpack的文章就会疑问:我们之前不是用了babel插件用来转成es5了呢?我当时也疑问了好久,直到我在webpack里面找到一个插件,具体的使用方法:

import "babel-polyfill"
import es6Promise from 'es6-promise'
es6Promise.polyfill()
require('es6-promise').polyfill()

// webpack配置文件处
  entry: {
    app: ['babel-polyfill', './src/main.js']
  },

10. 页面统一判断

在开发中经常会遇到权限判断的问题,我们又不可能在每一个页面的生命周期中去判断一下,那样太消耗时间了,我的处理:

router.beforeEach((to, from, next) => {
  myAccess.checkhaveAccess(to.path) === true ? next() : next('/forbid')
})

11. 事件的传递:

一般来说事件的传递有很多种,比如父子之间传递数据就可以直接用props,和emit来做关联。
父组件给子组件传递

// 父组件
<parent>
    <child :datas="content"></child> 
</parent>

data(){
    return {
        content:'sichaoyun'
    };
}

// 子组件

props:["datas"];
// 或者是 
props: {
 datas: String
}

子组件给父组件传递

// 子组件
<template>
    <div @click="open"></div>
</template>

methods: {
   open() {
        this.$emit('showbox','the msg'); //触发showbox方法,'the msg'为向父组件传递的数据
    }
}
// 父组件
<child @showbox="toshow" :msg="msg"></child> //监听子组件触发的showbox事件,然后调用toshow方法

methods: {
    toshow(msg) {
        this.msg = msg;
    }
}

12、 深度watch与watch立即触发回调

这个是我偶尔在vuejs官网上面发现的,watch有两个可选参数,但是好像版本有限制,具体请移步官方文档。查看版本信息
选项:deep
在选项参数中指定 deep: true,可以监听对象中属性的变化。
选项:immediate
在选项参数中指定 immediate: true, 将立即以表达式的当前值触发回调,也就是默认触发一次。

13、 路由的项目启动页和404页面

  export default new Router({
      routes: [
        {
          path: '/', // 项目启动页
          redirect:'/login'  // 重定向到下方声明的路由 
        },
        {
          path: '*', // 404 页面 
          component: () => import('./notfind')
        },
      ]
    })

比如你的域名为:www.baidu.com

项目启动页指的是: 当你进入www.baidu.com,会自动跳转到login登录页。

404页面指的是: 当进入一个没有 声明/没有匹配 的路由页面时就会跳转到404页面。

比如进入www.baidu.com/testRouter,就会自动跳转到notFind页面。

当你没有声明一个404页面,进入www.baidu.com/testRouter,显示的页面是一片空白。

CSS 篇

1.使用 text-align-last 对齐两端文本

在线演示

<div class="bruce flex-ct-x">
    <ul class="justify-text">
        <li>账号</li>
        <li>密码</li>
        <li>电子邮件</li>
        <li>通讯地址</li>
    </ul>
</div>

.justify-text {
    li {
        margin-top: 5px;
        padding: 0 20px;
        width: 100px;
        height: 40px;
        background-color: #f66;
        line-height: 40px;
        text-align-last: justify;
        color: #fff;
        &:first-child {
            margin-top: 0;
        }
    }
}

2.使用 color 改变边框颜色

border` 没有定义 `border-color` 时,设置 `color` 后,`border-color` 会被定义成 `color

场景:边框颜色与文字颜色相同

.elem {
  border: 1px solid;
  color: #f66;
}

3.黑白图像

让你的彩色照片显示黑白照片

img.desaturate {
    filter: grayscale(100%);
    -webkit-filter: grayscale(100%);
    -moz-filter: grayscale(100%);
    -ms-filter: grayscale(100%);
    -o-filter: grayscale(100%);
}

4.将图片作为背景

当给页面添加图片时,尤其需要图片是响应式的时候,最好使用 background 属性来引入图片,而不是 <img> 标签

这看起来使用图片会更复杂,但实际上它会使设置图片的样式变得更加容易。有了 background-size, background-position 和其它的属性,保持或改变图片原始尺寸和宽高比会更方便

background 引入图片的一个缺点是页面的 Web 可访问性会受到轻微的影响,因为屏幕阅读器和搜索引擎无法正确地获取到图像。这个问题可以通过 CSS object-fit 属性解决,到目前为止除了 IE 浏览器其他的浏览器都可以使用 object-fit

<section>
    <p>Img element</p>
    <img src="https://tutorialzine.com/media/2016/08/bicycle.jpg" alt="bicycle">
</section>

<section>
    <p>Div with background image</p>
    <div></div>
</section>
img {
    width: 300px;
    height: 200px;
}

div {
    width: 300px;
    height: 200px;
    background: url('https://tutorialzine.com/media/2016/08/bicycle.jpg');
    background-position: center center;
    background-size: cover;
}

section{
    float: left;
    margin: 15px;
}

5.保持选择器的低权重

css 的选择器并不都是平等的。当初学习 CSS 时,我总是认为选择器会覆盖它上面的所有内容。然而,情况并非如此

<a href='#' id='blue-btn' class="active">按钮</a>

a{
    color: #fff;
    padding: 15px;
}
a#blue-btn {
    background-color: blue;
}
a.active {
    background-color: red;
}

我们希望.active类中设置的样式会生效使按钮变为红色。但是它并不会起作用,因为按钮在上面有一个ID选择器,它同样设置了background-color,ID选择器具有更高的权重,所以按钮的颜色是蓝色的

权重也会叠加,于是a#button.active的权重要比a#button的高。一开始就使用高权重的选择器会导致你在后面的维护中不断的使用更高权重的选择器

6.使用rem进行全局大小调整;使用em进行局部大小调整

在设置根目录的基本字体大小后,例如html字体大小:15px;,可以将包含元素的字体大小设置为rem

article {    
    font-size: 1.25rem;  
}    
aside {    
    font-size: .9rem;  
}

将文本元素的字体大小设置为em

h2 {    
    font-size: 2em;  
}    
p {    
    font-size: 1em;  
}

评论
  目录