百度、谷歌、搜狗、必应、360怎么提交网站收录、网址索引

为了加快网站被各大搜索引擎收录,建议新站点手动提交一下网站

百度搜索(baidu)主动提交网站索引的地址

https://ziyuan.baidu.com/site/index

其次百度也有一个手动匿名提交网站收录的入口

https://ziyuan.baidu.com/linksubmit/url

在百度的搜索资源平台-用户中心-站点管理里可以手动提交站点

咱们可以选择百度提供的如下3种验证方式进行站点的验证

  • 文件验证
  • HTML标签验证
  • CNAME验证

具体页面长这样👇,还是比较简单的

搜狗搜索(sogo)主动提交网站索引的地址

https://zhanzhang.sogou.com/index.php/dashboard/index

在搜狗的资源平台-网站支持-站点验证里可以手动提交站点

咱们可以选择搜狗提供的如下2种验证方式进行站点的验证

  • 文件验证
  • HTML标签验证

具体页面长这样👇,也还是比较简单的,不过比较操蛋的是我用HTML标签验证一直验证不成功

360搜索(so)主动提交网站索引的地址

https://info.so.360.cn/site_submit.html

直接点击链接就可以提交网址验证了,360搜索的网站收录提交是匿名的,没那么麻烦

具体页面长这样👇,超级简单了

谷歌搜索(google)主动提交网站索引的地址

https://search.google.com/search-console/not-verified

点击链接登录谷歌账号以后,点击左上角的搜索资源下拉添加自己的网站域名

咱们可以选择谷歌提供的如下1种验证方式进行站点的验证

  • DNS解析验证

具体页面长这样👇,需要自己去域名服务商那里解析一个TXT值,就是这个谷歌给出的这个一串字符

必应搜索(bing)主动提交网站索引的地址

https://www.bing.com/webmasters

咱们可以选择必应提供的如下3种验证方式进行站点的验证

  • 文件验证
  • HTML标签验证
  • CNAME验证

具体页面长这样👇,还是比较简单的

Fetch简单封装

不多逼逼,直接上代码

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
function request(option = {
method: 'GET',
formData: false
}) {
let url = option.url
if (option.param) {
url = `${url}?${qs(option.param)}`
}
function qs(data, flag) {
const typeObj = (obj) => Object.prototype.toString.call(obj).slice(8, -1) === 'Object'
const typeArr = (obj) => Object.prototype.toString.call(obj).slice(8, -1) === 'Array'
var str = '', originData, encodeData;
for (var i in data) {
if (data.hasOwnProperty(i)) {
originData = data[i]
if (typeObj(originData) || typeArr(originData)) {
str += qs(originData, i)
} else {
encodeData = encodeURIComponent(originData)
if (typeObj(data) && flag) {
str += `${flag}[${i}]=${encodeData}&`
} else if (typeArr(data) && flag) {
str += `${flag}[${i}]=${encodeData}&`
// str += `${flag}=${encodeData}&`
} else {
if (str.length > 0 && str[str.length - 1] !== '&') str += '&';
str += `${i}=${encodeData}&`
}
}
}
}
return str[str.length - 1] === '&' ? str.slice(0, -1) : str
}
return fetch(url, {
method: option.method,
headers: option.formData ? undefined : {
'Content-Type': 'application/json',
},
body: option.formData ? Object.keys(option.data).reduce((ret, val) => {
ret.append(val, option.data[val])
return ret
}, new FormData()) : JSON.stringify(option.data),
}).then(response => response.json())
}

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// get请求
await request({
url: 'https://netease-cloud-music-api-dv7rufaa3-vearvip.vercel.app/search',
method: 'GET',
param: {
keywords: '海阔天空'
}
})
// post请求
// formData自行决定是否开启,默认不开启
await request({
url: 'https://netease-cloud-music-api-dv7rufaa3-vearvip.vercel.app/search',
method: 'POST',
formData: true,
data: {
keywords: '海阔天空'
}
})

Js转文件为Base64和Js下载Base64文件

非常的好用!

js转文件为base64字符串

1
2
3
4
5
6
7
8
function fileToBase64(file, callback) {
let reader = new FileReader();
reader.addEventListener('load', (e) => {
callback(e.target.result);
reader = null;
});
reader.readAsDataURL(file);
}

竟然还有童鞋不知道咋上传文件,下面封装了一下,直接调用pickerFileBase64这个函数就可以选取文件并且得到base64字符串了

