资料汇总

指定内容

由浅入深,66条JavaScript面试知识点
ES6入门 - 阮一峰
在阿里我是如何当面试官的
第三期:前端九条bug分享
记一次grid布局实战应用分享会
最强大的 CSS 布局 —— Grid 布局
JavaScript 继承的八种写法
「前端料包」深究JavaScript作用域(链)知识点和闭包
「牛客网」45道JS能力测评经典题总结
Vue经常会问到的面试题
正则表达式不要背
「前端料包」深入理解JavaScript原型和原型链

8月29日内容汇总

this.$nextTick的实现
其实就是利用promise把nextTick要执行的内容放到微任务队列,微任务队列里的任务会在当前一次的事件循环结束后执行,不支持promise的话就会换成setTimeout

8月28日内容汇总

cookie相关

Cookie 的SameSite属性用来限制第三方 Cookie,从而减少安全风险。可以设置三个值:Strict,Lax,None
Cookie 的 SameSite 属性 - 阮一峰

只要在Set-Cookie中附带了HttpOnly这个属性,那么这个Cookie就无法被JS脚本获取
怎样指定当前cookie不能通过js脚本获取

moment.js设置24小时制

设置24小时制:小时格式设置为大写HH,例如:
YYYY-MM-DD HH:mm:ss==>2018-01-18 20:01:17
设置12小写时为12小时制,例如
YYYY-MM-DD hh:mm:ss==>2018-01-18 08:01:17

8月27日内容汇总

银行EPI专项试题
农业银行笔试试题
2018农业银行春季校园招聘科技岗笔试科目及经验 - 百度文库
中国农业银行2018年校园招聘笔试考试真题及答案【最新】

8月26日内容汇总

今天看了一个Object.create的实现,里面有一步是给空函数指定prototype,感觉这个用法比较奇怪,后来看了JS的继承,这实际上就是原型式继承,利用一个空对象作为中介,将某个对象直接赋值给空对象构造函数的原型。

Object.myCreate = function (obj, properties)  {
     
  var F = function ()  {
     }
  F.prototype = obj
  if (properties) {
     
     Object.defineProperties(F, properties)
  }
  return new F()
}

Object.myCreate({
     }, {
     a: {
     value: 1}})     // {a: 1}

Object.create() 和 new Object()
JavaScript 继承的八种写法

8月25日内容汇总

Vue双向绑定实现

vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

核心:通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的
要实现mvvm的双向绑定,就必须要实现以下几点:

1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
4、mvvm入口函数,整合以上三者

vue双向绑定原理分析
剖析Vue原理&实现双向绑定MVVM

8月24日内容汇总

JS对象的hasOwnProperty方法

Object的hasOwnProperty()方法返回一个布尔值,判断对象是否包含特定的自身(非继承)属性。

var obj = {
     name: "32233232332"};
console.log(obj.hasOwnProperty(name)); // true

常见用法:
1.判断自身属性是否存在;
2.判断自身属性与继承属性;
3.遍历一个对象的所有自身属性;
for…in循环对象的所有枚举属性,然后再使用hasOwnProperty()方法来忽略继承属性
js属性对象的hasOwnProperty方法

JS中的reduce()方法

reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

total:必须,初始值, 或者计算结束后的返回值。如果没有指定初始值initialValue,那么total开始的值为数组第一项。
currentValue:必须,当前元素。

常见用法:

var arr = [3,9,4,3,6,0,9];

// 1. 求数组项之和
var sum = arr.reduce(function (prev, cur) {
     
    return prev + cur;
},0);

// 2. 求数组项最大值
var max = arr.reduce(function (prev, cur) {
     
    return Math.max(prev,cur);
});

// 3. 数组去重
var newArr = arr.reduce(function (prev, cur) {
     
    prev.indexOf(cur) === -1 && prev.push(cur);
    return prev;
},[]);

// 4. 统计数组中每个元素出现的次数
const arr = ["j", "s", "h", "d", "j", "s", "i", "h", "h"];
const obj = arr.reduce((pre,item) => {
     
	pre[item] ? pre[item] ++ : pre[item] = 1
	return pre
},{
     })
console.log(obj) // {j: 2, s: 2, h: 3, d: 1, i: 1}

8月23日内容汇总

初始化Vue模板
VS Code输入vue然后ta’b

我在阿里招前端,我该怎么帮你?
拿不到大厂offer ?简历你就写错了!
前端性能优化:当页面渲染遇上边缘计算
Vue面试题汇总【精品问答】
58道Vue常见面试题集锦,涵盖入门到精通,自测 Vue 掌握程度
22个ES6面试、复习干货知识点汇总

8月21日内容汇总

ES6箭头函数

箭头函数不能访问arguments

// 这样写会报错
const getArgs = () => arguments
// 但是可以通过剩余运算符取到所有参数
const getArgs2 = (...rest) => rest

箭头函数没有自己的this值,它捕获词法作用域函数的this值,在此示例中,addAll函数将复制computeResult 方法中的this值。

const data = {
     
  result: 0,
  nums: [1, 2, 3, 4, 5],
  computeResult() {
     
    const addAll = () => {
     
      let {
     result, nums} = this;
      console.log(result, nums);
    }
    return addAll()
  }
}
data.computeResult(); // 0 [1, 2, 3, 4, 5]

如果箭头函数外面没有函数,那么this就指向window对象。换句话说,箭头函数如果想取到当前对象的this,那就必须嵌套在一个函数中。

const data = {
     
  result: 0,
  nums: [1, 2, 3, 4, 5],
  addAll: () => {
     
    let {
     result, nums} = this;
    console.log(result, nums);
  }
}
data.addAll(); // undefined undefined

其他内容

图解 Vue 响应式原理
图解 Vue 异步更新原理
网页布局都有哪种?一般都用什么布局?- 淘系技术
有意思的 Node.js 内存泄漏问题

8月20日内容汇总

微软实习招聘

2021 Graduates Summer Intern - Software Engineer Intern - Cloud + AI – Shanghai

混入mixin和moment插件

报错replace of undefined导致页面加载阻塞

混入mixin类似于Object.assign,可以用于全局注册某些方法,比如全局注册时间处理函数。

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue组件中的可复用功能。当组件和混入对象含有同名选项时,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。

混入 - vue官方文档

格式化时间插件moment
Moment.js官方文档
moment.js插件使用

8月19日内容汇总

JS中require和import的区别

JS 中的require 和 import 区别 - 莉莉安~
JS 中的require 和 import 区别 - 大橙子

JS中访问对象属性

在JavaScript中,可以使用“ . ”和“ [ ] ”来访问对象的属性。其中“ . ”既可以用来访问属性,也能用来设置属性,而“ [ ] ”只能用来访问属性,不能用来设置属性。

JS Object对象方法

Object本身是一个函数,可以当作工具方法使用,将任意值转为对象。
Object不仅可以当作工具函数使用,还可以当作构造函数使用,即前面可以使用new命令。

注意,通过var obj = new Object()的写法生成新对象,与字面量的写法var obj = {}是等价的。或者说,后者只是前者的一种简便写法。

Object 对象的静态方法
所谓“静态方法”,是指部署在Object对象自身的方法

1.Object.keys() 遍历对象的(属性名,索引),并返回一个数组,该数组成员都是对象自身的(不是继承的),Object.keys方法只返回可枚举的属性
2.Object.getOwnPropertyNames() 遍历对象的(属性名,索引),并返回一个数组,该数组成员都是对象自身的(不是继承的),Object.getOwnPropertyNames方法还能返回不可枚举的属性名
3.Object.getOwnPropertyDescriptor( obj, prop) 返回一个指定对象上的自有属性对应的属性描述 (自由属性指,直接赋值的属性,不需要从原型上查找的属性)
4.Object.defineProperty( obj, prop, decriptor) 直接在一个对象上定义一个新属性,或修改一个对象的现有属性,并返回这个对象,默认情况下使用此方法添加的属性值是不能被修改的
5.Object.assign() 法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)

