0%

方法一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
let input = [
{
id: 1,
val: "学校",
parentId: null,
},
{
id: 2,
val: "班级1",
parentId: 1,
},
{
id: 3,
val: "班级2",
parentId: 1,
},
{
id: 4,
val: "学生1",
parentId: 2,
},
{
id: 5,
val: "学生2",
parentId: 3,
},
{
id: 6,
val: "学生3",
parentId: 3,
},
];
function buildTree(arr, parentId, childrenArray) {
arr.forEach((item) => {
if (item.parentId === parentId) {
item.children = [];
buildTree(arr, item.id, item.children);
childrenArray.push(item);
}
});
}
function arrayToTree(input, parentId) {
const array = [];
buildTree(input, parentId, array);
return array.length > 0 ? (array.length > 1 ? array : array[0]) : {};
}
const obj = arrayToTree(input, null);
console.log(obj);

方法二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const tempArr = [{
id: 1,
parentId: 0
},
{
id: 2,
parentId: 1
},
{
id: 3,
parentId: 1
},
{
id: 4,
parentId: 2
},
];

function arrayToTree(sourceArr) {
sourceArr.forEach(item => {
let parentId = item.parentId;
if (parentId !== 0) {
sourceArr.forEach(subitem => {
if (subitem.id == parentId) {
if (!subitem.children) {
subitem.children = [];
}
subitem.children.push(item);
}
});
}
});
return sourceArr.filter(item => item.parentId === 0);
}
console.log(arrayToTree(tempArr));

方法三

阅读全文 »

瀑布流布局

纵向瀑布流

实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
var colCount //定义列数
var colHeightArry = [] //定义列高度数组
var imgWidth = $('.waterfall img').outerWidth(true) //单张图片的宽度
colCount = parseInt($('.waterfall').width() / imgWidth) //计算出列数
for (var i = 0; i < colCount; i++) {
colHeightArry[i] = 0
}

//[0,0,0]
$('.waterfall img').on('load', function () {
var minValue = colHeightArry[0] //定义最小的高度
var minIndex = 0 //定义最小高度的下标
for (var i = 0; i < colCount; i++) {
if (colHeightArry[i] < minValue) { //如果最小高度组数中的值小于最小值
minValue = colHeightArry[i] //那么认为最小高度数组中的值是真正的最小值
minIndex = i //最小下标为当前下标
}
}
$(this).css({
left: minIndex * imgWidth,
top: minValue
})
colHeightArry[minIndex] += $(this).outerHeight(true)
})

//当窗口大小重置之后,重新执行
$(window).on('resize', function () {
reset()
})

//当窗口加载完毕,执行瀑布流
$(window).on('load', function () {
reset()
})

//定义reset函数
function reset() {
var colHeightArry = []
colCount = parseInt($('.waterfall').width() / imgWidth)
for (var i = 0; i < colCount; i++) {
colHeightArry[i] = 0
}
$('.waterfall img').each(function () {
var minValue = colHeightArry[0]
var minIndex = 0
for (var i = 0; i < colCount; i++) {
if (colHeightArry[i] < minValue) {
minValue = colHeightArry[i]
minIndex = i
}
}
$(this).css({
left: minIndex * imgWidth,
top: minValue
})
colHeightArry[minIndex] += $(this).outerHeight(true)
})
}
总结瀑布流布局原理
阅读全文 »

闭包是什么

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)

函数执行后返回结果是一个内部函数,并被外部变量所引用,如果内部函数持有被执行函数作用域的变量,即形成了闭包。

可以在内部函数访问到外部函数作用域。使用闭包,一可以读取函数中的变量,二可以将函数中的变量存储在内存中,保护变量不被污染。而正因闭包会把函数中的变量值存储在内存中,会对内存有消耗,所以不能滥用闭包,否则会影响网页性能,造成内存泄漏。当不需要使用闭包时,要及时释放内存,可将内层函数对象的变量赋值为null。

在 JavaScript中,每当创建一个函数,闭包就会在函数创建的同时被创建出来,作为函数内部与外部连接起来的一座桥梁

阅读全文 »

字体属性: (font)

大小{font-size: x-large;}(特大) xx-small;(极小) 一般中文用不到,只要用数值就可以,单位: PX、 PD
样式{font-style: oblique;}(偏斜体) italic;(斜体) normal;(正常)
行高{line-height: normal;}(正常)单位: PX. PD、EM
粗细{font-weight: bold;}(粗体) lighter;(细体) normal;(正常)
变体{font-variant: small-caps;}(小型大写字母) normal;(正常)
大小写{text- transform: capitalize;}(首字母大写) uppercase;(大写) lowercase;(小写) none;(无)
修饰{text-decoration: underline;}(下划线) overline;(上划线) line-through;(删除线) blink;(闪烁)

常用字体: (font-family)

"Courier New", Courier, monospace, "Times New Roman", Times, serif, Arial, Helvetica, sans-serif, Verdana

背景属性: (background)

阅读全文 »

问题描述

因为浏览器缓存原因导致打包的文件偶尔会出现不能及时更新最新代码。

解决方案