用例:纯Js获取文件并转base64

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function pickerFileBase64() {
return new Promise((resolve) => {
const inputFile = document.createElement('input')
inputFile.type = 'file'
inputFile.onchange = event => {
const file = event.target.files[0]
function fileToBase64(file, callback) {
const reader = new FileReader();
reader.addEventListener('load', (e) => {
callback(e.target.result);
reader = null;
});
reader.readAsDataURL(file);
}
fileToBase64(file, resolve)
}
inputFile.click()
})
}

(async () => {
const base64 = await pickerFileBase64()
console.log(base64)
})()

下载base64字符串文件也是非常简单的,直接调用就完事了

js下载base64字符串文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function downloadBase64File(base64,name){
function dataURLtoBlob(dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
}

function downloadFile(url,name=new Date().toLocaleString()){
var a = document.createElement("a")
a.setAttribute("href",url)
a.setAttribute("download",name)
a.setAttribute("target","_blank")
let clickEvent = document.createEvent("MouseEvents");
clickEvent.initEvent("click", true, true);
a.dispatchEvent(clickEvent);
}
var myBlob = dataURLtoBlob(base64)
var myUrl = URL.createObjectURL(myBlob)
downloadFile(myUrl,name)
}

Unity笔记-时钟代码

学习自这个教程: https://mp.weixin.qq.com/s/QaEZuMRGTf07pml_h1rhxA

首先创造一个表盘

GameObject → 3D Object → Cylinder 创建1个圆柱体

给它加上刻度

GameObject → 3D Object → Cube 创建12个方块

再加上指针

GameObject → 3D Object → Cube 创建3个方块

最后加上脚本让他动起来

效果如下

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
using System;
using UnityEngine;

public class Clock : MonoBehaviour
{
const float degressPreHour = 30f;
const float degressPreMinuteSecond = 6f;
public Transform HourArmTransform;
public Transform MinusArmTransform;
public Transform SecondArmTransform;

// 每秒动一次
void makeArmRun()
{
var time = DateTime.Now;
HourArmTransform.localRotation = Quaternion.Euler(0, time.Hour * degressPreHour, 0);
MinusArmTransform.localRotation = Quaternion.Euler(0, time.Minute * degressPreMinuteSecond, 0);
SecondArmTransform.localRotation = Quaternion.Euler(0, time.Second * degressPreMinuteSecond, 0);
}
// 一直都动
void makeArmRunContinuous()
{
var time = DateTime.Now.TimeOfDay;
HourArmTransform.localRotation = Quaternion.Euler(0, (float)time.TotalHours * degressPreHour, 0);
MinusArmTransform.localRotation = Quaternion.Euler(0, (float)time.TotalMinutes * degressPreMinuteSecond, 0);
SecondArmTransform.localRotation = Quaternion.Euler(0, (float)time.TotalSeconds * degressPreMinuteSecond, 0);
}

// Update is called once per frame
void Update()
{
//makeArmRun();
makeArmRunContinuous();

}
}

业务代码问题记录

二维数组合并

输入这样一个数组

1
2
3
4
[
['A', 'B'],
['C', 'D'],
]

要求经过处理得到这样一个结果, 也就是 2x2 = 4个

1
2
3
4
5
6
[
'AC',
'AD',
'BC',
'BD',
]

或者这个数组

1
2
3
4
5
[
['A', 'B'],
['C', 'D'],
['E', 'F', 'G'],
]

要求经过处理得到这样一个结果, 也就是 2x2x3 = 12个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[
'ACE',
'ACF',
'ACG',
'ADE',
'ADF',
'ADG',
'BCE',
'BCF',
'BCG',
'BDE',
'BDF',
'BDG',
]

代码也很简单,没啥难度,只是做一下记录

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
let arr = [
['A', 'B'],
['C', 'D'],
['E', 'F', 'G'],
]

const foo = (origin, index = 1, next) => {
let result = []
if (origin.length === 1 || origin.length === 0) {
return origin[0] || []
}
if (index === 1) {
next = origin[0]
}
next.forEach(ele => {
origin[index].forEach(item => {
result.push(ele + item)
})
})
if (index === origin.length - 1) {
return result
}
return foo(origin, index + 1, result)
}
console.log('result', foo(arr))

React hooks使用setInterval产生的问题

需求: 显示当前的最新时分秒

一看哇,着很简单啊,刷刷刷开始写代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React, { useEffect, useState } from "react";