Object对象的实例方法
除了Object对象本身的方法,还有不少方法是部署在Object.prototype对象上的,所有Object的实例对象都继承了这些方法。Object实例对象的方法,主要有以下六个

a). valueOf() 返回当前对象对应的值
b). toString() 返回当前对象对应的字符串形式,用来判断一个值的类型
c). toLocaleString() 返回当前对象对应的本地字符串形式
d). hasOwnProperty() 判断某个属性是否为当前对象自身的属性,还是继承自原型对象的属性
e). isPrototypeOf() 判断当前对象是否为另一个对象的原型
f). propertyIsEnumerable() 判断某个属性是否可枚举

JS Object对象的方法总结( ES5 与 ES6 )
ES6入门教程——对象的扩展 - 阮一峰

JS检查空对象

将json对象转化为json字符串,再判断该字符串是否为"{}"。这里不能用toString,否则无论是否为空,一律返回"[object Object]"。

var data = {
     };
var b = (JSON.stringify(data) == "{}");
console.log(b) // true

ES6的Object.keys()方法,返回值是对象中属性名组成的数组。

var data = {
     };
var arr = Object.keys(data);
console.log(arr.length == 0); // true

Vue中的data为什么要写成函数形式

Vue中的data通常是这样写的

同一个组件被复用多次,会创建多个实例。这些实例用的是同一个构造函数,如果data是一个对象的话。那么所有组件都共享了同一个对象。为了保证组件的数据独立性要求每个组件必须通过data函数返回一个对象作为组件的状态。

<script>
export default {
     
	data: function() {
     
		return {
     
		}
	}
	// 也可以这样简写
	data() {
     
		return {
     
		}
	}
}
</script>

类数组转数组汇总

将类数组,例如Set对象,arguments对象转为数组

let ary = new Set([5, 6, 7, 8]);
arr = Array.prototype.slice.call(ary); // ES5中常用方法
arr = Array.hasOwnProperty('from') && Array.from(ary);
arr = [...ary];

附件上传实现loading

直接使用element的v-loading实现

upload(item) {
     
  const formData = new FormData();
  formData.append("mpf", item.file);
  const _t = this;

  _t.edit.uploading = true; // 开启loading
  api.sysInfo
    .uploadImage(formData)
    .then(res => {
     
      const a = {
     
        url: res.url,
        name: res.name
      };
      if (_t.baseform.demandAttachments == null) {
     
        _t.baseform.demandAttachments = [];
      }
      if (_t.demandAttachments == null) {
     
        _t.demandAttachments = [];
      }
      _t.baseform.demandAttachments = [..._t.baseform.demandAttachments, a];
      _t.demandAttachments.push(res);
      this.$message.success("文件上传成功");
      this.changeCommand(
        this.demand,
        _t.baseform.demandAttachments,
        "demandAttachments"
      );
    })
    .catch(err => {
     
      this.$message.error(`${
       err}`);
    })
    .finally( () => {
     
      this.edit.uploading = false; // 关闭loading
    });
},

Object.assign()的用法

在项目中有一个场景,有一个标签列表tagList,可以从tagList中选取标签关联到实体上,即将标签加入selectedTags中,同时tagList中的标签还支持编辑。交互的同学提了一个要求,编辑tagList里面的标签,如果这个标签已被关联,那么实体上的标签也需要同步更新。换句话说,selectedTags是tagList的子集,当tagList中有元素更新的话,如果selectedTags中也有这个元素,那么这个元素也需要更新。

之前的方案是更新之后将这个元素传过来,通过forEach循环根据id查找selectedTags有没有匹配项,如果有那就将这个元素里面的每个字段赋值给selectedTags中的元素。后来将forEach改为find方法,用Object.assign方法代替每个字段赋值。这样发现有个问题,如果find没有找到元素,那么tag就是undefined,但undefined是无法添加属性的。

 modifuSuccess(obj) {
     
	const tag = this.selectedTags.find(({
     id}) => id === obj.id);
	Object.assign(tag, obj);
},

这里这样改一下就正常了。

 modifuSuccess(obj) {
     
	const tag = this.selectedTags.find(({
     id}) => id === obj.id);
	tag && Object.assign(tag, obj);
},

这里顺便说一下Object.assign()的用法。

这里是tag对象中的属性

color: "6"
createTime: "2020-08-18T13:39:47.147+0800"
creator: "加菲猫"
id: "5f3a20a7d2829a00014b1915"
modifier: "加菲猫"
modifyTime: "2020-08-19T15:40:59.336+0800"
name: "京东钱包"
projectId: 185
status: 1

这里是obj对象的属性,可以看到,这里color和name被更新了。如果想要将obj中的内容合并到tag中,就可以使用Object.assign()方法。对tag和obj进行合并,改动也会同步到selectedTags上,因为这两个实际上是联动的。

color: "4"
id: "5f3a20a7d2829a00014b1915"
name: "京东钱包2333"

Object.assign是ES6新添加的接口,主要的用途是用来合并多个JavaScript的对象。

Object.assign()接口可以接收多个参数,第一个参数是目标对象,后面的都是源对象,assign方法将多个原对象的属性和方法都合并到了目标对象上面,如果在这个过程中出现同名的属性(方法),后合并的属性(方法)会覆盖之前的同名属性(方法)。

var target  = {
     a : 1}; //目标对象
var source1 = {
     b : 2}; //源对象1
var source2 = {
     c : 3}; //源对象2
var source3 = {
     c : 4}; //源对象3,和source2中的对象有同名属性c
var result = Object.assign(target,source1,source2,source3); // {a:1,b:2,c:4}

注意:Object.assign进行的是浅拷贝,所以上面result和target是联动的。
浅谈Object.assign

8月18日内容汇总

v-if和v-for不能同时使用

在vue的官方文档中是这样说的: 注意我们不推荐在同一标签上使用 v-if 和 v-for。当它们处于同一节点,v-for 的优先级比 v-if 更高,v-for会先于v-if执行,这意味着 v-if 将分别重复运行于每个 v-for 循环中,造成性能浪费。v-if嵌套v-for和v-for嵌套v-if都是可以的,也可以使用计算属性computed。

template的使用

如下所示,在v-for的外面套一个div,使用v-if进行判断,这样的话,在渲染之后在循环的div外面还会多一个div。

<div v-if="true">
	<div v-for="(item, index) in array" :key="index">
		{
     {
      item.name }}
	</div>
</div>

资料汇总_第1张图片

如果不希望有这个div,可以使用template

<template v-if="true">
	<div v-for="(item, index) in array" :key="index">
		{
     {
      item.name }}
	</div>
</template>

其他内容
VMware 虚拟化技术
我在阿里写代码学会的六件事

8月17日内容汇总

Grid 网格布局

项目中需要实现一个三栏的布局(如下所示),用弹性布局比较难实现,因为弹性布局实际上是轴线布局,即使把每一个项目的宽度设为33%,当空间不足的时候还是会换行(项目有一个最小宽度)。而且弹性布局还有一个很大的问题,弹性布局的项目之间默认是不会有间距的,也就是上下左右都是紧挨着的,当需要设置间距的时候一般用margin-right和margin-bottom,但是这样的话每个项目占的宽度就不好确定了,box-sizing属性也不管用了,所以也没办法准确知道每个项目的比例是多少。
资料汇总_第2张图片
网格布局特别适合这样的场景,当设置了行数或者列数之后,项目的布局就确定了,不会发生换行。而且在网格布局下,项目之间如果需要有间距,不用设置margin,直接设置行间距和列间距即可,顺便还解决了边缘元素的margin问题。

启用grid布局,只需要将父容器的display属性设为grid即可。

.box {
     
	display: grid;
}

启用了grid布局之后,使用浏览器审查元素就会出现下面的网格。
资料汇总_第3张图片
想要实现三栏布局,只需要设置一下列数和列宽