对于每次打包后的文件加上一个时间戳,使浏览器的缓存失效 找到vue.config.js文件下的chainWebpack 并加入以下配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
chainWebpack(config) {
// 略......
const timestamp = new Date().getTime()
if (process.env.NODE_ENV === 'production') {
// 给js和css配置版本号
config.output.filename(`js/[name].${timestamp}.js`).end()
config.output.chunkFilename(`js/[name].${timestamp}.js`).end()
config.plugin('extract-css').tap(args => [{
filename: `css/[name].${timestamp}.css`,
chunkFilename: `css/[name].${timestamp}.css`
}])
// 注意 此处由坑
//当我们配置了 打包后静态文件输出为 assetsDir:'static' 后
// 那么下面的路径也应该加上static
/* config.output.filename(`static/js/[name].${timestamp}.js`).end()
config.output.chunkFilename(`static/js/[name].${timestamp}.js`).end()
config.plugin('extract-css').tap(args => [{
filename: `static/css/[name].${timestamp}.css`,
chunkFilename: `static/css/[name].${timestamp}.css`
}]) */
}
// 略......
}

一、安装插件(compression-webpack-plugin)

1
npm install compression-webpack-plugin --save-dev

可能出现的错误:

Unsupported URL Type: npm:vue-loader@^16.1.0

原因:npm版本过低

阅读全文 »

1.主动调用uni.hideKeyboard()收起键盘后点击屏幕任意区域键盘重新抬起的问题。

解决方案:给input的focus绑一个flag(false),聚焦赋true,失焦赋flase即可解决

2. 日历组件选择时间域时 input显示的时间与点击同步修改,预期为点击完成时才进行值变更

原因: 传递给子组件的时一个数组,由于传入的是一个引用赋值时未进行深拷贝导致此问题出现 解决方案: 对象或者数组传递时需要进行深拷贝 可以使用扩展运算符 …

3. ios系统 浏览器div可编辑属性 contenteditable``=``"true" 不生效

阅读全文 »

为什么前端框架Vue能够做到响应式?当依赖数据发生变化时,会对页面进行自动更新,其原理还是在于对响应式数据的获取和设置进行了监听,一旦监听到数据发生变化,依赖该数据的函数就会重新执行,达到更新的效果。那么我们如果想监听对象中的属性被设置和获取的过程,可以怎么做呢?

1、Object.defineProperty

在ES6之前,如果想监听对象属性的获取和设置,可以借助Object.defineProperty方法的存取属性描述符来实现,具体怎么用呢?我们来看一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const obj = {
name: 'curry',
age: 30
}

// 1.拿到obj所有的key
const keys = Object.keys(obj)

// 2.遍历obj所有的key,并设置存取属性描述符
keys.forEach(key => {
let value = obj[key]

Object.defineProperty(obj, key, {
get: function() {
console.log(`obj对象的${key}属性被访问啦!`)
return value
},
set: function(newValue) {
console.log(`obj对象的${key}属性被设置啦!`)
value = newValue
}
})
})

// 设置:
obj.name = 'kobe' // obj对象的name属性被设置啦!
obj.age = 24 // obj对象的age属性被设置啦!
// 访问:
console.log(obj.name) // obj对象的name属性被访问啦!
console.log(obj.age) // obj对象的age属性被访问啦!

在Vue2.x中响应式原理实现的核心就是使用的Object.defineProperty,而在Vue3.x中响应式原理的核心被换成了Proxy,为什么要这样做呢?主要是Object.defineProperty用来监听对象属性变化,有以下缺点:

阅读全文 »

前段时间写项目遇到一个问题,更改代码时页面自动刷新,vuex中的数据丢失,导致需要重新返回赋值的页面,开发起来影响效率,于是想到了vuex的持久化处理。

起初我是这样用的

先下载插件

1
npm install vuex-persistedstate --save

引入插件

阅读全文 »

采用合理的数据处理算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* 数组转树形结构,时间复杂度O(n)
* @param list 数组
* @param idKey 元素id键
* @param parIdKey 元素父id键
* @param parId 第一级根节点的父id值
* @return {[]}
*/
function listToTree (list,idKey,parIdKey,parId) {
let map = {};
let result = [];
let len = list.length;

// 构建map
for (let i = 0; i < len; i++) {
//将数组中数据转为键值对结构 (这里的数组和obj会相互引用,这是算法实现的重点)
map[list[i][idKey]] = list[i];
}

// 构建树形数组
for(let i=0; i < len; i++) {
let itemParId = list[i][parIdKey];
// 顶级节点
if(itemParId === parId) {
result.push(list[i]);
continue;
}
// 孤儿节点,舍弃(不存在其父节点)
if(!map[itemParId]){
continue;
}
// 将当前节点插入到父节点的children中(由于是引用数据类型,obj中对于节点变化,result中对应节点会跟着变化)
if(map[itemParId].children) {
map[itemParId].children.push(list[i]);
} else {
map[itemParId].children = [list[i]];
}
}
return result;
}
判断一个json字符串
1
2
3
4
var str = "{'   retmsg':'success   ',\n'  trans_date':'   20170906'}";
console.log(str);
//"{' retmsg':'success ',
//' trans_date':' 20170906'}"

去掉空格

阅读全文 »