export default function App() {
const [hour, setHour] = useState();
const [minute, setMinute] = useState();
const [second, setSecond] = useState();

useEffect(() => {
const intervalId = setInterval(() => {
const nowDate = new Date();
setHour(() => nowDate.getHours());
setMinute(() => nowDate.getMinutes());
setSecond(() => nowDate.getSeconds());
}, 1000);
return clearInterval(intervalId)
}, []);

return <h1>{hour}时{minute}分{second}秒</h1>;
}

一顿操作猛如虎,运行一看就咋回事跑成这个鬼样子呢?

怎么没正常显示呢

写一个useInterval的hooks,这样时间就正常显示了

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
import React, { useEffect, useState, useRef } from "react";

const useInterval = (callback, delay) => {
const savedCallback = useRef(() => {});

useEffect(() => {
savedCallback.current = callback;
});

useEffect(() => {
if (delay !== null) {
const interval = setInterval(() => savedCallback.current(), delay || 0);
return () => clearInterval(interval);
}

return undefined;
}, [delay]);
};

export default function App() {
const [hour, setHour] = useState();
const [minute, setMinute] = useState();
const [second, setSecond] = useState();

useInterval(() => {
const nowDate = new Date();
setHour(nowDate.getHours());
setMinute(nowDate.getMinutes());
setSecond(nowDate.getSeconds());
}, 1000);

return <h1>{hour}时{minute}分{second}秒</h1>;
}

hexo的new_post_name到底有啥用,为啥没生效

首先明确 new_post_name 无论你配置成啥样,对展示的时候的文章title和网页上的时间是没有影响的

Hexo的hexo/_config.yml配置文件中的配置项,new_post_name是创建新的博文文件时使用的

当执行hexo new [layout] <title>的时候,会在[layout]文件夹下生成<title>.md的文章

同时也会生成<title>.md的文章的头

例子

编辑new_post_name参数为:year-:month-:day-:title.md

然后使用

1
hexo new 测试文章标题

会在根目录/source/_posts下生成2021-12-31-测试文章标题.md的文件

这个文件同时会写好hexo/scaffolds/post.md模版文件中定义好的文章头的参数

1
2
3
4
5
---
title: 测试文章标题
date: 2021-12-31 17:23:08
tags:
---

重点

也就是说new_post_name配置的东西,只是在使用命令行生成文件的时候有用,对网站上展示的东西是没影响的,有影响的是文章的头里填的属性

flutter神器getx介绍

基于官网文档提炼关键部分,方便安装使用

详细文档getx官方中文文档

关于Get

GetX 是 Flutter 上的一状态管理、依赖注入和路由管理的包

安装

将 Get 添加到你的 pubspec.yaml 文件中。

1
2
dependencies:
get:

在需要用到的文件中导入

1
import 'package:get/get.dart';

GetX的计数器示例

Flutter默认创建的 “计数器 “项目有100多行(含注释),为了展示Get的强大功能,我将使用 GetX 重写一个”计数器 Plus版”,实现:

  • 每次点击都能改变状态
  • 在不同页面之间切换
  • 在不同页面之间共享状态
  • 将业务逻辑与界面分离

而完成这一切只需 26 行代码(含注释)

  • 第一步:
    在你的MaterialApp前添加 “Get”,将其变成GetMaterialApp,GetMaterialApp会创建注入路由
1
void main() => runApp(GetMaterialApp(home: Home()));
  • 第二步:
    创建你的业务逻辑类,并将所有的变量,方法和控制器放在里面。
    你可以使用一个简单的”.obs “使任何变量成为可观察的。
1
2
3
4
class Controller extends GetxController{
var count = 0.obs;
increment() => count++;
}
  • 第三步:
    创建你的界面,使用StatelessWidget节省一些内存,使用Get不再需要使用StatefulWidget。
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
class Home extends StatelessWidget {

@override
Widget build(context) {

// 使用Get.put()实例化你的类,使其对当下的所有子路由可用。
final Controller c = Get.put(Controller());

return Scaffold(
// 使用Obx(()=>每当改变计数时,就更新Text()。
appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),

// 用一个简单的Get.to()即可代替Navigator.push那8行,无需上下文!
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
}
}

class Other extends StatelessWidget {
// 你可以让Get找到一个正在被其他页面使用的Controller,并将它返回给你。
final Controller c = Get.find();

@override
Widget build(context){
// 访问更新后的计数变量
return Scaffold(body: Center(child: Text("${c.count}")));
}
}