.container {
     
  display: grid;
  grid-template-columns: 100px 100px 100px; /* 可以指定具体长度作为列宽 */
  grid-template-columns: 33.33% 33.33% 33.33%; /* 也可以使用百分比作为列宽 */
  grid-template-columns: repeat(3, 33.33%); /* 重复写同样的值用repeat就行 */
  grid-template-columns: 70% 30%; /* 两栏式布局只要这样写 */
  grid-template-columns: 1fr 2fr; /* fr即片断,表示剩余空间做等分,后者的宽度是前者的两倍 */
  grid-template-columns: repeat(12, 1fr); /* 传统的十二网格布局 */
  grid-template-columns: repeat(3, 1fr); /* 实现三栏布局 */
  grid-template-columns: repeat(3, 33.33%); /* 使用百分比也是可以的 */
}

实际开发的时候发现, 使用grid-template-columns: repeat(3, 1fr);的话,某个项目内部如果有很多内容,这一栏就会特别宽。
资料汇总_第4张图片
使用grid-template-columns: repeat(3, 33%);则没有这样的问题。
资料汇总_第5张图片
同样的方法还可以设置行数和行高。

.container {
     
  display: grid;
  grid-template-rows: repeat(3, 33.33%);
}

设置行间距和列间距。需要注意的是,设置了列间距后,列间距本身也会占据一部分父容器宽度,所以在三栏布局下,如果项目宽度还是按33.33%的话,那么内部元素宽度就会超出父容器,这种情况下推荐使用fr来表示列宽。

.container {
     
  grid-row-gap: 20px; /* 行间距 */
  grid-column-gap: 20px; /* 列间距 */
  grid-gap: 20px 20px; /* grid-gap属性是grid-column-gap和grid-row-gap的合并简写形式 */
  
  /* 根据最新标准,上面三个属性名的grid-前缀已经删除 */
  row-gap: 20px; /* grid-row-gap写成row-gap */
  column-gap: 20px; /* grid-column-gap写成column-gap */
  gap: 20px 20px; /* grid-gap写成gap */
}

参考:CSS Grid 网格布局教程 - 阮一峰

JS内置对象

Arguments, Boolean, Date, Error, Function, JSON, Math, Number, Array, Object, RegExp, String
JS所有内置对象属性和方法汇总

Call()的实现

昨天看了一个视频,是关于call()的实现,看了下代码都是ES5的老语法,很多地方其实可以优化的。

  1. 那句for循环,其实就是为了取除第一项之外的剩余参数,我们可以使用ES6的剩余运算符;

  2. 然后为了将数组中的元素拆分出来给函数传参,他这里用了字符串拼接和eval()函数,在ES6中只要一个延展运算符就能解决问题;

有同学看到这里用了ES5里面常用的逻辑或,可能会说ES6中不是有函数默认值吗,为什么不用函数默认值呢?因为只有传入的参数为undefined才会触发默认值,在这里传入的对象可以是null,这样就会报错了,因为不能给null添加属性。

有同学说既然是把数组的第一项拿掉,可不可以用shift()呢?实际上把数组的第一项移除,那么剩下的每一项的下标都要往前移一位,所以shift()的复杂度也是O(n),跟循环或者剩余运算符没有区别。顺便一提,…放在等号右边叫延展运算符,…放在等号左边或者形参上叫剩余运算符,两者的作用恰好相反,其内部也是通过for of循环实现的。

// 可以使用shift()方法
const newArguments = Array.from(arguments).shift();
// 也可以使用剩余运算符
[obj, ...newArguments] = arguments;

这里说明一下,arguments对象其实不是真正的数组,而是类数组(array-like)的对象,类数组虽然可以像数组一样通过下标访问元素(例如arguments[0]),并且也有length属性,但是类数组不能直接调用数组的API,数组的操作方法都不能用,类数组的循环遍历只能用for(试了一下for in和for of也是可以的)。这里如果要调用数组的shift方法,需要使用Array.from将类数组转为数组。

原来的代码如下:

Function.prototype.newCall = function(obj) {
     
    var obj = obj || window;
    obj.p = this;
    var newArguments = [];
    for (var i=1; i<arguments.length; i++) {
     
        newArguments.push('arguments[' + i + ']');
    }
    var result = eval('obj.p(' + newArguments + ')');
    delete obj.p;
    return result
}

优化以后的代码如下:

Function.prototype.newCall = function(obj, ...newArguments ) {
     
    var obj = obj || window;
    obj.p = this;
    var result = obj.p(...newArguments);
    delete obj.p;
    return result
}

上测试用例:

function person(a, b, c, d) {
     
    return {
     
        name: this.name,
        a: a, b: b, c: c, d: d
    }
}

const user = {
      name: '加菲猫' };

let res = person.newCall(user, '肥宅', '吃鸡', '桌游', '王者');
console.log(res);

成功拿到结果

{
     name: "加菲猫", a: "肥宅", b: "吃鸡", c: "桌游", d: "王者"}

其他内容

最新!Apache Struts 又爆安全漏洞(危害程度特别大)

8月16日内容汇总

Koa - 基于 node.js 平台的下一代 web 开发框架

8月15日内容汇总

Vue 3.0 开发文档

Vue 3.0 开发文档

重点内容:

Vite(官方推荐的用于替代webpack的构建工具)
Composition API
新的响应式机制
计算属性和侦听器
teleport (传送)
Fragment(碎片)
自定义事件($emit 验证)
组件的 v-model 升级

TypeScript

TypeScript 是由微软开发的开源、跨平台的编程语言。它是 JavaScript 的超集,最终会被编译为 JavaScript 代码。TypeScript 起源于使用 JavaScript 开发的大型项目。由于 JavaScript 的局限性,难以胜任和维护大型项目开发。因此微软开发了 TypeScript ,使其能够胜任开发大型项目。

其他内容
使用Nuxt.js搭建VUE应用的SSR(服务端渲染)
两种方式识别“传统”图片验证码 - 淘系技术
从架构到源码:一文了解Flutter渲染机制 - 阿里技术
阿里淘系优质开源项目推荐 - 淘系技术

8月14日内容汇总

弹框展开加载内容

经常遇到一个场景,当一个弹框组件展开的时候自动加载内容,组件关闭的时候又要自动清空内容。之前的做法就是通过watch监听isShow的变化,如果为true,那么就去请求接口,如果为false,就去清空内容。(不能用created钩子,因为弹框关闭后组件并不会销毁,所以再次点开弹框并不能触发请求)

今天遇到一个问题,有同事需要确定弹框的高度,如果是先显示弹框再加载内容的话,高度就无法确定了。那就只能把加载的方法拿到外面执行。在组件内部定义加载内容方法和清空内容方法,然后通过外部调用去执行。

这里做个简单示范,TagRelatedPopup.vue弹框组件内容如下

<template>
	<div>
		<popup-wrap :visible.sync="isShow"></popup-wrap>
	</div>
</template>

<script>
import PopupWrap from '@/views/common/PopupWrap';
export default {
     
	components: {
     
		PopupWrap
	},
	data() {
     
		isShow: false,
		tagList: []
	},
	props: {
     
		selectedTags: {
     
	      type: Array,
	      default: () => {
     
	        return []
	      }
	    },
	}
	methods: {
     
		// 从后端接口拉取数据的方法
		getCustomTags() {
     
			let id = this.$route.params.id;
			return api.minderTag.getTag(id)
				.then((data) => {
     
					this.tagList = [...data];
				})
				.catch((err) => {
     
				  	this.$message.error(err);
				})
		},
		// 从props获取已关联的标签
		getRelatedTags() {
     
  			this.selected = this.selectedTags.map(x => x.id)
	    },
	    // 打开弹框的方法
		async handleOpen() {
     
			// 获取异步数据
			await this.getCustomTags();
			// 获取同步数据
			this.getRelatedTags();
			this.isShow= true;
		}
	}
}
</script>

从外部调用handleOpen方法

<template>
	<tag-relate-popup ref="tagRelateBox"></tag-relate-popup>
</template>