三大功能

响应式状态管理器

要想让它变得可观察,你只需要在它的末尾加上”.obs”。

1
var name = 'Jonatas Borges'.obs;

而在UI中,当你想显示该值并在值变化时更新页面,只需这样做。

1
Obx(() => Text("${controller.name}"));

这就是全部,就这么简单。

路由管理

在你的MaterialApp前加上 “Get”,把它变成GetMaterialApp。

1
2
3
GetMaterialApp( // Before: MaterialApp(
home: MyHome(),
)

导航到新页面

1
2

Get.to(NextScreen());
1
2

Get.toNamed('/details');

要关闭snackbars, dialogs, bottomsheets或任何你通常会用Navigator.pop(context)关闭的东西。

1
Get.back();

进入下一个页面,但没有返回上一个页面的选项(用于闪屏页,登录页面等)。

1
Get.off(NextScreen());

进入下一个页面并取消之前的所有路由(在购物车、投票和测试中很有用)。

1
Get.offAll(NextScreen());

依赖管理

Get依赖管理器就是导入状态管理

注入依赖:

1
Get.put<PutController>(PutController());

获取依赖:

1
2
3
4
5
6
Controller putController = Get.find<PutController>();
```

直接使用
```dart
Text(putController.textFromApi);

提示: Get依赖管理与包的其他部分是解耦的,所以可以导入多个

例子

Get.find() ,它可以帮你找到控制器,这个东西也是有限制的,这东西就找不到直接实例化的控制器,只能找到通过依赖注入的控制器

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
class ListPage extends StatelessWidget {
// 直接实例化,Get.find找不到
final ListController controller = ListController();

final GoodsController goodsController = Get.put(GoodsController());

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("依赖管理"),
centerTitle: true,
),
body: Column(
children: [
Text("渲染ListController的数据"),
Row(
children: controller.lists.map((item) => Text("$item, ")).toList(),
),
SizedBox(height: 50),
Text("渲染GoodsController的数据"),
Row(
children:
goodsController.goods.map((item) => Text("$item, ")).toList(),
),
SizedBox(height: 50),
Text("通过Get.find查找GoodsController"),
Row(
children: Get.find<GoodsController>()
.goods
.map((item) => Text("$item, "))
.toList(),
),
// 以下报错 【ListController not found, you need to call Get.put() 】
SizedBox(height: 50),
Text("通过Get.find查找ListController"),
Row(
children: Get.find<ListController>()
.lists
.map((item) => Text("$item, "))
.toList(),
)
],
),
);
}
}

Nest.js操控MongoDB的方法

一、安装 nestjs/mongoose 以及 mongoose 模块

Nest 操作 Mongodb 官方文档:https://docs.nestjs.com/techniques/mongodb

1
npm install --save @nestjs/mongoose mongoose

二、配置数据库连接地址

在 app.module.ts 中配置数据库连接

1
2
3
4
5
6
7
8
import { Module } from '@nestjs/common'; 
import { MongooseModule } from '@nestjs/mongoose';

@Module({
imports: [MongooseModule.forRoot('mongodb://localhost/koa',{ useNewUrlParser: true })]
})

export class ApplicationModule {}

三、配置 Schema

1
2
3
4
5
6
7
8
import * as mongoose from 'mongoose'; 

export const ArticleSchema = new mongoose.Schema({
title: String,
keywords:String,
author: Number,
status: String,
});

四、在控制器对应的 Module 中配置 Model

1
2
3
4
5
6
7
8
9
10
11
12
import { Module } from '@nestjs/common'; 
import { NewsController } from './news.controller';
import { NewsService } from './news.service';
import { ArticleSchema } from './schemas/article.schema';
import { MongooseModule } from '@nestjs/mongoose';

@Module({
imports: [MongooseModule.forFeature([{ name: 'Article', schema: ArticleSchema,collection:"article" }])], controllers: [NewsController],
providers: [NewsService]
})

export class NewsModule {}

五、在服务里面使用 InjectModel 获取数据库 Model 实现 操作数据库

1
2
3
4
5
6
7
8
9
10
import { Injectable } from '@nestjs/common'; 
import { InjectModel } from '@nestjs/mongoose';

@Injectable()
export class NewsService {
constructor(@InjectModel('Article') private readonly articleModel) {}
async findAll() {
return await this.articleModel.find().exec();
}
}