<script>
import TagRelatePopup from '@/views/common/TagRelatePopup';
export default {
     
	components: {
     
		TagRelatePopup
	},
	methods: {
     
		showtagRelateBox() {
     
	    	this.$refs.tagRelateBox.handleOpen();
	    }
	}
}
</script>

utils.js的用法

项目中有一个场景,后端传数字,前端根据数字匹配颜色,而数字和颜色的映射关系是保存在前端的。这个映射关系可以直接写在data中,但是如果别的地方需要调用就不方便了。可以将这个关系保存在utils.js文件中。

// utils.js 的内容
export const tagColorMapping = [
  '#3D3D3D',
  '#00C565',
  '#1E83FF',
  '#953EFF',
  '#00C7CF',
  '#FFA200',
  '#FF7516',
  '#FF3C84',
  '#FF4D4D',
  '#0FBCEB'
]

有组件需要调用的话,直接import一下就行了

<script>
import {
      tagColorMapping as colorMapping } from '@/views/common/utils';
export default {
     
	data() {
     
		colorMapping
	}
}
</script>

JS中map(),filter()和forEach()

map()方法跟forEach()方法类似,map() 方法返回一个新数组,不改变原始数组。需要注意的是,map()中的回调函数必须要return返回值,不然会返回一个undefind的数组

array.map(function(currentValue,index,arr), thisValue)

常见的用法是将原始数组的值经过处理后装到新的数组里面

const arr = [1, 2, 3, 4, 5];
const arr2 = arr.map(item => return item + 1);

filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,并且回调函数中也需要return返回值

const arr = [1, 2, 2, 3, 4, 4, 5, 6];
// 数组去重
const unique = arr.filter((item, index) => {
     
	// 过滤条件是数组下标与检索下标一致
	return arr.indexOf(item) == index;
})

在不需要返回值的时候,建议使用forEach()

array.forEach(function(currentValue, index, arr), thisValue)

表单校验空格

项目中要求校验某个字段是否为空,一般的做法是这样的

if(this.input == '') {
     
  this.$message.error('请输入标签名称!');
  return
}

这样的话,如果用户输入空格,则不会触发这个验证,可以使用trim()去掉空格

if(this.input.trim() == '') {
     
  this.input = ''; // 如果用户输入空格,那么就把表单清空
  this.$message.error('请输入标签名称!');
  return
}

使用includes()也可以验证(不推荐,如果字符串中间出现空格,也会触发这个验证)

还可以使用正则表达式

/^\S+$/ // 非空无空格
/^\S*$/ // 无空格,可以为空

异步回调两种方法

异步方法可以通过.then进行回调,通过.catch捕获异常

open() {
     
  this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
     
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
     
    this.$message({
     
      type: 'success',
      message: '删除成功!'
    });
  }).catch(() => {
     
    this.$message({
     
      type: 'info',
      message: '已取消删除'
    });          
  });
}

也可以使用async/await进行回调,由于async返回一个Promise对象,如果await后面的语句出错,等同于Promise被reject,异常将无法被捕获到

async confirmDelete(tag, index) {
     
  await this.$confirm(`确认删除《${
       tag.name}》?`, '提示', {
     
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    });
  // 回调成功执行的方法
  this.deleteTag(tag, index)
},

建议将async放在try…catch…结构中,如果有多个await命令,还可以进行统一的异常处理

async function getUser() {
     
	try {
     
		const a1 = await firstStep();
		const a2 = await secondStep(a1);
		const a3 = await finalStep(a1, a2);
		console.log("Final", a3);
	} catch (err) {
     
		console.error(err);
	}
}

参考:async 函数 - 阮一峰

其他内容

这篇介绍的非常详细
css3中的变形(transform)、过渡(transtion)、动画(animation)
如何规范你的Git commit?- 阿里技术
一口气搞懂「文件系统」,就靠这 25 张图了

8月13日内容汇总

slot的用法

通常组件是无法直接嵌套的

<popup-wrap>
	<div>这里的内容不会被加载</div>
</popup-wrap>

可以通过slot嵌入内容

// 这是popupWrap组件
<template>
  <div class="popup-wrap el-popover" ref="popupWrap" :style="styles">
    <slot name="content">
    
    </slot>
  </div>
</template>
// 引用popupWrap组件,并向里面嵌入内容
<popup-wrap :visible.sync="show"
            ref="tagRelatePopup">
	<template slot="content">
		// 这里面是嵌入的内容
		<custom-tag-select
			ref="customTagSelect"
			@showTagEdit="handleOpenEdit"
		</custom-tag-select>
		<tag-edit-popup
			ref="tagEditPopup"
			@reloadTagList="reloadTagList">
		</tag-edit-popup>
	</template>
</popup-wrap>

封装dialog或者popover后控制显示与隐藏

将对话框或者弹出框封装后,想通过引用它的父组件控制显示与隐藏,不推荐使用传参的方法,因为如果弹窗打开后,点击旁边的modal或者右上角的×同样也可以关闭弹窗,但此时父组件的isShow仍将会是true且不会与组件内部保持同步。即使要用传参,也应该使用:show.sync="isShow"使外部与内部保持同步

<tag-relate-popup :show="isShow"></tag-relate-popup>

推荐使用$refs直接调用组件内部方法打开弹窗

在 TagRelatedPopup 组件内部定义一个 handleOpen 方法用于打开弹框:

<template>
  <popup-wrap :visible.sync="show"
  			  :pageEvent="pageEvent"
              ref="tagRelatePopup">
    <template slot="content">
    	// 这里是弹框内容
    </template>
  </popup-wrap>
</template>

<script>
import PopupWrap from '@/views/common/PopupWrap';
export default {
     
	components: {
     
		PopupWrap
	},
	data() {
     
		return {
     
			show: false	
		}
	},
	methods: {
     
		// 在组件内部建一个handleOpen方法用于打开弹框
		handleOpen(e) {
     
			this.show = true;
      		this.pageEvent = e;
		}
	}
}
</script>

在父组件中通过$refs调用子组件内部的handleOpen方法打开弹框:

<template>
	<div>
		<span @click.stop="showtagRelateBox($event)">
		</span>
		<tag-relate-popup ref="tagRelateBox"></tag-relate-popup>
	</div>
</template>

<script>
import TagRelatePopup from '@/views/common/TagRelatePopup';
export default {
     
	components: {
     
		TagRelatePopup
	},
	data() {
     
		return {
     
			
		}
	},
	methods: {
     
		// 打开关联tag 浮窗
		// $event可用于传入触发click事件时鼠标的坐标
		// 根据指针坐标可以指定弹框的位置
    	showtagRelateBox(e) {
     
	    	this.$refs.tagRelateBox.handleOpen(e);
	    }
	}
}
</script>

CSS 动画

transition 添加多个属性

transition: transform 2s ease, border-radius 3s ease-out;   // 多个属性逗号隔开

CSS3 transition 属性 - 菜鸟教程

animation 定义动画的两种方式:

@keyframes go {
     
  from {
     }
  to {
     }
}
@keyframes go {
     
  0% {
     }
  50%{
     }
  100%{
     }
}

CSS3 animation(动画) 属性 - 菜鸟教程

CSS — 贝塞尔曲线(cubic-bezier)
css3动画贝塞尔曲线cubic-bezier,css3动画的五种情况
css3里的贝塞尔速度曲线

其他内容

前端简历中的项目经历怎么突出亮点?- 淘系技术

图片上传的问题
Content-Type: multipart/form-data
图片上传方式:base64或者file对象
base64图片比源文件大1/3,所以只能用于传一些非常小的图

Http请求中Content-Type

阿里云 Hands-on Labs

机器学习算法(一): 基于逻辑回归的分类预测
使用PolarDB和ECS搭建门户网站
基于Redis实现在线游戏积分排行榜

8月11日内容汇总

ES6 中的Map()和Set()

ES6 提供了新的数据结构Map()和Set()。Map是一组键值对的结构,具有极快的查找速度。Set类似于数组,但是成员的值都是唯一的,没有重复的值。

Map的用法:使用Array进行查找时,数组越长,就会耗费更多时间。但是通过Map,无论数组有多长,查找都非常高效。

// 创建的时候初始化
let mapObj = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3]
])
// 创建空map,之后添加元素
let mapObj = new Map()
mapObj.set('a', 1)
mapObj.set('b', 2)
mapObj.set('c', 3)
// 基本操作
mapObj.set('a', 1) // 添加元素
mapObj.delete('d') // 删除指定元素
mapObj.has('a') // true 检测是否包含某个key对应的元素
mapObj.get('a') // 1
// Map对象的长度不是length,而是size
console.log(mapObj.size) // 3

Set的用法:所有的成员值都是唯一的,可以实现数组去重,获取交集、并集、差集等。

// 创建的时候初始化,自动过滤重复的值
let setObj = new Set([1, 2, 3, 3])
// 创建的时候初始化,之后添加元素
let setObj = new Set()
setObj.add(1)
setObj.add(2)
setObj.add(3)
// 或者这样添加
[2,3,5,4,5,2,2].forEach(x => setObj.add(x));
// 基本操作
let s = new Set([1, 2, 3])
s.add(3) // 由于key重复,添加不进
s.delete(3) // 删除指定key
console.log(s) // 1 2
// Set对象的长度也是size
console.log(setObj.size)

Set的常用技巧:

// 数组去重
const arr = [2,2,4,2,3,4];
const unique = [... nw Set(arr)];

// Array.from 方法可以将 Set 结构转为数组
function unique(array) {
     
	return Array.from(new Set(array));
}

// 扩展运算符内部使用for of循环,也能嫁给你Set转为数组
let set = new Set(['red', 'green', 'blue']);
let arr = [...set];

// 实现并集、交集、差集
let a = new Set([1,2,3]);
let b = new Set([4,3,2]);

let union = new Set([...a, ...b]);
console.log(union);

let intersect = new Set([...a].filter(x => b.has(x)));
console.log(intersect);

let difference = new Set([...a].filter(x => !b.has(x)));
console.log(difference);

Set 和 Map 数据结构 - 阮一峰
js中ES6的Set的基本用法
js中的Set和Map简单使用
JS中集合对象(Array、Map、Set)及类数组对象的使用与对比

技术热点

语雀的技术架构演进之路
React + TypeScript/JavaScript + Element + egg.js
egg.js 官方文档
curl 的用法指南 - 阮一峰

Vue 设置动态样式

// 三元运算符判断
<div :style="{ 'opacity': !editableCheckNum ? 0.5 : 1 }">555</div>
// 设置动态class
<div :class="activeMachineId"></div>
// 方法判断
<div :style="handleStyle(item.style)"></div>

div 标签width根据内容自适应

width: auto;
max-width: 100%; /* 最大宽度为父元素宽度 */

text-overflow: ellipsis 无效的问题

在开发中用了overflow: hidden和text-overflow: ellipsis,结果发现只有英文和数字才有…的效果,中文只有隐藏。查了一下,还需要加一句white-space: nowrap

.the-tag {
     
	width: 160px;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}

8月10日内容汇总

JS 数据类型详解

JavaScript一共有8种数据类型,其中有7种基本数据类型:Undefined、Null、Boolean、Number、String、Symbol(es6新增,表示独一无二的值)和BigInt(es10新增);

1种引用数据类型——Object(Object本质上是由一组无序的名值对组成的)。里面包含 function、Array、Date等。JavaScript不支持任何创建自定义类型的机制,而所有值最终都将是上述 8 种数据类型之一。
「前端料包」可能是最透彻的JavaScript数据类型详解

JS 面试必备

之前的干货再捞一下
由浅入深,66条JavaScript面试知识点

var 和 let,const

除了作用域不同之外,var声明的变量会挂载在window上,而let和const声明的变量不会

var a1 = "3242423";
console.log(this.a1); // "3242423"
let a2 = "代表一个沙壁";
console.log(this.a2); // undefined

JS 自动装箱机制

字符串(String)是基本类型,没有属性和方法,但是字符串却可以调用length

const str = "323425435345";
console.log(str.length); // 12

这是因为 JS 内部自动对这个字符串进行了装箱操作,即将这个字符串封装为实例对象,然后再调用实例对象上的length方法输出结果,最后销毁这个对象

let Str = new String("323425435345");
console.log(Str.length);
Str = null;

可以看到实例对象Str的__proto__上挂载有length方法,而构造函数String()的prototype上也有length方法。(实际上,实例对象的__proto__ === 构造函数的prototype)
资料汇总_第6张图片

8月7日内容汇总

第一期:前端九条bug分享
第三期:前端九条bug分享
记一次grid布局实战应用分享会
前端面试题总结(js、html、小程序、React、ES6、Vue、算法、全栈热门视频资源)

JS基础总结(4)——this指向及call/apply/bind

防抖:当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。
节流:当持续触发事件时,保证一定时间段内只调用一次事件处理函数。
浅谈JavaScript的防抖与节流

8月6日内容汇总

Vue响应式数据原理:数据劫持和数据代理

Object.defineProperty() 和 ES2015 中新增的 Proxy 对象会经常用来做数据劫持

数据劫持:在访问或者修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果.数据劫持最典型的应用------双向的数据绑定

一道面试题:

什么样的a可以满足(a === 1 && a === 2 && a === 3) === true

既然是严格相等,类型转换什么的基本不考虑了。一个自然的想法就是每次访问 a 返回的值都不一样,那么肯定会想到数据劫持。

多继承

Javascript 通过原型链实现继承,正常情况一个对象(或者类)只能继承一个对象(或者类)。但通过这两个方法都可以实现一种黑科技,允许一个对象继承两个对象。下面的例子使用 Proxy 实现。

vue中是如何监听数组变化?

Object.defineProperty与Proxy理解整理
【第1423期】数据劫持 OR 数据代理
深入浅出Object.defineProperty()

面经合集

子弈大佬的面经
在阿里我是如何当面试官的

8月5日内容汇总

Vue.set()方法的使用

vue响应式的原理:

当你把一个普通的JS对象传给vue实例的data选项时,vue将遍历此对象的所有属性,并使用 Object.defineProperty把这些属性全部转为 getter/setter。Object.defineProperty是ES5中一个无法shim的特性,这也就是为什么vue不支持IE8以及更低版本的浏览器。

因为受现代JS的限制,vue不能检测到对象属性的添加或删除
由于vue会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在data对象上存在才能让vue转换它,这样它才能是响应的。

vue不允许在已经创建的实例上动态添加新的根级响应式属性,不过可以使用Vue.set()方法将响应式属性添加到嵌套的对象上

也可以使用 this.$set 实例方法,该方法是全局方法 Vue.set 的一个别名:

Vue.set(vm.items, indexOfItem, newValue)
// vm.items :源数据;indexOfItem : 要修改的数据的键;newValue : 要修改的数据
let a = [
    {
     name:'张三',age:'20',sex:1},
    {
     name:'李四',age:'21',sex:0},
    {
     name:'王五',age:'22',sex:1},
]
a[1].age = 19; // 修改李四的age为19
Vue.set(a,1,a[1]); // 这时候 a 是源数据, 1 是键, a[1]是修改后的数据
Vue.forceUpdate(); // 也可以用这个方法手动触发视图更改

深入响应式原理 - Vue.js官方文档
Vue.set() this.$set()引发的视图更新思考
说说vue.set() (this.$set) 的用法

边缘计算架构

边缘计算是什么,和云计算的区别是什么?- 知乎
什么是边缘计算?- 知乎
什么是边缘计算 What Is Edge Computing?
[原创]边缘计算开源方案对比
边缘计算的架构、挑战与应用

块级格式化上下文(Block formatting context, BFC)

什么是BFC?看这一篇就够了
CSS中重要的BFC

switch case的用法。

一般不在case里面直接return,而是先给变量赋值,到最后再return。