记录一次编程问题

先说问题

有如下一个数据,但它是用数组存放的具有联级关系的数据,需要将其转化为适合UI库的数据结构树状结构

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
const data = [
"办公设备、附件和用品>>办公用品>>书写工具>>毛笔",
"造纸原料和纸制品>>纸制品>>个人纸制品>>餐巾纸和餐巾",
"造纸原料和纸制品>>纸制品>>个人纸制品>>丝巾",
"办公设备、附件和用品>>办公用品>>测试分类>>苹果",
"其它",
"办公设备、附件和用品>>办公用品>>测试分类>>荔枝",
"办公设备、附件和用品>>家具用品>>床头用品>>枕头",
"食品、饮料和烟草>>肉和家禽产品>>加工和处理过的肉>>鲜的加工和处理过的肉",
"食品、饮料和烟草>>巧克力、糖、甜品和糖果>>糖果>>口香糖",
"食品、饮料和烟草>>饮料>>咖啡和茶>>咖啡饮料",
"食品、饮料和烟草>>饮料>>非酒精饮料>>泉水和矿泉水",
"办公设备、附件和用品>>办公用品>>书写工具>>水笔",
"造纸原料和纸制品>>纸制品>>个人纸制品>>纸巾",
"食品、饮料和烟草>>巧克力、糖、甜品和糖果>>巧克力、糖和甜品>>巧克力和巧克力代用品",
"食品、饮料和烟草>>饮料>>非酒精饮料>>水",
"食品、饮料和烟草>>乳制品和蛋>>牛奶和黄油产品>>贮藏的牛奶和黄油产品",
"食品、饮料和烟草>>预制食品和罐头>>方便什锦和用品>>方便什锦小吃",
"食品、饮料和烟草>>饮料>>咖啡和茶>>袋茶",
"食品、饮料和烟草>>面包和烘焙食品>>蛋糕、派和糕点>>新鲜蛋糕、派和糕点",
"休闲零食",
"食品、饮料和烟草>>饮料>>咖啡和茶>>非乳场生产的乳品饮料",
"服装、箱包、个人护理用品>>个人护理用品>>洗浴、身体护理品>>化妆品",
"食品、饮料和烟草>>饮料>>非酒精饮料>>软饮料",
"食品、饮料和烟草>>肉和家禽产品>>加工和处理过的肉>>贮藏加工和处理过的肉",
"食品、饮料和烟草>>谷类和豆类制品>>豆类>>豆粉",
"食品、饮料和烟草>>预制食品和罐头>>小吃>>坚果和水果干"
]

适合的结构如下

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
[
{
"value": "办公设备、附件和用品",
"lable": "办公设备、附件和用品",
"children": [
{
"value": "办公用品",
"lable": "办公用品",
"children": [
{
"value": "书写工具",
"lable": "书写工具",
"children": [
{
"value": "毛笔",
"lable": "毛笔"
}
...
]
}
...
]
}
...
]
}
]

首先的思路是切分字符串

使用String.prototype.split()将字符串切分为数组,方便分级

1
2
3
4
5
6
7
8
[
[ '办公设备、附件和用品', '办公用品', '书写工具', '毛笔' ],
[ '造纸原料和纸制品', '纸制品', '个人纸制品', '餐巾纸和餐巾' ],
[ '造纸原料和纸制品', '纸制品', '个人纸制品', '丝巾' ],
[ '办公设备、附件和用品', '办公用品', '测试分类', '苹果' ],
[ '其它' ],
...
]

简单点的就是死办法,看数据貌似只有4级,所以套四重循环就可以解决

但是这样真的很蠢,很笨,一旦数据发生变化,这就白写了

按照思路来先把数组中的字符串进行切分

1
2
3
4
5
6
const treeArr = []
const analysisData = (data) => { // 这样就得到了一个切分好的数组
data.forEach((ele, index) => {
treeArr.push(ele.split('>>'))
})
}

其次是观察数据结构

观察切分好的数据结构,有的是只有一级,没有子级的,有的呢,可能有四级也可能有三级。这样就对分级存放数据结构带来了很大的困扰。

这样就需要对每一条数据进行判断,这个判断的过程就抽出来写成一个函数就行了。

1
2
3
4
5
6
7
const treeArr = []
const analysisData = (data) => {
data.forEach(ele => {
const eleArr = ele.split('>>')
judgeData(treeArr, eleArr, 0)
})
}