function checkFileType(suffix) {
     
	let fileTypeIcon;
    switch(suffix) {
     
      case "jpg":
      case "jpeg":
      case "png":
      case "gif":
        fileTypeIcon = "info_file_pic";
        break;
      case "pdf":
        fileTypeIcon = "info_file_pdf";
        break;
      case "doc":
      case "docx":
        fileTypeIcon = "info_file_word";
        break;
      case "xls":
      case "xlsx":
        fileTypeIcon = "info_file_excel";
        break;
      case "ppt":
      case "pptx":
        fileTypeIcon = "info_file_ppt";
        break;
      case "":
        fileTypeIcon = "info_file_folder";
        break;
    }
    // 如果未能匹配到
    return fileTypeIcon || "info_file_folder"
  },
}

如果case非常多代码就会很长,这个时候可以使用对象字面量来实现,语法更简洁。

// use object literal to find fruits in color
const fruitColor = {
     
  red: ['apple', 'strawberry'],
  yellow: ['banana', 'pineapple'],
  purple: ['grape', 'plum']
};
 
function test(color) {
     
  return fruitColor[color] || [];
}

ES6的Map()对象具有极高的查询效率,可以实现相同的效果。

// use Map to find fruits in color
const fruitColor = new Map()
  .set('red', ['apple', 'strawberry'])
  .set('yellow', ['banana', 'pineapple'])
  .set('purple', ['grape', 'plum']);
 
function test(color) {
     
  return fruitColor.get(color) || [];
}

8月3日内容汇总

尽量少用if else的技巧:|| 和 && 运算符

项目中经常遇到一个问题,后端返回字段为空的时候,会出现各种变量类型,例如一个原本是数组类型 的字段,用来保存附件信息,但是如果没有附件,这个字段有时会返回空数组,有时会返回null,这样的话,由于null是不可迭代的,因此会报错Cannot read property map of null。

在这种情况下,可以通过逻辑或 || 来判断,在其操作数中找到第一个真值表达式并返回它。当第一个变量为 nullundefined0"" 时,就让他为另一个缺省值

demandAttachments = this.demandAttachments || []
demand = {
     
	description: this.description || "暂无描述"}
function checkFileType(suffix) {
     
	// do something
	return fileType || "未匹配到文件"
}

实现一个逻辑,如果数组中没有某个元素,就把它push到这个数组中

!result.includes(item) && result.push(item)

&& 叫逻辑与,在其操作数中找到第一个虚值表达式并返回它,如果没有找到任何虚值表达式,则返回最后一个真值表达式。它采用短路来防止不必要的工作。
|| 叫逻辑或,在其操作数中找到第一个真值表达式并返回它。这也使用了短路来防止不必要的工作。在支持 ES6 默认函数参数之前,它用于初始化函数中的默认参数值。
!! 运算符可以将右侧的值强制转换为布尔值,这也是将值转换为布尔值的一种简单方法。

使用arguments对象获取函数参数

function fn(arguments) {
     
	// arguments = [a1, a2, a3]
}
fn(a1, a2, a3);

8月2日内容汇总

之前的内容再捞一下
基于Vue实现一个简易MVVM
你真的理解$nextTick么
Vue源码分析 - nextTick

推荐一篇非常好的文章,看完绝对有收获
Tasks, microtasks, queues and schedules

子弈大佬的GitHub,包含JS学习笔记,CSS学习笔记,数据结构与算法,react学习笔记等等
https://github.com/ziyi2?tab=repositories

7月31日内容汇总

React + TypeScript + Golang全栈
Go+GraphQL+React+Typescript搭建简书项目(一)——概览

Golang Gin web框架
Golang Gin 实战(一)| 快速安装入门
Golang Gin 实战(二)| 简便的Restful API 实现
Golang Gin 实战(三)| 路由参数
Golang Gin 实战(四)| URL查询参数的获取和原理分析

项目中遇到很多父子组件嵌套的场景,比如父组件中有一些概览信息,子组件中是详情数据,例如表格。数据由父组件通过xhr请求获取,然后传参给子组件,在子组件中通过props接收,然后通过监听props的变化,将该值传给data。

在很多业务场景中,子组件的详情数据都需要支持编辑操作,编辑操作通常是做两件事,一个是通过接口向后端发送更新的数据,二是更新组件的data,以更新视图。但是如果只更新子组件自己的data,那就无法与父组件保持同步,概览信息无法更新。为使父子组件之间能够同步数据,通常的做法包括:子组件向父组件传递更新的数据、让父组件从接口拉一下数据、强制刷新父组件。这样的做法很容易产生冗余数据,同样的数据在父组件和子组件都做了拷贝,没有必要,而且代码耦合度增加,导致组件复用困难。

本人在实践中发现,子组件的props传值给data其实没有必要。为什么要传值给data,因为一般认为,props的值是只读的,只有data才可以修改,所以要将props传给data。但是本人发现,props实际上和es6里的const很像,并非不能修改。当props的值为引用类型,例如对象,它的属性值都是可以修改的,因此展示和修改数据都可以用props。而且在子组件中修改props还会直接同步到父组件的data,两端数据会始终保持同步,不需要再进行额外的传参。

7月29日内容汇总

由浅入深,66条JavaScript面试知识点
解锁各种js数组骚操作,总有你想要的!
最强大的 CSS 布局 —— Grid 布局
总结前端性能优化的方法
你也许不知道的javascript高级函数

7月28日内容汇总

this.$nextTick()的用法

在项目中遇到这样一个问题,需要给一个弹窗里面的自定义组件传参。本人实现的流程如下,当弹窗显示的时候,监听dialogVisible的变化,如果为true,那么就给相应的data赋值,用v-bind实现传参。在实践过程中发现,当页面首次加载的时候,即便data已经被赋值,点开弹窗的时候参数仍然没有传入组件,重新点开弹窗才会传参。

watch: {
     
  dialogVisible: function(val) {
     
    // 弹窗展开时获取需求信息
    if (val == true) {
     
      // 新建状态下
      if (this.requireId == '') {
     
        this.getCurrentDemandClass();
      }
    }
  }
},

与此同事,本人发现另一个xhr方法却可以给弹窗内的组件正常传参,由此做出推断,在组件DOM更新完成之前是无法绑定传参的,只有当组件DOM更新完成后才能拿到参数。按照这个思路,只要把赋值操作改成异步方法就可以,用setTimeout()就能模拟异步方法,试了一下果然成功了,就是视图更新有点慢,弹窗显示之后过一会才会出现数据,用户体验较差。

watch: {
     
  dialogVisible: function(val) {
     
    // 弹窗展开时获取需求信息
    if (val == true) {
     
      // 新建状态下
      if (this.requireId == '') {
     
        setTimeout(() => {
     
          this.getCurrentDemandClass();
        }, 0)
      }
    }
  }
},

本人还看到项目里面类似的场景下有用到this.$nextTick()方法,拿来试试,发现也可以用,而且数据的显示基本是与弹窗同步的,不会存在刚才的问题。

watch: {
     
  dialogVisible: function(val) {
     
    // 弹窗展开时获取需求信息
    if (val == true) {
     
      // 新建状态下
      if (this.requireId == '') {
     
        this.$nextTick(() => {
     
          this.getCurrentDemandClass();
        })
      }
    }
  }
},

根据上面的示例可以看出,this.$nextTick()的作用大致就是等待DOM更新完毕后,再去执行回调函数,v-bind给组件传参是一个场景,另一个场景是用this.$refs执行组件内部的方法。

Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。
例如,当你设置 vm.someData = ‘new value’,该组件不会立即重新渲染。当刷新队列时,组件会在下一个事件循环“tick”中更新。多数情况我们不需要关心这个过程,但是如果你想基于更新后的 DOM 状态来做点什么,这就可能会有些棘手。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。

深入响应式原理 - Vue.js官方文档

自定义指令v-clickoutside

v-clickoutside可以在组件外部点击的时候执行方法,如收起popover