这个函数接收3个传参

  • treeArr 存放预期数据结构的数组
  • eleArr 每一条原始的字符串切分数组
  • step 进行到第几步了

judgeData函数负责对传进来的每一条原始的字符串切分数组,进行判断,如果符合要求就push,不符合要求就递归判断,关键是递归的思想

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const judgeData = (treeArr, eleArr, step) => {
if (!treeArr.some(item => {
if (item.value === eleArr[step]) {
return true
}
})) {
const treeSon = {
value: eleArr[step],
lable: eleArr[step]
}
treeArr.push(treeSon)
if (eleArr[step + 1] !== undefined) {
treeSon.children = []
judgeData(treeSon.children, eleArr, step + 1)
}
} else {
treeArr.forEach(ele => {
if (ele.value === eleArr[step]) {
judgeData(ele.children, eleArr, step + 1)
}
})
}
}

treeArr传入的并不是预先在最开始设置的那个treeArr,而是每次存放预期数据结构的数组,因为js的对象是引用类型的所以,从对象上拆children下来传进去,并不影响存值,而step则是为了记录分级的层级,避免不知道到哪一步了,乱分。

这里贴上完整代码

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
59
60
61
const data = [
"办公设备、附件和用品>>办公用品>>书写工具>>毛笔",
"造纸原料和纸制品>>纸制品>>个人纸制品>>餐巾纸和餐巾",
"造纸原料和纸制品>>纸制品>>个人纸制品>>丝巾",
"办公设备、附件和用品>>办公用品>>测试分类>>苹果",
"其它",
"办公设备、附件和用品>>办公用品>>测试分类>>荔枝",
"办公设备、附件和用品>>家具用品>>床头用品>>枕头",
"食品、饮料和烟草>>肉和家禽产品>>加工和处理过的肉>>鲜的加工和处理过的肉",
"食品、饮料和烟草>>巧克力、糖、甜品和糖果>>糖果>>口香糖",
"食品、饮料和烟草>>饮料>>咖啡和茶>>咖啡饮料",
"食品、饮料和烟草>>饮料>>非酒精饮料>>泉水和矿泉水",
"办公设备、附件和用品>>办公用品>>书写工具>>水笔",
"造纸原料和纸制品>>纸制品>>个人纸制品>>纸巾",
"食品、饮料和烟草>>巧克力、糖、甜品和糖果>>巧克力、糖和甜品>>巧克力和巧克力代用品",
"食品、饮料和烟草>>饮料>>非酒精饮料>>水",
"食品、饮料和烟草>>乳制品和蛋>>牛奶和黄油产品>>贮藏的牛奶和黄油产品",
"食品、饮料和烟草>>预制食品和罐头>>方便什锦和用品>>方便什锦小吃",
"食品、饮料和烟草>>饮料>>咖啡和茶>>袋茶",
"食品、饮料和烟草>>面包和烘焙食品>>蛋糕、派和糕点>>新鲜蛋糕、派和糕点",
"休闲零食",
"食品、饮料和烟草>>饮料>>咖啡和茶>>非乳场生产的乳品饮料",
"服装、箱包、个人护理用品>>个人护理用品>>洗浴、身体护理品>>化妆品",
"食品、饮料和烟草>>饮料>>非酒精饮料>>软饮料",
"食品、饮料和烟草>>肉和家禽产品>>加工和处理过的肉>>贮藏加工和处理过的肉",
"食品、饮料和烟草>>谷类和豆类制品>>豆类>>豆粉",
"食品、饮料和烟草>>预制食品和罐头>>小吃>>坚果和水果干"
]
// console.log(data)
const treeArr = []
const analysisData = (data) => {
data.forEach(ele => {
const eleArr = ele.split('>>')
judgeData(treeArr, eleArr, 0)
})
}
const judgeData = (treeArr, eleArr, step) => {
if (!treeArr.some(item => {
if (item.value === eleArr[step]) {
return true
}
})) {
const treeSon = {
value: eleArr[step],
lable: eleArr[step]
}
treeArr.push(treeSon)
if (eleArr[step + 1] !== undefined) {
treeSon.children = []
judgeData(treeSon.children, eleArr, step + 1)
}
} else {
treeArr.forEach(ele => {
if (ele.value === eleArr[step]) {
judgeData(ele.children, eleArr, step + 1)
}
})
}
}
analysisData(data)
console.log('treeArr: ', JSON.stringify(treeArr))