<template>
	<div>
		<!-- 人时 任务展示 -->
      <el-form-item v-if="detailType == 'task'">
        <span slot="label">
          <svg-icon icon-class="common_type"
                    class-name="svg-demand-class"></svg-icon>
          <span class="label_text">工时</span>
        </span>
        <span v-if="!edit.worktime"
              @click="initWorkTime">
              {
     {
     demand.workTime == 0 || demand.workTime == null ? "--" : demand.workTime}}
        </span>
        <el-input-number ref="pickWorktime"
                         v-else
                         v-model="demand.workTime"
                         :step="1"
                         :min="0"
                         v-clickoutside="() => {
     
            edit.worktime = false;
            changeCommand(demand, demand.workTime, 'workTime')
          }"></el-input-number>人时
      </el-form-item>
	</div>
</template>

<script>
import Clickoutside from "element-ui/src/utils/clickoutside";
export default {
     
	components: {
     
		
	},
	directives: {
     
		Clickoutside
	},
	data() {
     
		return {
     
			
		}
	},
	methods: {
     
		
	}
}
</script>

clickoutside自定义指令源码分析

弹性布局实现两端对齐

.box {
     
	display: flex;
	justify-content: space-between; /* 两端对齐 */
	align-items: center; /* 垂直居中 */
}

效果如下:
资料汇总_第7张图片

CSS box-sizing属性

box-sizing常用的有两个值:content-box或border-box

box-sizing: content-box|border-box

content-box(默认值)
这是 CSS2.1 指定的宽度和高度的行为。指定元素的宽度和高度(最小/最大属性)适用于box的宽度和高度。元素的填充和边框布局和绘制指定宽度和高度除外

border-box
指定宽度和高度(最小/最大属性)确定元素边框。也就是说,对元素指定宽度和高度包括了 padding 和 border 。通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度。

应用场景:响应式Web设计经常需要我们通过百分比设置组件宽度。如果我们不考虑边框,那么很容易就可以实现,但如果你给每一列以及总宽度都采用百分比设置,那这个时候固定的边框大小就会出来捣乱。
css3属性box-sizing:border-box 用法解析

debounce和throttle

没时间总结了,先上链接
前端性能优化——debounce
函数去抖(debounce)& 函数节流(throttle)总结
Lodash之throttle(节流)与debounce(防抖)总结

7月26日内容汇总

推荐:2019年十佳DevOps工具
Jenkins+Docker 持续集成、部署(CI/CD)项目实践

7月25日内容汇总

Vue运行机制概述,v-model双向绑定详解,面试必备
基于Vue实现一个简易MVVM

7月24日内容汇总

在插值表达式中使用三元表达式

<span style="padding-left: 10px;">{
     {
      requireId == '' ? '新建' : '编辑'}}需求</span>

在模板字符串中使用三元表达式

this.$message.success(`需求${
       this.requireId == '' ? '创建' : '更新'}成功!`);

使用箭头函数需要return

this.iterationMap = res.filter((item) => {
     
  return item.state != '关闭';
})

Vue组件嵌套传值

7月23日内容汇总

Jenkins - 持续集成引擎
Jenkins入门(一)
前端开发想了解机器学习?用一台Mac就可以

7月22日内容汇总

// 选中节点
handleNodeClick(data, node){
     
  this.valueList = []; // 先清空路径
  this.recursiveParentId(node); // 递归获取当前路径

  this.valueTitle = this.valueList.join(' / '); // 拼接路径
  this.valueId = data[this.props.value]
  this.$emit('getValue',this.valueId)
  this.defaultExpandedKey = []

  this.$refs.select.blur(); // 失去焦点,并收起下拉框
},
// 递归获取根节点
recursiveParentId(node) {
     
  if (node.data.id == -1) {
     
    this.valueList.unshift("所有分类")
    return
  } else {
     
    this.valueList.unshift(node.data.text);
    this.recursiveParentId(node.parent);
  }
}
// 这里定义ref
<el-select style="width: 100%;" :value="valueTitle" ref="select">
</el-select>
// 这里访问组件内部的方法
this.$refs.select.blur();

在popover和dialog中嵌套的div,样式需要定义在最外层,如果嵌套样式是访问不到的

popover, dialog如果放在外层的, 看element放在哪

popover-class
你看下这个属性
控件里面的
就是设定一个class, 然后再这个class 后面跟他下面的选择器
注意控制范围就好了

transition实现颜色过渡动画
资料汇总_第8张图片
在less中不能直接用>>>,需要用/deep/
资料汇总_第9张图片

7月21日内容汇总

通过cssText设置元素内联样式

let upload = document.querySelectorAll('.el-upload--picture-card')[0]
upload.style.cssText = 'display: none'

var elmnt = document.getElementsByTagName("h1")[0];
elmnt.style.cssText = "color: blue;";

防抖实现
资料汇总_第10张图片

7月20日内容汇总

通过自定义data-xxx标签实现动态样式

在html标签中定义data-level标签,其值为数组下标
资料汇总_第11张图片
在样式中这样定义
资料汇总_第12张图片

7月17日内容汇总

父组件访问子组件方法:通过$refs直接访问

<template>
    <div>
        <div @click="click">点击父组件</div>
        // 注意:这里需要加ref属性
        // 这里的属性值需要与下面调用的名称一致
        <tree-select ref="treeSelect"></tree-select>
    </div>
</template>
<script>
import treeSelect from "@/components/require/treeSelect";
export default {
     
    components: {
     
        treeSelect,
    },
    methods: {
     
        click() {
     
            this.$refs.treeSelect.clearTreeSelect() // 直接调用
        },
    }
}
</script>

JS删除数组中的元素

// splice() 方法用于添加或删除数组中的元素
array.splice(index,howmany,item1,.....,itemX);
// 从下标为2的元素开始删除1个元素
array.splice(2, 1);

JavaScript Array 对象
利用process.env.NODE_ENV设置不同环境的url

7月15日内容汇总

动态修改组件的样式

在项目中需要实现一个需求,根据优先级的不同修改div的颜色。师兄告诉我在标签内用data-xxx的属性,我觉得比较麻烦,希望动态修改组件样式,网上查了下果然可以。在这里priorityStyle是计算属性,所有的颜色判断的逻辑都放在这里。

<div :style="{
        'background-color': priorityStyle}">
	{
    { form.priority }}
div>
computed: {
     
  priorityStyle() {
     
    let style;
    if (this.form.priority == '低') {
     
      style = '#5ae6d7';
    }
    if (this.form.priority == '中') {
     
      style = '#0fbceb';
    }
    if (this.form.priority == '高') {
     
      style = '#ff426f';
    }
    return style;
  }
},

实践表明,动态属性放到methods里其实也可以

<template>
	<span class="child_state"
	      :class="state_color(child)"
	      @click="stateChange">
	  <svg-icon icon-class="info_ellipsis"
	            class-name="svg-check"
	            v-if="child.state == '规划中'"></svg-icon>
	  <svg-icon icon-class="info_doing_white"
	            class-name="svg-check"
	            v-else-if="child.state == '实现中'"></svg-icon>
	  <svg-icon icon-class="info_check_white"
	            class-name="svg-check"
	            v-else-if="child.state == '已实现'"></svg-icon>
	  <svg-icon icon-class="info_cross_white"
	            class-name="svg-check"
	            v-else-if="child.state == '已拒绝'"></svg-icon>
	  <span class="state">{
     {
     child.state}}</span>
	</span>
</template>

<script>
export default {
     
	methods: {
     
		state_color(sonDemand) {
     
		 let color = "";
		 switch (sonDemand.state) {
     
		   case "规划中":
		     color = "willing";
		     break;
		   case "实现中":
		     color = "doing";
		     break;
		   case "已实现":
		     color = "over";
		     break;
		   case "已拒绝":
		     color = "refuse";
		     break;
		 }
		 return color;
		},
	}
}
</script>

<style>
.over {
     
  background-color: rgb(0, 197, 101);
}
.doing {
     
  background-color: rgb(255, 162, 0);
}
.willing {
     
  background-color: rgb(0, 199, 207);
}
.refuse {
     
  background-color: rgb(80, 93, 124);
}
</style>

子组件获取父组件数据

在父组件使用子组件的地方绑定一下数据

<template>
<sub-list :submsg="msg"></sub-list>
</tempalte>

<script>
import subList from "@/components/xxxx"

export default {
     
	components: {
     
		subList
	},
	data() {
     
		return {
     
			msg: "您好,加菲猫!"
		}
	}
}
</script>

在子组件中通过props接收
Vue 实现文件的上传
vue中的文件上传和下载
基于Element-UI的组件改造的树形选择器(树形下拉框)
Element-UI 实现树形选择器

7月14日内容汇总

el-select宽度自适应父元素宽度

在使用饿了么组件的时候,el-select选择器的宽度默认是由里面的文本决定的,如果希望自适应父元素宽度,在el-select的标签内添加style属性,设置width: 100%即可。

<el-select v-model="form2.type"
           placeholder="请选择"
           style="width: 100%;">
  <el-option label="区域一"
             value="shanghai">el-option>
  <el-option label="区域二"
             value="beijing">el-option>
el-select>

组件引入及使用

在vue项目中 @ 符号代表的是根目录,即 src 目录。
在项目中,公用的组件放在components目录下,项目组件放在views目录下。

  1. 第一种使用方式

    /* 引入 */
    import navs from '@/views/nav/index'
    
    /* 注册组件 */
    components:{
           
      'v-nav':navs
    }
    
    /* 在模板中使用 */
    <v-nav></v-nav>
    
  2. 第二种使用方式

    /* 引入 */
    import navs from '@/views/nav/index'
    import indexList from './index-list'
    
    /* 注册组件 */
    components: {
            navs,indexList },
    
    /* 在模板中使用 */
    <index-list></index-list>
    <navs></navs>
    
  3. 第三种使用方式

    /* 目录结构 */
    components/BacktoTop/index.vue
    
    /* 引入 */
    import BackToTop from '@/components/BackToTop'
    
    /* 注册组件 */
    components: {
            BackToTop },
    
    /* 在模板中使用 */
    <el-tooltip placement="top" content="tooltip">
      <back-to-top :custom-style="myBackToTopStyle" :visibility-height="300" :back-position="50" transition-name="fade" />
    </el-tooltip>
    

VUE修饰符sync

深入理解vue 修饰符sync【 vue sync修饰符示例】
彻底明白VUE修饰符sync

7月13日内容汇总

在覆盖饿了么UI某个控件原生样式的时候发现一直都不生效,使用!important同样也无效,经师兄指点,用了deep穿透,样式覆盖成功,>>>这个是简写。

>>> .el-badge .el-badge__content {
     
  background: rgba(0,0,0,0.08);
  font-family: SegoeUI;
  font-size: 12px;
  color: rgba(0,0,0,0.56);
  letter-spacing: 0;
  line-height: 16px;
}

vue css >>> /deep/ 穿透

全局覆盖和局部覆盖

/* 这是全局覆盖 */
.el-menu-item.is-active {
     
  border-bottom-color: #00aea6 !important;
  color: rgba(0, 0, 0, 0.88) !important;
}
/* 这是在.main-list下局部覆盖 */
.main-list .el-menu-item.is-active {
     
  border-bottom-color: #00aea6 !important;
  color: rgba(0, 0, 0, 0.88) !important;
}

7月10日内容汇总

Less快速入门
SCSS快速入门
sass/scss 和 less的区别
Minder敏捷开发平台项目列表已上传Github

7月8日内容汇总

CSS padding属性的说明

padding:10px 5px 15px 20px;
上填充是 10px
右填充是 5px
下填充是 15px
左填充是 20px
padding:10px 5px 15px;
上填充是 10px
右填充和左填充是 5px
下填充是 15px
padding:10px 5px;
上填充和下填充是 10px
右填充和左填充是 5px
padding:10px;
所有四个填充都是 10px

CSS line-height属性

设置行间距,将行高设为父元素高度,可以实现文字在div内的垂直居中

<style>
.default {
      
	border-bottom: 1px solid;
	height: 40px; /* 这个是父元素高度 */
	line-height: 40px; /* 实现文字垂直居中 */
}
style>
<body>
<div class="default">
这是一个标准行高的段落。
div>
<div class="default">
这是一个标准行高的段落。
div>
<div class="default">
这是一个标准行高的段落。
div>
body>

CSS border属性

在设置div边框宽度后,还必须指定边框样式,否则不显示

.single-item{
     
	border:5px solid red;
}

7月7日内容汇总

TortoiseSVN 使用教程

TortoiseSVN下载及安装地址
根据上面的提示安装,安装之后文件夹内点击鼠标右键看到有SVN的菜单就算安装成功
更新操作:鼠标右键update
提交文件:鼠标右键commit
一般就用updatecommit

7月6日内容汇总

一次弄懂Event Loop(彻底解决此类面试问题)
JS之Event Loop(事件循环)
js笔记十二:利用await和async,将回调函数变成同步的处理的办法
饿了么前端组件
CSS命名规范–BEM

7月3日内容汇总

Fetch使用

fetch是一种HTTP数据请求的方式,是XMLHttpRequest的一种替代方案。fetch不是ajax的进一步封装,而是原生js。Fetch函数就是原生js,没有使用XMLHttpRequest对象。

fetch(url).then(response => response.json()) // 或者response.text()
  .then(data => console.log(data))
  .catch(e => console.log("Oops, error", e))

fetch API获取返回值的方式
Js中数组去重的几种方法
js调试技巧(通过debugger调试)
解析JS如何运用断点进行调试

7月2日内容汇总

chrome-extensions-examples
chrome.webRequest
Chrome Extension - How to get HTTP Response Body?
Chrome Extension 获得RequstBody

7月1日内容汇总

chrome-plugin-demo
Chrome插件中 popup,background,contantscript消息传递机制
实例解析防抖动(Debouncing)和节流阀(Throttling)
函数去抖(debounce)& 函数节流(throttle)总结

6月29日内容汇总

this.$nextTick用法和意义
本地编辑项目的时候,如果远程仓库的内容已被更改,这个时候执行git pull会提示如下错误:

error: Your local changes to the following files would be overwritten by merge:

接下来分两种情况处理:

  1. 保留本地的修改同时又把远程的合并过来

    git stash  // 将本地快照
    git pull origin master  // 用远程代码覆盖本地
    git stash pop  // 恢复本地修改
    

    下一步就可以commit和push了

  2. 不保留本地修改

    git reset --hard  // 将本地的状态恢复到上一个commit id
    git pull origin master  // 用远程的代码直接覆盖本地
    

【Git】pull遇到错误:error: Your local changes to the following files would be overwritten by merge:

6月28日内容汇总

这 10 行比较字符串相等的代码给我整懵了,不信你也来看看
告别动态规划,连刷40道动规算法题,我总结了动规的套路
Vue基础知识总结(绝对经典)
Vue中this.$router.push(参数) 实现页面跳转
vue中返回上一页go()和back()的区别
Vue.js 路由 - 菜鸟教程
Vue设置路由跳转的两种方法: 和router.push(…)
vue中处理文本不换行问题
Vue插值文本换行问题

6月24日内容汇总

Vue.js系列

一、vue基础语法
二、vue组件化开发
三、vue前后端交互(轻松入门vue)
四、vue前端路由
vue脚手架学习总结,vue参数、基础指令、声明周期函数、组件、插槽(持续更新)
Vue3.0来了,一起来看看尤大大说了啥

Vue Router系列

vue-router 基本使用
Vue学习笔记——Vue-router
Vue Router官方文档

Flex弹性布局

Flex弹性布局教程-语法篇

Javascript系列

JavaScript Array 对象 - 菜鸟教程
JavaScript ES6 字符串、数组、Map、Set
javaScript教程之JS常用字符串API汇总梳理
Airbnb Javascript Style Guide

你可能感兴趣的:(flex弹性布局,Javascript,Vue.js,vue,javascript,flex)