首页

都2021年了,再不学ES6你就out了 —— 一文搞懂ES6

前端达人

导语:ES6是什么?用来做什么?

  • ES6, 全称 ECMAScript 6.0 ,是 JavaScript 的下一个版本标准,2015.06 发版

  • 虽然15年就有正式版本了,但是国内普遍商用是在2018年之后去了,甚至到现在有很多前端仍然搞不懂ES6(都2021年了,兄dei~)
    在这里插入图片描述

  • ES6 的出现主要是为了解决 ES5 的先天不足,比如 JavaScript 里并没有类的概念

  • 目前存在少数低版本浏览器的 JavaScript 是 ES5 版本,大多数的浏览器已经支持 ES6

  • ES6提供了大量的语法糖,让你写代码的时候简直不要太爽!

  • 你必须要知道的是:现在各企业都普遍使用,不会ES6意味着你很难找到工作,上班了你连别人的代码都看不懂
    在这里插入图片描述

1. let 与 const

1.1 let 与 var

  • let:ES6新增,用于声明变量,有块级作用域
  • var:ES5中用于声明变量的关键字,存在各种问题(例如:红杏出墙~)
  • 如果你的代码里还存在 var,那你的良心就大大的坏了!

var存在的问题:

 // 1.声明提升 // 此处会正常打印,但这是错误的(属于先上车后买票了!) console.log(name); var name = "大帅比"; // 2. 变量覆盖 var demo = "小明"; var demo = "小红"; // 此处会打印小红,这也是错误的(属于套牌车,违法的啊,兄弟) // 同一个项目中,发生变量覆盖可能会导致数据丢失以及各种不可预知的bug,原则上来说:变量不能重名 console.log(demo) // 3. 没有块级作用域 function fn2(){ for(var i = 0; i < 5; i++){ // do something } // 此处会正常打印出 i 的值,这是错误的 // i是定义在循环体之内的,只能在循环体内打印,当前现象叫做红杏出墙!!! console.log(i); } fn2(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

let不会存在上述问题:

 // 1. 不会存在声明提前 // 此处会报错(这里必须报错,原则上来说不能先上车后买票) console.log(name); let name = "大帅比"; // 2. 不会有变量覆盖 let demo = "小明"; let demo = "小红"; // 此处会报错(不能使用套牌车!)告诉你已经定义了此变量。避免了项目中存在变量覆盖的问题 console.log(demo) // 3. 有块级作用域 function fn2(){ for(let i = 0; i < 5; i++){ // do something } // 此处会报错,无法打印,防止红杏出墙!!! // i是定义在循环体之内的,循环体外当然无法打印  console.log(i); } fn2(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

const

  • const 声明一个只读的常量,一旦声明,常量的值就不能改变
  • 一般用于全局变量
  • 通常变量名全部大写(请按照规则来,不要乱搞,容易出事情)
const PI = "3.1415926"; 
  • 1

2. 解构赋值

  • 解构赋值是对赋值运算符的扩展
  • 针对数组或者对象进行模式匹配,然后对其中的变量进行赋值
  • 代码简洁且易读,语义更加清晰明了,方便了复杂对象中数据字段获取(简而言之:用起来很爽!

在这里插入图片描述

2.1 用在数组上

let [a, b, c] = [1, 2, 3]; // a = 1,b = 2,c = 3 相当于重新定义了变量a,b,c,取值也更加方便 // , = 占位符 let arr = ["小明", "小花", "小鱼", "小猪"]; let [,,one] = arr; // 这里会取到小鱼 // 解构整个数组 let strArr = [...arr]; // 得到整个数组 console.log(strArr); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2.2 用在对象上

let obj = { className : "卡西诺", age: 18 } let {className} = obj; // 得到卡西诺 let {age} = obj; // 得到18 // 剩余运算符 let {a, b, ...demo} = {a: 1, b: 2, c: 3, d: 4}; // a = 1 // b = 2 // demo = {c: 3, d: 4} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

3. 模板字符串

  • 模板字符串相当于加强版的字符串,用反引号 ``
  • 除了作为普通字符串,还可以用来定义多行字符串,可以在字符串中加入变量和表达式

3.1 普通字符串

// 普通字符串 let string = "hello"+"小兄弟"; // hello小兄弟 // 如果想要换行 let string = "hello'\n'小兄弟" // hello // 小兄弟 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3.2 模板字符串

let str1 = "穿堂而过的"; let str2 = "风"; // 模板字符串 let newStr = `我是${str1}${str2}`; // 我是穿堂而过的风 console.log(newStr) // 字符串中调用方法 function fn3(){ return "帅的不行!"; } let string2= `我真是${fn3 ()}`; console.log(string2); // 我真是帅的不行! 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

4. ES6 函数(升级后更爽)

4.1 箭头函数

  • 箭头函数是一种更加简洁的函数书写方式
  • 箭头函数本身没有作用域(无this)
  • 箭头函数的this指向上一层,上下文决定其this
  • 基本语法:参数 => 函数体

a. 基本用法

let fn = v => v;
//等价于
let fn = function(num){
 return num;
}
fn(100);  // 输出100 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

b. 带参数的写法

let fn2 = (num1,num2) => {
 let result = num1 + num2;
 return result;
}
fn2(3,2);  // 输出5 
  • 1
  • 2
  • 3
  • 4
  • 5

c. 箭头函数中的this指向问题

  • 箭头函数体中的 this 对象,是定义函数时的对象,而不是使用函数时的对象。在函数定义的时候就已经决定了
function fn3(){
  setTimeout(()=>{
    // 定义时,this 绑定的是 fn3 中的 this 对象
    console.log(this.a);
  },0)
}
var a = 10;
// fn3 的 this 对象为 {a: 10},因为它指向全局: window.a
fn3.call({a: 18});  // 改变this指向,此时 a = 18 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

d. 箭头函数适用的场景

  • 当我们代码里存在这样的代码:let self = this;
  • 需要新建变量去保存this的时候
  • 案例如下:
let Person1 = {
    'age': 18,
    'sayHello': function () {
      setTimeout(()=>{
        console.log(this.age);
      });
    }
};
var age = 20;
Person1.sayHello();  // 18 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4.2 函数参数的扩展

1. 默认参数

// num为默认参数,如果不传,则默认为10 function fn(type, num=10){ console.log(type, num); } fn(1); // 打印 1,10 fn(1,2); // 打印 1,2 (此值会覆盖默认参数10) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 需要注意的是:只有在未传递参数,或者参数为 undefined 时,才会使用默认参数,null 值被认为是有效的值传递

2. 不定参数

// 此处的values是不定的,且无论你传多少个 function f(...values){ console.log(values.length); } f(1,2); // 2 f(1,2,3,4); // 4 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

5. Class类

  • class (类)作为对象的模板被引入,可以通过 class 关键字定义类
  • class 的本质是 function,同样可以看成一个块
  • 可以看作一个语法糖,让对象原型的写法更加清晰
  • 更加标准的面向对象编程语法

5.1 类的定义

// 匿名类 let Demo = class { constructor(a) { this.a = a; } } // 命名类 let Demo = class Demo { constructor(a) { this.a = a; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

5.2 类的声明

class Demo { constructor(a) { this.a = a; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 请注意,类不能重复声明
  • 类定义不会被提升,必须在访问前对类进行定义,否则就会报错。
  • 类中方法不需要 function 关键字。
  • 方法间不能加分号

5.3 类的主体

  • 公共属性(依然可以定义在原型上)
class Demo{} Demo.prototype.a = 2; 
  • 1
  • 2
  • 实例属性
class Demo { a = 2; constructor () { console.log(this.a); } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 方法:constructor
class Demo{ constructor(){ console.log('我是构造器'); } } new Demo(); // 我是构造器 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果不写constructor,也会默认添加

5.4 实例化对象

class Demo { constructor(a, b) { this.a = a; this.b = b; console.log('Demo'); } sum() { return this.a + this.b; } } let demo1 = new Demo(2, 1); let demo2 = new Demo(3, 1); // 两者原型链是相等的 console.log(demo1._proto_ == demo2._proto_); // true demo1._proto_.sub = function() { return this.a - this.b; } console.log(demo1.sub()); // 1 console.log(demo2.sub()); // 2 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

6. Map()

6.1 Maps 和 Objects 的区别

  • 一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值
  • Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是
  • Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算
    在这里插入图片描述

6.2 Map中的key

// 1. key是字符串 let myMap = new Map(); let keyString = "string"; myMap.set(keyString, "和键'string'关联的值"); // keyString === 'string' myMap.get(keyString); // "和键'string'关联的值" myMap.get("string"); // "和键'string'关联的值" // 2.key是对象 let myMap = new Map(); let keyObj = {}, myMap.set(keyObj, "和键 keyObj 关联的值"); myMap.get(keyObj); // "和键 keyObj 关联的值" myMap.get({}); // undefined, 因为 keyObj !== {} // 3. key也可以是函数或者NaN  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

6.3 Map 的迭代

// 1.使用 forEach let myMap = new Map(); myMap.set(0, "zero"); myMap.set(1, "one"); // 0 = zero , 1 = one myMap.forEach(function(value, key) { console.log(key + " = " + value); }, myMap) // 2. 也可以使用 for...of 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

6.4 Map 与 Array的转换

letkvArray = [["key1", "value1"], ["key2", "value2"]]; // Map 构造函数可以将一个 二维 键值对数组转换成一个 Map 对象 let myMap = new Map(kvArray); // 使用 Array.from 函数可以将一个 Map 对象转换成一个二维键值对数组 let outArray = Array.from(myMap); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

6.5 关于map的重点面试题

  • 请谈一下 Map和ForEach 的区别(问到map,必定问到此题)

详细解析:

  1. forEach()方法不会返回执行结果,而是undefined
  2. map()方法会得到一个新的数组并返回
  3. 同样的一组数组,map()的执行速度优于 forEach()(map() 底层做了深度优化

性质决定了两者应用场景的不同

  • forEach() 适合于你并不打算改变数据的时候,而只是想用数据做一些事情(比如存入数据库)
let arr = ['a', 'b', 'c', 'd']; arr.forEach((val) => { console.log(val); // 依次打印出 a,b,c,d }); 
  • 1
  • 2
  • 3
  • 4
  • map() 适用于你要改变数据值的时候,它更快,而且返回一个新的数组

let arr = [1, 2, 3, 4, 5]; let arr2 = arr.map(num => num * 2).filter(num => num > 5); // arr2 = [6, 8, 10]



蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

截屏2021-05-13 上午11.41.03.png


部分借鉴自:csdn  

分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


你们要的Echart系列,今天它来了,教你一招快速上手echarts的属性设置,手把手教程系列

前端达人

一、echarts简介

以前的百度echart(echarts.baidu.com),不过现在的ECharts 正在 Apache 开源基金会孵化中,因此域名(echarts.baidu.com)已不再使用,请访问 echarts.apache.org。

ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖矢量图形库 ZRender,提供直观,交互丰富,可高度个性化定制的数据可视化图表。

现在废话不多说,官网地址:https://echarts.apache.org/

二、echarts的下载、安装与使用

点击上面的网址就来到了echarts的官网了,最新版的Apache Echarts 是5.x的版本了。
官网大概就长下面的这个样子。
在这里插入图片描述
然后点击快速入门,我们先去把echarts安装一下,按下图所示进行操作。
在这里插入图片描述
作者的demo环境是用的vue-cli3的脚手架,将Echarts安装到项目里

运行命令:

npm install echarts --save
//or yarn add echarts  
  • 1
  • 2
  • 3

安装整个包到项目里
在这里插入图片描述
在项目里使用,先写个测试用例,看看是否安装成功了。

<template> <div id="charts-container" /> </template> <script> // 引入基本模板 import * as echarts from "echarts"; export default { name: "LineCharts", props: { options: { required: false, type: [Object], default: () => {}, }, }, data() { return { }; }, mounted() { this.init(); }, methods: { /**
         * 初始化charts
         */ init() { // 基于准备好的dom,初始化echarts实例 let myChart = echarts.init(document.getElementById('charts-container')); var option = { xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, yAxis: { type: 'value' }, series: [{ data: [120, 200, 150, 80, 70, 110, 130], type: 'bar', showBackground: true, backgroundStyle: { color: 'rgba(180, 180, 180, 0.2)' } }] }; myChart.setOption(option); } } }; </script> <style lang="scss" scoped> #charts-container { width: 100%; height: 410px; } </style>  
  • 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

我们使用了一个官网示例的代码,是最简单版本的Echart原型。

https://echarts.apache.org/examples/zh/editor.html?c=bar-background
测试图表

三、举个echarts的需求例子

举个栗子,假如我们拿到的UI的设计图如下,需要我们做一个柱状图,这个柱状图需要下面的这种样式(本文不做100%的还原,仅做常用属性的举例子)。
UI图例子
其实看到这里,可能觉得我们刚刚写到的测试Demo和UI的设计不一样。所以才有了我们怎么样将官网的简单Demo配置成UI图一致。

怎么快速完成这个UI图的还原呢?首先我们要做的是找到这个UI图所属的Echarts类,如下图中所示,找到“示例”,再找到“柱状图”。这样我们就可以在柱状图中再找到基础配置项。就是如Demo中的一样。
官网示例
接下来就应该进行下一步的配置了,在配置这些属性之前,你要先明白一点你的需求是啥。先看UI图里的柱状图哪些地方是需要修改的,目前的肉眼所见“网格的样式(需要改成虚线,全且颜色有变)、柱状图的颜色、需要有图例、X和Y轴的刻度线不一样”等等。
测试图表
下一章节快速记住配置项的属性。

四、echarts属性速记

首先我们记住这些属性,就要对这些属性进行一个分类。其实在官网中的《配置项手册》已经分类的很细了,但是由于Echarts的灵活度非常高,就导致了配置项手册的东西看起来就越来越多了,看久了就会导致“眼睛疲惫”。

废话不多说,直接开始,其实这些英文单次就对应的属性,稍微英文好点的就可以轻松点了,
按项目里常用的属性排序,如下:

一级属性(options.xxxx):

  • 网格设置 ----- grid
    变色的部分就是网格
 { grid: { borderColor: "rgba(222, 48, 48, 1)", show: true, backgroundColor: "rgba(188, 71, 71, 1)" } }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • X轴设置 ----- xAxis
    x横轴设置
{ xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], axisLabel: { //坐标文字 color: '#24253B', interval: 0 }, axisLine: { lineStyle: { //坐标轴颜色 color: '#C6C9FF' } }, axisTick: { //坐标轴刻度 inside: true, //朝内 lineStyle: { color: '#A3A8FF' } } } }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • Y轴设置 ----- yAxis
    y轴
 yAxis: { type: 'value', axisLine: { show: !false, lineStyle: { //坐标轴颜色 color: '#E6EAF9' } }, splitLine: { //网格设置 lineStyle: { color: '#DADCFF', type: 'dashed' } } },  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 系列设置(系列的数据) ----- series
    系列数据
    也不难理解,就是你需要设置哪种图表的数据样式,就在里面找到对应的type
  • 全局字体样式设置 ----- textStyle
    全局的文字
    这个也不难理解,设置的就是当前这个图表全局的字体样式,设置之后会覆盖默认的字体样式,这个也会有一个优先级别,就是 单独的子属性设置 > 全局样式 > 默认
{ textStyle:{ color:'#f00' //设置全局的字体为红色 } }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 图例设置 ----- legend
    这个位置就是图例
    图例就是对应的每项数据的标识符,让你知道某种颜色对应代表某种数据。
option = { color: ["#003366", "#006699", "#4cabce", "#e5323e"], //这个是四个图例的样色。 dataset: { source: [ ["type", "2012", "2013", "2014", "2015", "2016"], ["Forest", 320, 332, 301, 334, 390], ["Steppe", 220, 182, 191, 234, 290], ["Desert", 150, 232, 201, 154, 190], ["Wetland", 98, 77, 101, 99, 40] ] }, legend: { itemStyle: { color: "rgba(249, 0, 0, 1)" //这里的子属性设置会覆盖上面的设置 } }, xAxis: { type: "category", axisTick: { show: false } }, yAxis: {}, series: [{ type: "bar", seriesLayoutBy: "row" }, { type: "bar", seriesLayoutBy: "row" }, { type: "bar", seriesLayoutBy: "row" }, { type: "bar", seriesLayoutBy: "row" }] }  
  • 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
  • 标题设置 ----- title
    标题设置
    这里的标题可以分为主标题和副标题,可以使用show属性去控制显示隐藏。
{ title: { text: "Main Title", subtext: "Sub Title", left: "center", textStyle: { fontSize: 30, color: "rgba(225, 15, 15, 1)" }, subtextStyle: { fontSize: 20 } } }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 提示设置(鼠标悬浮到图上的交互样式)----- tooltip
    提示组件
    这个就是提示组件,一般情况下设置的就是鼠标悬浮到图表上面的样式。
  • 工具栏设置 ----- toolbox
    工具栏
    上图箭头所指区域就是工具栏了,功能就是配置图表的常用工具,例如下载、图表切换等等。

二级属性(options.xxxx.xxx)

  • 是否显示某个样式 ----- show(布尔类型)
    是否显示
    重点记住这个show就可以了,大部分一级属性都有这个属性,就是控制显示与隐藏的,需要就为true,不需要就为false。
  • 坐标轴网格设置----- splitLine(x轴和y轴都有的属性)
    坐标网格样式设置
    这个属性也不难理解,就是设置x或者y轴在网格中显示的样式,grid在全局就是所有的,这里设置就是针对每个坐标轴的详细设置。
 yAxis: [{ type: "value", splitLine: { //坐标的网格设置 lineStyle: { width: 5, type: "dashed", color: "rgba(244, 23, 23, 1)" } } }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 字体设置----- textStyle
    text属性
    这里可能有些误解了,子属性的textStyle样式一般是指在某个具体的熟悉里的字体样式设置了,同js设置字体样式的一样。
    设置举例
 yAxis: { type: "value", axisLabel: { //刻度标签文字设置 fontSize: 18, // color: "rgba(235, 33, 33, 1)" } }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 图形样式设置 ----- itemStyle
    样式举例
    这个属性的设置也是大部分属性设置都有的,可以理解为设置某个属性的几何属性。
 xAxis: { axisLine: { lineStyle: { //坐标轴轴线样式设置 color: "rgba(228, 13, 13, 1)", type: "dashed" } } }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 线的样式设置 ----- lineStyle
    视觉引导线
    这个属性主要就是这种这种视觉引导线的样式的。
series: [{ type: "pie", labelLine: { lineStyle: { //引导线的样式设置 color: "rgba(231, 16, 16, 1)", width: 2 }, length: 20 } }]  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 文本标签设置 ----- label
    label标签属性设置
    文中所标记部分就是为某个标签的属性设置,一般是指显示在图表数据中的文字。
 series: [{ name: "Sale", type: "bar", data: [5, 20, 36, 10, 10, 20, 4], label: { show: true, fontSize: 16, color: "rgba(65, 215, 35, 1)", fontStyle: "italic", borderWidth: 0 } }]  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 标签的视觉引导线设置 ----- labelLine
    这个属性前面写lineStyle的时候就已经提到过了。
  • 显示的位置设置 ----- (left、right、top、bottom)等,都是同定位属性一样
    位置设置
    这里不难看出我们将原来在顶部居中的图例移动到了左侧往下一点的位置,就是通过这个几个属性来控制的,大部分与数据无关的提示类都有这些属性,如:工具栏、标题、标签等。
  • 透明度设置 ----- opacity
    设置某个显示的透明度
    这也很好理解,就是想要哪个部分透明,就往哪里写。
legend: { itemStyle: { opacity: 0.1 } },  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 格式化设置 ----- formatter
    格式化显示

上面这些都是常用的一些属性设置,你学废了吗?

五、本文总结

其实通过上面的一个小节不难看出,Echarts的一些属性设置都是很有规律的,只要找到这些规律即可快速的上手Echarts了。这作为一个Echarts的系列的文章,主要目的是让学习Echart的朋友可以快速上手,会持续进行更新的。




蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

截屏2021-05-13 上午11.41.03.png


部分借鉴自:csdn  作者:狼丶宇先生

分享此文一切功德,皆悉回向给文章原作者及众读者.

免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


react全家桶从0搭建一个完整的react项目(react-router4、redux、redux-saga)

前端达人

react全家桶从0到1(最新)

本文从零开始,逐步讲解如何用react全家桶搭建一个完整的react项目。文中针对react、webpack、babel、react-route、redux、redux-saga的核心配置会加以讲解,通过这个项目,可以系统的了解react技术栈的主要知识,避免搭建一次后面就忘记的情况。

代码库:https://github.com/teapot-py/react-demo

首先关于主要的npm包版本列一下:

  1. react@16.7.0
  2. webpack@4.28.4
  3. babel@7+
  4. react-router@4.3.1
  5. redux@4+

从webpack开始

思考一下webpack到底做了什么事情?其实简单来说,就是从入口文件开始,不断寻找依赖,同时为了解析各种不同的文件加载相应的loader,最后生成我们希望的类型的目标文件。

这个过程就像是在一个迷宫里寻宝,我们从入口进入,同时我们也会不断的接收到下一处宝藏的提示信息,我们对信息进行解码,而解码的时候可能需要一些工具,比如说钥匙,而loader就像是这样的钥匙,然后得到我们可以识别的内容。

回到我们的项目,首先进行项目的初始化,分别执行如下命令

mkdir react-demo // 新建项目文件夹
cd react-demo // cd到项目目录下
npm init // npm初始化 
  • 1
  • 2
  • 3

引入webpack

npm i webpack --save
touch webpack.config.js 
  • 1
  • 2

对webpack进行简单配置,更新webpack.config.js

const path = require('path');

module.exports = {
  entry: './app.js', // 入口文件
  output: {
    path: path.resolve(__dirname, 'dist'), // 定义输出目录
    filename: 'my-first-webpack.bundle.js'  // 定义输出文件名称
  }
}; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

更新package.json文件,在scripts中添加webpack执行命令

"scripts": {
  "dev": "./node_modules/.bin/webpack --config webpack.config.js"
} 
  • 1
  • 2
  • 3

如果有报错请按提示安装webpack-cli

npm i webpack-cli 
  • 1

执行webpack

npm run dev 
  • 1

如果在项目文件夹下生成了dist文件,说明我们的配置是没有问题的。

接入react

安装react相关包

npm install react react-dom --save 
  • 1

更新app.js入口文件

import React from 'react
import ReactDom from 'react-dom';
import App from './src/views/App';

ReactDom.render(<App />, document.getElementById('root')); 
  • 1
  • 2
  • 3
  • 4
  • 5

创建目录 src/views/App,在App目录下,新建index.js文件作为App组件,index.js文件内容如下:

import React from 'react';

class App extends React.Component {

    constructor(props) {
        super(props);
    }

    render() {
        return (<div>App Container</div>);
    }
}
export default App; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在根目录下创建模板文件index.html

<!DOCTYPE html>
<html>
<head>
    <title>index</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
</head>
<body>
    <div id="root"></div>
</body>
</html> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

到了这一步其实关于react的引入就OK了,不过目前还有很多问题没有解决

  1. 如何解析JS文件的代码?
  2. 如何将js文件加入模板文件中?

Babel解析js文件

Babel是一个工具链,主要用于在旧的浏览器或环境中将ECMAScript2015+的代码转换为向后兼容版本的JavaScript代码。

安装babel-loader,@babel/core,@babel/preset-env,@babel/preset-react

npm i babel-loader@8 @babel/core @babel/preset-env @babel/preset-react -D 
  • 1
  1. babel-loader:使用Babel转换JavaScript依赖关系的Webpack加载器, 简单来讲就是webpack和babel中间层,允许webpack在遇到js文件时用bable来解析
  2. @babel/core:即babel-core,将ES6代码转换为ES5。7.0之后,包名升级为@babel/core。@babel相当于一种官方标记,和以前大家随便起名形成区别。
  3. @babel/preset-env:即babel-preset-env,根据您要支持的浏览器,决定使用哪些transformations / plugins 和 polyfills,例如为旧浏览器提供现代浏览器的新特性。
  4. @babel/preset-react:即 babel-preset-react,针对所有React插件的Babel预设,例如将JSX转换为函数.

更新webpack.config.js

 module: {
    rules: [
      {
        test: /\.js$/, // 匹配.js文件
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      }
    ]
  } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

根目录下创建并配置.babelrc文件

{
  "presets": ["@babel/preset-env", "@babel/preset-react"]
} 
  • 1
  • 2
  • 3

配置HtmlWebPackPlugin

这个插件最主要的作用是将js代码通过

npm i html-webpack-plugin -D 
  • 1

webpack新增HtmlWebPackPlugin配置

至此,我们看一下webpack.config.js文件的完整结构

const path = require('path');

const HtmlWebPackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './app.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  },
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      }
    ]
  },
  plugins: [
    new HtmlWebPackPlugin({
      template: './index.html',
      filename: path.resolve(__dirname, 'dist/index.html')
    })
  ]
}; 
  • 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

执行 npm run start,生成 dist文件夹

当前目录结构如下
目录结构

可以看到在dist文件加下生成了index.html文件,我们在浏览器中打开文件即可看到App组件内容。

配置 webpack-dev-server

webpack-dev-server可以极大的提高我们的开发效率,通过监听文件变化,自动更新页面

安装 webpack-dev-server 作为 dev 依赖项

npm i webpack-dev-server -D 
  • 1

更新package.json的启动脚本

“dev": "webpack-dev-server --config webpack.config.js --open" 
  • 1

webpack.config.js新增devServer配置

devServer: {
  hot: true, // 热替换
  contentBase: path.join(__dirname, 'dist'), // server文件的根目录
  compress: true, // 开启gzip
  port: 8080, // 端口
},
plugins: [
  new webpack.HotModuleReplacementPlugin(), // HMR允许在运行时更新各种模块,而无需进行完全刷新
  new HtmlWebPackPlugin({
    template: './index.html',
    filename: path.resolve(__dirname, 'dist/index.html')
  })
] 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

引入redux

redux是用于前端数据管理的包,避免因项目过大前端数据无法管理的问题,同时通过单项数据流管理前端的数据状态。

创建多个目录

  1. 新建src/actions目录,用于创建action函数
  2. 新建src/reducers目录,用于创建reducers
  3. 新建src/store目录,用于创建store

下面我们来通过redux实现一个计数器的功能

安装依赖

npm i redux react-redux -D 
  • 1

在actions文件夹下创建index.js文件

export const increment = () => {
  return {
    type: 'INCREMENT',
  };
}; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在reducers文件夹下创建index.js文件

const initialState = {
  number: 0
};

const incrementReducer = (state = initialState, action) => {
  switch(action.type) {
    case 'INCREMENT': {
      state.number += 1
      return { ...state }
      break
    };
    default: return state;
  }
};
export default incrementReducer; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

更新store.js

import { createStore } from 'redux';
import incrementReducer from './reducers/index';

const store = createStore(incrementReducer);

export default store; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

更新入口文件app.js

import App from './src/views/App';
import ReactDom from 'react-dom';
import React from 'react';
import store from './src/store';
import { Provider } from 'react-redux';

ReactDom.render(
    <Provider store={store}>
        <App />
    </Provider>
, document.getElementById('root')); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

更新App组件

import React from 'react';
import { connect } from 'react-redux';
import { increment } from '../../actions/index';

class App extends React.Component {

    constructor(props) {
        super(props);
    }

    onClick() {
        this.props.dispatch(increment())
    }

    render() {
        return (
            <div>
                <div>current number: {this.props.number} <button onClick={()=>this.onClick()}>点击+1</button></div>

            </div>
        );
    }
}
export default connect(
    state => ({
        number: state.number
    })
)(App); 
  • 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

点击旁边的数字会不断地+1

引入redux-saga

redux-saga通过监听action来执行有副作用的task,以保持action的简洁性。引入了sagas的机制和generator的特性,让redux-saga非常方便地处理复杂异步问题。
redux-saga的原理其实说起来也很简单,通过劫持异步action,在redux-saga中进行异步操作,异步结束后将结果传给另外的action。

下面就接着我们计数器的例子,来实现一个异步的+1操作。

安装依赖包

npm i redux-saga -D 
  • 1

新建src/sagas/index.js文件

import { delay } from 'redux-saga'
import { put, takeEvery } from 'redux-saga/effects'

export function* incrementAsync() {
  yield delay(2000)
  yield put({ type: 'INCREMENT' })
}

export function* watchIncrementAsync() {
  yield takeEvery('INCREMENT_ASYNC', incrementAsync)
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

解释下所做的事情,将watchIncrementAsync理解为一个saga,在这个saga中监听了名为INCREMENT_ASYNC的action,当INCREMENT_ASYNC被dispatch时,会调用incrementAsync方法,在该方法中做了异步操作,然后将结果传给名为INCREMENT的action进而更新store。

更新store.js

在store中加入redux-saga中间件

import { createStore, applyMiddleware } from 'redux';
import incrementReducer from './reducers/index';
import createSagaMiddleware from 'redux-saga'
import { watchIncrementAsync } from './sagas/index'

const sagaMiddleware = createSagaMiddleware()
const store = createStore(incrementReducer, applyMiddleware(sagaMiddleware));
sagaMiddleware.run(watchIncrementAsync)
export default store; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

更新App组件

在页面中新增异步提交按钮,观察异步结果

import React from 'react';
import { connect } from 'react-redux';
import { increment } from '../../actions/index';

class App extends React.Component {

    constructor(props) {
        super(props);
    }

    onClick() {
        this.props.dispatch(increment())
    }

    onClick2() {
        this.props.dispatch({ type: 'INCREMENT_ASYNC' })
    }

    render() {
        return (
            <div>
                <div>current number: {this.props.number} <button onClick={()=>this.onClick()}>点击+1</button></div>
                <div>current number: {this.props.number} <button onClick={()=>this.onClick2()}>点击2秒后+1</button></div>
            </div>
        );
    }
}
export default connect(
    state => ({
        number: state.number
    })
)(App); 
  • 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

观察结果我们会发现如下报错:

这是因为在redux-saga中用到了Generator函数,以我们目前的babel配置来说并不支持解析generator,需要安装@babel/plugin-transform-runtime

npm install --save-dev @babel/plugin-transform-runtime 
  • 1

这里关于babel-polyfill、和transfor-runtime做进一步解释

babel-polyfill

Babel默认只转换新的JavaScript语法,而不转换新的API。例如,Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转译。如果想使用这些新的对象和方法,必须使用 babel-polyfill,为当前环境提供一个垫片。

babel-runtime

Babel转译后的代码要实现源代码同样的功能需要借助一些帮助函数,而这些帮助函数可能会重复出现在一些模块里,导致编译后的代码体积变大。
Babel 为了解决这个问题,提供了单独的包babel-runtime供编译模块复用工具函数。
在没有使用babel-runtime之前,库和工具包一般不会直接引入 polyfill。否则像Promise这样的全局对象会污染全局命名空间,这就要求库的使用者自己提供 polyfill。这些 polyfill一般在库和工具的使用说明中会提到,比如很多库都会有要求提供 es5的polyfill。
在使用babel-runtime后,库和工具只要在 package.json中增加依赖babel-runtime,交给babel-runtime去引入 polyfill 就行了;
详细解释可以参考

babel presets 和 plugins的区别

Babel插件一般尽可能拆成小的力度,开发者可以按需引进。比如对ES6转ES5的功能,Babel官方拆成了20+个插件。
这样的好处显而易见,既提高了性能,也提高了扩展性。比如开发者想要体验ES6的箭头函数特性,那他只需要引入transform-es2015-arrow-functions插件就可以,而不是加载ES6全家桶。
但很多时候,逐个插件引入的效率比较低下。比如在项目开发中,开发者想要将所有ES6的代码转成ES5,插件逐个引入的方式令人抓狂,不单费力,而且容易出错。
这个时候,可以采用Babel Preset。
可以简单的把Babel Preset视为Babel Plugin的集合。比如babel-preset-es2015就包含了所有跟ES6转换有关的插件。

更新.babelrc文件配置,支持genrator

{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": false,
        "helpers": true,
        "regenerator": true,
        "useESModules": false
      }
    ]
  ]
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14


点击按钮会在2秒后执行+1操作。

引入react-router

在web应用开发中,路由系统是不可或缺的一部分。在浏览器当前的URL发生变化时,路由系统会做出一些响应,用来保证用户界面与URL的同步。随着单页应用时代的到来,为之服务的前端路由系统也相继出现了。而react-route则是与react相匹配的前端路由。

引入react-router-dom

npm install --save react-router-dom -D 
  • 1

更新app.js入口文件增加路由匹配规则

import App from './src/views/App';
import ReactDom from 'react-dom';
import React from 'react';
import store from './src/store';
import { Provider } from 'react-redux';
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";

const About = () => <h2>页面一</h2>;
const Users = () => <h2>页面二</h2>;

ReactDom.render(
    <Provider store={store}>
        <Router>
            <Switch>
                <Route path="/" exact component={App} />
                <Route path="/about/" component={About} />
                <Route path="/users/" component={Users} />
            </Switch>
        </Router>
    </Provider>
, document.getElementById('root')); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

更新App组件,展示路由效果

import React from 'react';
import { connect } from 'react-redux';
import { increment } from '../../actions/index';
import { Link } from "react-router-dom";

class App extends React.Component {

    constructor(props) {
        super(props);
    }

    onClick() {
        this.props.dispatch(increment())
    }

    onClick2() {
        this.props.dispatch({ type: 'INCREMENT_ASYNC' })
    }

    render() {
        return (
            <div>
                <div>react-router 测试</div>
                <nav>
                    <ul>
                    <li>
                        <Link to="/about/">页面一</Link>
                    </li>
                    <li>
                        <Link to="/users/">页面二</Link>
                    </li>
                    </ul>
                </nav>

                <br/>
                <div>redux & redux-saga测试</div>
                <div>current number: {this.props.number} <button onClick={()=>this.onClick()}>点击+1</button></div>
                <div>current number: {this.props.number} <button onClick={()=>this.onClick2()}>点击2秒后+1</button></div>
            </div>
        );
    }
}
export default connect(
    state => ({
        number: state.number
    })
)(App); 
  • 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


点击列表可以跳转相关路由

总结

至此,我们已经一步步的,完成了一个简单但是功能齐全的react项目的搭建,下面回顾一下我们做的工作

  1. 引入webpack
  2. 引入react
  3. 引入babel解析react
  4. 接入webpack-dev-server提高前端开发效率
  5. 引入redux实现一个increment功能
  6. 引入redux-saga实现异步处理
  7. 引入react-router实现前端路由

麻雀虽小,五脏俱全,希望通过最简单的代码快速的理解react工具链。其实这个小项目中还是很多不完善的地方,比如说样式的解析、Eslint检查、生产环境配置,虽然这几项是一个完整项目不可缺少的部分,但是就demo项目来说,对我们理解react工具链可能会有些干扰,所以就不在项目中加了。

后面会新建一个分支,把这些完整的功能都加上,同时也会对当前的目录结构进行优化。



蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

截屏2021-05-13 上午11.41.03.png


部分借鉴自:csdn  作者:郑清

原文链接:

分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

前端开发框架与方案总结——蓝蓝设计

前端达人

在与客户的沟通中,聆听了许多建议,学习到了很多知识,也收到过赞美与批评,在经过千锤百炼过后  总结了一点点经验

首先:



框架选择

    网站css框架选择(简洁,节约成本,快速开发)

    对于一些简单静态网站,展示类网站项目,达到快速开发建站,而又节约成本人力的情况下 选择一些用于css库的框架最为合适,


1.Bootstrap

        Bootstrap 是最受欢迎的 HTML、CSS 和 JS 框架,用于开发响应式布局、移动设备优先的 WEB 项目。

        预处理工具  虽然可以直接使用 Bootstrap 提供的 CSS 样式表,但是不要忘记,Bootstrap 的源码是采用最流行的 CSS 预处理工具

        一个框架、多种设备。 你的网站和应用能在 Bootstrap 的帮助下通过同一份源码快速、有效地适配手机、平板和 PC 设备,这一切都是 CSS 媒体 查询(Media Query)的功劳。

功能完备  Bootstrap 提供了全面、美观的文档,你能在这里找到关于普通 HTML 元素、HTML 和 CSS 组件以及 jQuery 插件方面的所有详细文档。

Bootstrap 是最受欢迎的 CSS 框架,被认为是拥有最好的响应性的CSS框架。专为前端开发而设计,有助于构建web设计理念、移动优先项目、网格系统、排版和按钮等。


iShot2021-05-31 10.55.29.png


2.layui

开源模块化前端 UI 框架

开源模块化前端 UI 框架

      由职业前端倾情打造,面向全层次的前后端开发者,易上手开箱即用的 Web UI 组件库

Layui 是一款采用自身模块规范编写的情怀型前端UI框架,遵循原生HTML/CSS/JS的书写与组织形式,门槛极低,拿来即用。其外在极简,却又不失饱满的内在,体积轻盈,组件丰盈,从核心代码到API的每一处细节都经过精心雕琢,非常适合界面的快速开发。


iShot2021-05-31 14.50.44.png


   3.Semantic-UI


Semantic 是一个开发框架,可以使用人性化的 HTML 帮助创建漂亮的响应式布局。Semantic UI 旨在使网站构建过程更加语义化。核心特征是利用自然语言原理使代码更易于阅读,更容易理解。

iShot2021-05-31 18.36.54.png

4.Pure

Pure 非常轻量级,经过压缩后不过 3.8KB。这是一个特别为移动端考虑的框架,为了压缩大小,每一行代码都经过仔细考量。当然如果你不使用框架给出的全部模块,体量还可以更小。

iShot2021-05-31 18.37.30.png

5.Skeleton

Skeleton 如其名字,非常小巧,设计简约,麻雀虽小五脏俱全。网格系统,文本,表单,按钮,列表,表格,媒体查询等功能面面俱到。非常适合快速创建简约网站的需求。


iShot2021-05-31 18.38.17.png


快速搭建

为客户节省时间成本, 并满足客户快速建站的需求,开发过程中 使用到css模块化,html也应简洁实用。

手写源生 CSS

在我们最初学习写页面的时候,大家都学过怎么去写 css,也就以下几种情况:

  • 行内样式,即直接在 html 中的 style 属性里编写 css 代码。
  • 内嵌样式,即在 html h 中的 style 标签内编写 class,提供给当前页面使用。
  • 导入样式,即在内联样式中 通过 @import 方法,导入其他样式,提供给当前页面使用。
  • 外部样式,即使用 html 中的 link 标签,加载样式,提供给当前页面使用。

我们在不断摸索中,逐渐形成了以编写内嵌样式和外部样式为主要的编写习惯。

读到这里大家肯定有所疑问,为什么不建议使用行内样式?

使用行内样式的缺点
  • 样式不能复用。
  • 样式权重太高,样式不好覆盖。
  • 表现层与结构层没有分离。
  • 不能进行缓存,影响加载效率。

然后我们继续剖析一下,为什么不建议使用导入样式?

经测试,在 css 中使用 @import 会有以下两种情况:

1、在 IE6-8 下,@import 声明指向的样式表并不会与页面其他资源并发加载,而是等页面所有资源加载完成后才开始下载。

2、如果在 link 标签中去 @import 其他 css,页面会等到所有资源加载完成后,才开始解析 link 标签中 @import 的 css。

使用导入样式的缺点 - 导入样式,只能放在 style 标签的第一行,放其他行则会无效。 - @import 声明的样式表不能充分利用浏览器并发请求资源的行为,其加载行为往往会延后触发或被其他资源加载挂起。 - 由于 @import 样式表的延后加载,可能会导致页面样式闪烁。

使用预处理器 Sass/Less

随着时间的不断发展,我们逐渐发现,编写源生的 css 其实并不友好,例如:源生的 css 不支持变量,不支持嵌套,不支持父选择器等等,这些种种问题,催生出了像 sass/less 这样的预处理器。

预处理器主要是强化了 css 的语法,弥补了上文说了这些问题,但本质上,打包出来的结果和源生的 css 都是一样的,只是对开发者友好,写起来更顺滑。

后处理器 PostCSS

随着前端工程化的不断发展,越来越多的工具被前端大佬们开发出来,愿景是把所有的重复性的工作都交给机器去做,在 css 领域就产生了 postcss。

postcss 可以称作为 css 界的 babel,它的实现原理是通过 ast 去分析我们的 css 代码,然后将分析的结果进行处理,从而衍生出了许多种处理 css 的使用场景。

常用的 postcss 使用场景有:

  • 配合 stylelint 校验 css 语法
  • 自动增加浏览器前缀 autoprefixer
  • 编译 css next 的语法

更多 postcss 使用场景

CSS 模块化迅速发展

随着 react、vue 等基于模块化的框架的普及使用,我们编写源生 css 的机会也越来越少。我们常常将页面拆分成许多个小组件,然后像搭积木一样将多个小组件组成最终呈现的页面。

但是我们知道,css 是根据类名去匹配元素的,如果有两个组件使用了一个相同的类名,后者就会把前者的样式给覆盖掉,看来解决样式命名的冲突是个大问题。

为了解决这个问题,产生出了 CSS 模块化的概念。

CSS 模块化定义

  • 你是否为 class 命名而感到苦恼?
  • 你是否有怕跟别人使用同样 class 名而感到担忧?
  • 你是否因层级结构不清晰而感到烦躁?
  • 你是否因代码难以复用而感到不爽?
  • 你是否因为 common.css 的庞大而感到恐惧?

你如果遇到如上问题,那么就很有必要使用 css 模块化。

CSS 模块化的实现方式

BEM 命名规范

BEM 的意思就是块(block)、元素(element)、修饰符(modifier)。是由 Yandex 团队提出的一种前端命名方法论。这种巧妙的命名方法让你的 css 类对其他开发者来说更加透明而且更有意义。

BEM 的命名规范如下:

/* 块即是通常所说的 Web 应用开发中的组件或模块。每个块在逻辑上和功能上都是相互独立的。 */ .block { } /* 元素是块中的组成部分。元素不能离开块来使用。BEM 不推荐在元素中嵌套其他元素。 */ .block__element { } /* 修饰符用来定义块或元素的外观和行为。同样的块在应用不同的修饰符之后,会有不同的外观 */ .block--modifier { }

通过 bem 的命名方式,可以让我们的 css 代码层次结构清晰,通过严格的命名也可以解决命名冲突的问题,但也不能完全避免,毕竟只是一个命名约束,不按规范写照样能运行。

CSS Modules

CSS Modules 指的是我们像 import js 一样去引入我们的 css 代码,代码中的每一个类名都是引入对象的一个属性,通过这种方式,即可在使用时明确指定所引用的 css 样式。

并且 CSS Modules 在打包的时候会自动将类名转换成 hash 值,完全杜绝 css 类名冲突的问题。

使用方式如下:

1、定义 css 文件。

.className { color: green; } /* 编写全局样式 */ :global(.className) { color: red; } /* 样式复用 */ .otherClassName { composes: className; color: yellow; } .otherClassName { composes: className from "./style.css"; }

2、在 js 模块中导入 css 文件。

import styles from "./style.css"; element.innerHTML = '<div class="' + styles.className + '">'; 

3、配置 css-loader 打包。

CSS Modules 不能直接使用,而是需要进行打包,一般通过配置 css-loader 中的 modules 属性即可完成 css modules 的配置。

// webpack.config.js module.exports = { module: { rules: [ { test: /\.css$/, use:{ loader: 'css-loader', options: { modules: { // 自定义 hash 名称  localIdentName: '[path][name]__[local]--[hash:base64:5]', } } } ] } }; 

4、最终打包出来的 css 类名就是由一长串 hash 值生成。

._2DHwuiHWMnKTOYG45T0x34 { color: red; } ._10B-buq6_BEOTOl9urIjf8 { background-color: blue; }

CSS In JS

CSS in JS,意思就是使用 js 语言写 css,完全不需要些单独的 css 文件,所有的 css 代码全部放在组件内部,以实现 css 的模块化。

CSS in JS 其实是一种编写思想,目前已经有超过 40 多种方案的实现,最出名的是 styled-components。

使用方式如下:

import React from "react"; import styled from "styled-components"; // 创建一个带样式的 h1 标签 const Title = styled.h1`  font-size: 1.5em;  text-align: center;  color: palevioletred; `; // 创建一个带样式的 section 标签 const Wrapper = styled.section`  padding: 4em;  background: papayawhip; `; // 通过属性动态定义样式 const Button = styled.button`  background: ${props => (props.primary ? "palevioletred" : "white")};  color: ${props => (props.primary ? "white" : "palevioletred")};   font-size: 1em;  margin: 1em;  padding: 0.25em 1em;  border: 2px solid palevioletred;  border-radius: 3px; `; // 样式复用 const TomatoButton = styled(Button)`  color: tomato;  border-color: tomato; `; <Wrapper> <Title>Hello World, this is my first styled component!</Title> <Button primary>Primary</Button> </Wrapper>; 

可以看到,我们直接在 js 中编写 css,案例中在定义源生 html 时就创建好了样式,在使用的时候就可以渲染出带样式的组件了。

除此之外,还有其他比较出名的库:

  • emotion
  • radium
  • glamorous

总结

最后放一张总结好的图。




v2-0c8a8007eae08838730306aa8e03c677_1440w.jpg


下一篇我们讲一下主流js框架 与js开发


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

截屏2021-05-13 上午11.41.03.png


部分借鉴自:知乎 作者:孟思行

原文链接:

分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


Bootstrap 是最受欢迎的 HTML、CSS 和 JS 框架,用于开发响应式布局、移动设备优先的 WEB 项目。

Bootstrap 是最受欢迎的 HTML、CSS 和 JS 框架,用于开发响应式布局、移动设备优先的 WEB 项目。

Bootstrap 是最受欢迎的 HTML、CSS 和 JS 框架,用于开发响应式布局、移动设备优先的 WEB 项目。

从零开始部署到上线:手把手教你搭建属于自己的个人博客网站!

前端达人

现在是互联网逐渐发展,已经出现了很多可以供自己写博客的网站,大家可以在上面 发表自己的文章,供自己记录或者是供他人阅读。但是,可不可以自己搭建一个只属于自己的个人博客网站呢?这篇文章就带你从0开始搭建一个自己的个人博客网站,并部署到属于自己服务器。这里有一点要说的是,没有服务器的同学使用自己机器的linux系统也是一样的操作。我们选用一个很好用的博客框架Hexo进行搭建我们的个人博客。

博客框架Hexo介绍:


Hexo是一个快速,简介而且高效的博客框架,Hexo 使用Markdown(或其他渲染引擎)解析文章,在几秒内,即可生成一个静态网页展示我们发布的文章,同时也提供了大量精美的博客主题供我们使用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BUkzFJqh-1622032930743)(pictures/image-20210524011732509.png)]

Hexo博客框架的优点


  • 速度极快:Node.js 所带来的超快生成速度,让上百个页面在几秒内瞬间完成渲染。
  • 支持MarkDown:Hexo 支持 GitHub Flavored Markdown 的所有功能,甚至可以整合 Octopress 的大多数插件。
  • 一键部署:只需一条指令即可部署到 GitHub Pages, Heroku 或其他平台。
  • 插件和可扩展性:这个也是hexo很强大的一个地方,强大的 API 带来无限的可能,与数种模板引擎(EJS,Pug,Nunjucks)和工具(Babel,PostCSS,Less/Sass)轻易集成

Hexo博客框架搭建:


我们使用Centos7系统作为演示,使用其他linux系统也是可以的,只需要更换为对应Linux版本的软件安装命令即可。

1.安装Git

直接使用yum安装即可,在命令行输入 yum -y install git

完成之后输入git version 查看是否安装成功,如果显示git版本信息即为成功,如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gVJMnq6W-1622032930745)(pictures/image-20210526142911469.png)]

2.安装Node.js

Node.js是一种运行在服务端的JavaScript,是一个基于Chrome JavaScript运行时建立的一个平台。

Hexo基于Node.js,所以安装Node.js是必须的一个操作,安装步骤如下:

2.1:下载安装包:

wget https://nodejs.org/dist/v12.13.1/node-v12.13.1-linux-x64.tar.xz  
  • 1

2.2:解压缩软件包并配置环境变量:

#解压 tar -xvJf node-v6.10.1-linux-x64.tar.xz #移动到/usl/lcoal目录下 mv node-v6.10.1-linux-x64 /usr/local/node-v6 #创建软链接 ln -s /usr/local/node-v6/bin/node /bin/node ln -s /usr/local/node-v6/bin/npm /bin/npm #添加环境变量 echo 'export PATH=/usr/local/node-v6/bin:$PATH' >> /etc/profile source /etc/profile #让环境变量生效  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

2.3:测试是否安装成功:

在命令行输入node -v 和 npm -v,若是显示出了版本号,即为安装成功:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-47pt856h-1622032930748)(pictures/image-20210526143600103.png)]

3.安装并使用Hexo

Hexo的安装较为简单,使用如下命令安装

npm install -g hexo-cli #这里有一点要注意的就是,npm的源是在国外的,访问可能会很慢,这里可以换成我们国内的源进行安装加快速度。操作如下: npm config set registry https://registry.npm.taobao.org  
  • 1
  • 2
  • 3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TEjeb2E6-1622032930750)(pictures/image-20210526143826327.png)]

3.1:初始化Hexo

上面的安装完成之后执行下面的命令进行对Hexo进行一个初始化

#这个文件名字可以自己指定,之后会在当前目录下生成对应文件夹 hexo init <文件名字> cd 文件名字 npm install  
  • 1
  • 2
  • 3
  • 4

可以看到安装好之后的一个目录结构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-raE9WJQX-1622032930751)(pictures/image-20210526144057199.png)]

目录文件说明:

_config.yml:网站的配置信息,您可以在此配置大部分的参数。

package.json:应用程序的信息。EJSStylus 和 Markdown renderer 已默认安装,您可以自由移除。

scaffolds:模版文件夹。当您新建文章时Hexo 会根据 scaffold 来建立文件Hexo的模板是指在新建的文章文件中默认填充的内容。例如,如果您修改scaffold/post.md中的Front-matter内容,那么每次新建一篇文章时都会包含这个修改。

source:资源文件夹是存放用户资源的地方。除 _posts 文件夹之外,开头命名为 _ (下划线)的文件 / 文件夹和隐藏的文件将会被忽略。Markdown 和 HTML 文件会被解析并放到 public 文件夹,而其他文件会被拷贝过去。

themes:主题 文件夹。Hexo 会根据主题来生成静态页面。

查看hexo的版本以及对应的数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1B3aWxn9-1622032930752)(pictures/image-20210526144143747.png)]

3.2生成静态文件,并开启Hexo服务:

进入到了hexo的安装目录之后,使用hexo generate来生成静态文件,也可以使用hexo g,之后使用hexo server(可以写成hexo s)命令启动服务,操作如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YuvIWOuI-1622032930753)(pictures/image-20210526144957135.png)]

可以看到4000端口的服务已经开启,之后在你的浏览器输入http://<你的linux机器的ip地址或者服务器公网地址>:4000,如下可以看到最开始的一个界面:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w9ELcFFg-1622032930753)(pictures/image-20210526145217729.png)]

4.初步使用Hexo:


使用前,我们对我们的站点进行一个配置,也就是我们创建的hexo目录的_config.yml文件,可以修改的部分介绍如下:

# Site
title: QIMING.INFO #博客网站的标题
subtitle:          #博客网站的副标题
description:       #你的网站描述
keywords:          #网站的关键词  
author:            #作者的名字
language:          #博客网站使用的语言
timezone:          #网站时区  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

我自己的修改如下供大家参考,这里的修改没有太大的限制:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G0cTYgQ1-1622032930754)(pictures/image-20210526145734893.png)]

4.1:开始使用Hexo发布自己的第一篇博客!

执行下面的目录创建一篇新文章:

hexo new post <文章标题>  
  • 1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Tz5aBlT-1622032930755)(pictures/image-20210526145922392.png)]

这里我创建了一篇标题为First_Blog的博客,创建之后hexo目录下面的source/_post文件夹下会产生一个First_Blog.md的文件

4.2:编辑文章

进入到上面说的那个目录下可以看到我们创建的博客文件:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cuPREJLQ-1622032930756)(pictures/image-20210526150208204.png)]

直接使用vim或者vi就可以对我们的博客文章进行编辑了,打开此First_Blog.md后可以看到—分隔的区域,这部分主要对文章进行标注变量,如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GOYKjBSu-1622032930756)(pictures/image-20210526150326264.png)]

title:标题

tage:标签

categories:分类

date:时间

这些标注大家在-----区域可以进行使用

4.3:发布文章

输入如下命令,生成静态网页,静态网页会存放在public文件下

hexo  g
hexo s  
  • 1
  • 2

之后就可以去浏览器访问了!可以看到我们发布的文章已经成功在浏览器显示,到这里个人博客网站就已经成功搭建了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2ZpSg9fl-1622032930757)(pictures/image-20210526150824449.png)]

5.主题的选择:

主题网站:https://hexo.io/themes/ hexo提供了大量精美的主题供我们选择,选择喜欢的主题,在hexo目录下的themes文件夹下使用git clone下载主题,之后再配置文件_config.yml把theme后面修改成下载的主题的名字,之后运行hexo clean ,hexo g即可看到生效的主题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eN5cZDmN-1622032930757)(pictures/image-20210526161641366.png)]


将Hexo部署上线到服务器:


如果是有服务器的小伙伴,也可以将Hexo部署到服务器供全网访问,服务器的购买这里就不多说,阿里云跟腾讯云上面对于学生也有较为优惠的价格。部署到服务器的话,就需要将上面的全部操作,在你的服务器系统上面执行,之后我们使用Nginx(反向代理服务器)进行部署。

Nginx安装:

Nginx是一款高性能的 HTTP 和反向代理服务器,这里我们采用编译安装的方式,按照下面的指引依次执行命令

#安装gcc编译环境: yum install -y gcc-c++ #安装zlib-devel库: yum install -y zlib-devel #安装OpenSSL密码库: yum install -y openssl openssl-devel #安装pcre正则表达式库:编译nginx,需要需要指定pcre的路径,这里我们选择安装稳定版本的。 下载地址:https://ftp.pcre.org/pub/pcre/ #选择对应的版本下载下来之后上传到我们的服务器,也可以使用wget直接下载 tar -xf pcre-8.43.tar.gz cd pcre-8.43 mkdir -p /usr/local/pcre
./configure --prefix=/usr/local/pcre make && make install  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

下载编译安装nginx:

nginx下载官网:http://nginx.org/en/download.html wget http://nginx.org/download/nginx-1.16.0.tar.gz mkdir -p /usr/local/nginx tar -xf nginx-1.16.0.tar.gz #编译指定安装路径需要进入nginx cd nginx-1.16.0
./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module --with-pcre #http_ssl_module  这是支持https的一个模块,就是可以使用https://这样去访问。 make && make install #编译安装  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

启动nginx服务:

#启动: /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf #用指定配置文件的方式启动  -c #测试: /usr/local/nginx/sbin/nginx -t #这个用于测试nginx的语法是否有问题 显示is successful即为成功。 #关闭: /usr/local/nginx/sbin/nginx -s stop #继续输入以下命令使Nginx开机自动启动: systemctl enable nginx #配置文件的位置:/usr/local/nginx/conf  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

之后我们需要配置服务器公网ip,编辑配置文件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TOR7RVwA-1622032930758)(pictures/image-20210526174027780.png)]

之后再重启nginx服务,开启hexo服务,这个时候使用公网的ip就可以访问到我们的hexo服务了!




蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

截屏2021-05-13 上午11.41.03.png


文章来源:csdn    作者:YO哥教你大数据

分享此文一切功德,皆悉回向给文章原作者及众读者.

免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


vue AES加密(超详细)

前端达人

第一步:


  1. //安装
  2. npm install crypto-js --save-dev

第二步:在src目录下新建个放公用js文件夹(common),再建一个AES.js文件,例如:

第三步:在AES.js中填写如下代码,key密钥长度则可以是128,192或256位(默认情况下是128位),正常情况下固定16位数即可

 
  1. import CryptoJS from 'crypto-js';
  2. export default {
  3. //随机生成指定数量的16进制key
  4. generatekey(num) {
  5. let library = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  6. let key = "";
  7. for (var i = 0; i < num; i++) {
  8. let randomPoz = Math.floor(Math.random() * library.length);
  9. key += library.substring(randomPoz, randomPoz + 1);
  10. }
  11. return key;
  12. },
  13. //加密
  14. encrypt(word, keyStr) {
  15. keyStr = keyStr ? keyStr : 'abcdsxyzhkj12345'; //判断是否存在ksy,不存在就用定义好的key
  16. var key = CryptoJS.enc.Utf8.parse(keyStr);
  17. var srcs = CryptoJS.enc.Utf8.parse(word);
  18. var encrypted = CryptoJS.AES.encrypt(srcs, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
  19. return encrypted.toString();
  20. },
  21. //解密
  22. decrypt(word, keyStr) {
  23. keyStr = keyStr ? keyStr : 'abcdsxyzhkj12345';
  24. var key = CryptoJS.enc.Utf8.parse(keyStr);
  25. var decrypt = CryptoJS.AES.decrypt(word, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
  26. return CryptoJS.enc.Utf8.stringify(decrypt).toString();
  27. }
  28. }

第四步:在需要的地方引入

import AES from "@/common/AES.js";

第五步:调用

 
  1. // var keys = AES.generatekey(16);
  2. //如果是对象/数组的话,需要先JSON.stringify转换成字符串
  3. // 不传key值,就默认使用上述定义好的key值
  4. var encrypts = AES.encrypt(JSON.stringify(cars));
  5. var dess = JSON.parse(AES.decrypt(encrypts));
  6. // var encrypts = AES.encrypt('1234asdasd');
  7. // var dess = AES.decrypt(encrypts);
  8. console.log(encrypts)
  9. console.log(encrypts.length)
  10. console.log(dess)

 

 

特别提示:当解密的时候是为空的时候(也没有报错),那么就一定是你的key长度不符合规范, 可以调整为key长度为16位。

 


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

截屏2021-05-13 上午11.41.03.png


文章来源:csdn   

分享此文一切功德,皆悉回向给文章原作者及众读者.

免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务



关于web项目前后端加密解密总结

前端达人

首先项目是基于vue开发的项目

1、DES加密

前端

需要引入js

import cryptoJs from 'crypto-js'

// DES加密

export const encryptDes = (message, key) => {

return cryptoJs.DES.encrypt(message, cryptoJs.enc.Utf8.parse(key), {

mode: cryptoJs.mode.ECB,

padding: cryptoJs.pad.Pkcs7

}).toString()

}

后台


package com.huihui.until;

import java.security.SecureRandom;
import java.util.Scanner;
 
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
 
import org.apache.commons.codec.binary.Base64;
 
 
/**
 * <b>类说明:DES</b>
 * <p>
 * <b>详细描述:</b>
 * @since 2019年3月31日 下午17:00:16
 */
public class DESCryptUtil {
    
    private static final String DES = "DES";
    
    public static final String desKey = "ba54ee44";
 
    public static String doEncrypt(String plainMessage, String hexDesKey) throws Exception {
        byte desKey[] = hexDesKey.getBytes();
        byte desPlainMsg[] = plainMessage.getBytes();
        return Base64.encodeBase64URLSafeString(desCrypt(desKey, desPlainMsg, Cipher.ENCRYPT_MODE));
    }
    /**
     * 获取解密后的字符串
     * @param hexEncryptMessage
     * @param hexDesKey
     * @return
     * @throws Exception
     */
    public static String doDecrypt(String hexEncryptMessage, String hexDesKey) throws Exception{
        if (hexEncryptMessage == null) {
            return null;
        }
        byte desKey[] = hexDesKey.getBytes();
        byte desPlainMsg[] = Base64.decodeBase64(hexEncryptMessage);
        return new String(desCrypt(desKey, desPlainMsg, Cipher.DECRYPT_MODE));
    }
    /**
     * 获取解密后的数组
     * @param desPlainMsg
     * @param hexDesKey
     * @return
     * @throws Exception
     */
    public static byte[] doDecryptByte(byte[] desPlainMsg, String hexDesKey) throws Exception{
        if (desPlainMsg == null) {
            return null;
        }
        byte desKey[] = hexDesKey.getBytes();
        return desCrypt(desKey, desPlainMsg, Cipher.DECRYPT_MODE);
    }
    
    private static byte[] desCrypt(byte[] desKey, byte[] desPlainMsg, int CipherMode) throws Exception{
        try {
            SecureRandom sr = new SecureRandom();
            DESKeySpec dks = new DESKeySpec(desKey);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
            javax.crypto.SecretKey key = keyFactory.generateSecret(dks);
            Cipher cipher = Cipher.getInstance(DES);
            cipher.init(CipherMode, key, sr);
            return cipher.doFinal(desPlainMsg);
        } catch (Exception e) {
            String message = "";
            if (CipherMode == Cipher.ENCRYPT_MODE) {
                message = "DES\u52A0\u5BC6\u5931\u8D25";
            } else {
                message = "DES\u89E3\u5BC6\u5931\u8D25";
            }
            throw new Exception(message, e);
        }
    }
    /**
     * 获取8位的key
     * @param str
     * @return
     */
    public static String processString(String str) {
        if(str==null||"".equals(str)) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<8;i++) {
            int index = i<<2&(32-i);
            sb.append(str.charAt(index));
        }
        
        return sb.toString();
    }
    public static void main(String[] args) throws Exception{
        DESCryptUtil se=new DESCryptUtil();
        for (int i = 0; i < 5; i++) {
            Scanner scanner=new Scanner(System.in);
            /*
             * 加密
             */
            System.out.println("请输入要加密的内容:");
            String content = scanner.next();
            System.out.println("加密后的密文是:"+se.doEncrypt(content, desKey));
           
            /*
             * 解密
             */
            System.out.println("请输入要解密的内容:");
             content = scanner.next();
            System.out.println("解密后的明文是:"+se.doDecrypt(content, desKey));
        }
    }

}
 

2 RSA加密解密

这是我是在在线生成公钥私钥的网站中生成了自己的公钥私钥用来测试

前台

import JsEncrypt from 'jsencrypt'

// RSA加密

export function encryptRsa(publickey, message) {

const rsa = new JsEncrypt()

rsa.setPublicKey(publickey)

return rsa.encrypt(message)

}

后台

package com.huihui.until;

import org.apache.commons.codec.binary.Base64;

import com.googosoft.config.GlobalConstants;

import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
  
  
public class RSAUtil {  
      
    private static Map<Integer, String> keyMap = new HashMap<Integer, String>();  //用于封装随机产生的公钥与私钥
    public static void main(String[] args) throws Exception {
        //生成公钥和私钥
        genKeyPair();
        //加密字符串
        String message = "df723820";
    //GlobalConstants.PUBLICKEY 公钥加密
        String messageEn = encrypt(message,GlobalConstants.PUBLICKEY);
        System.out.println(message + "\t加密后的字符串为:" + messageEn);

//GlobalConstants.PRIVATEKEY 私钥解密
        String messageDe = decrypt(messageEn,GlobalConstants.PRIVATEKEY);
        System.out.println("还原后的字符串为:" + messageDe);
    }

    /** 
     * 随机生成密钥对 
     * @throws NoSuchAlgorithmException 
     */  
    public static void genKeyPair() throws NoSuchAlgorithmException {  
        // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象  
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");  
        // 初始化密钥对生成器,密钥大小为96-1024位  
        keyPairGen.initialize(1024,new SecureRandom());  
        // 生成一个密钥对,保存在keyPair中  
        KeyPair keyPair = keyPairGen.generateKeyPair();  
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥  
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥  
        String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));  
        // 得到私钥字符串  
        String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));  
        // 将公钥和私钥保存到Map
        keyMap.put(0,publicKeyString);  //0表示公钥
        keyMap.put(1,privateKeyString);  //1表示私钥
    }  
    /** 
     * RSA公钥加密 
     *  
     * @param str 
     *            加密字符串
     * @param publicKey 
     *            公钥 
     * @return 密文 
     * @throws Exception 
     *             加密过程中的异常信息 
     */  
    public static String encrypt( String str, String publicKey ) throws Exception{
        //base64编码的公钥
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
        return outStr;
    }

    /** 
     * RSA私钥解密
     *  
     * @param str 
     *            加密字符串
     * @param privateKey 
     *            私钥 
     * @return 铭文
     * @throws Exception 
     *             解密过程中的异常信息 
     */  
    public static String decrypt(String str, String privateKey) throws Exception{
        //64位解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
        //base64编码的私钥
        byte[] decoded = Base64.decodeBase64(privateKey);  
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));  
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }

}  

蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

截屏2021-05-13 上午11.41.03.png


文章来源:csdn   

分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

nodejs 接收上传的图片

前端达人

1.nodejs接收上传的图片主要是使用formidable模块,服务器是使用的express搭建。

引入formidable

var formidable = require('./node_modules/formidable');

拦截请求,设置formidable的常规项

复制代码
app.post("/image",function (req,res) { var form = new formidable.IncomingForm();
    form.encoding = 'utf-8';
    form.uploadDir = path.join(__dirname + "/../page/upload");
    form.keepExtensions = true;//保留后缀 form.maxFieldsSize = 2 * 1024 * 1024;

});
复制代码

解析图片,重命名图片名称,返回给前端

复制代码
 //处理图片  form.parse(req, function (err, fields, files){
        console.log(files.the_file); var filename = files.the_file.name var nameArray = filename.split('.'); var type = nameArray[nameArray.length - 1]; var name = ''; for (var i = 0; i < nameArray.length - 1; i++) {
            name = name + nameArray[i];
        } var date = new Date(); var time = '_' + date.getFullYear() + "_" + date.getMonth() + "_" + date.getDay() + "_" + date.getHours() + "_" + date.getMinutes(); var avatarName = name + time + '.' + type; var newPath = form.uploadDir + "/" + avatarName;
        fs.renameSync(files.the_file.path, newPath); //重命名 res.send({data:"/upload/"+avatarName})
    })
复制代码


完整代码如下


var path = require("path"); var fs = require("fs"); var express =require("./node_modules/express"); var app=express(); var bodyParser = require('./node_modules/body-parser'); var formidable = require('./node_modules/formidable');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static(__dirname + "./../page"));
app.listen("8083",function () {
    console.log("服务启动")
}); //拦截请求 app.post("/image",function (req,res) { var form = new formidable.IncomingForm();
    form.encoding = 'utf-8';
    form.uploadDir = path.join(__dirname + "/../page/upload");
    form.keepExtensions = true;//保留后缀 form.maxFieldsSize = 2 * 1024 * 1024; //处理图片  form.parse(req, function (err, fields, files){
        console.log(files.the_file); var filename = files.the_file.name var nameArray = filename.split('.'); var type = nameArray[nameArray.length - 1]; var name = ''; for (var i = 0; i < nameArray.length - 1; i++) {
            name = name + nameArray[i];
        } var date = new Date(); var time = '_' + date.getFullYear() + "_" + date.getMonth() + "_" + date.getDay() + "_" + date.getHours() + "_" + date.getMinutes(); var avatarName = name + time + '.' + type; var newPath = form.uploadDir + "/" + avatarName;
        fs.renameSync(files.the_file.path, newPath); //重命名 res.send({data:"/upload/"+avatarName})
    })
});


    

蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

截屏2021-05-13 上午11.41.03.png

文章来源:博客园

分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

pm2的安装和使用

前端达人

一、简介

PM2是node进程管理工具,可以利用它来简化很多node应用管理的繁琐任务,如性能监控、自动重启、负载均衡等,而且使用非常简单。

二、前期必备

  1. node 环境
  2. npm

三、安装

全局安装

npm install -g pm2

四、入门教程

挑express应用来举例。一般我们都是通过npm start启动应用,其实就是调用node ./bin/www。那么,换成pm2就是

注意,这里用了–watch参数,意味着当你的express应用代码发生变化时,pm2会帮你重启服务(长时间监测有可能会出现问题,这时需要重启项目)

pm2 start ./bin/www –watch

五、常用命令

启动

参数说明:
–watch:监听应用目录的变化,一旦发生变化,自动重启。如果要精确监听、不见听的目录,最好通过配置文件。

-i –instances:启用多少个实例,可用于负载均衡。如果-i 0或者-i max,则根据当前机器核数确定实例数目。

–ignore-watch:排除监听的目录/文件,可以是特定的文件名,也可以是正则。比如–ignore-watch=”test node_modules “some scripts”“

-n –name:应用的名称。查看应用信息的时候可以用到。

-o –output :标准输出日志文件的路径。

-e –error :错误输出日志文件的路径。

–interpreter :the interpreter pm2 should use for executing app (bash, python…)。比如你用的coffee script来编写应用。
完整命令行参数列表:地址

pm2 start app.js –watch -i 2

重启

pm2 restart app.js

停止

停止特定的应用。可以先通过pm2 list获取应用的名字(–name指定的)或者进程id。

pm2 stop app_name|app_id

如果要停止所有应用,可以

pm2 stop all

删除

pm2 stop app_name|app_id
pm2 stop all

查看进程状态

pm2 list

自动重启

pm2 start app.js –watch

*这里是监控整个项目的文件

日志查看

除了可以打开日志文件查看日志外,还可以通过pm2 logs来查看实时日志。

pm2 logs

更新pm2

pm2 save # 记得保存进程状态
npm install pm2 -g
pm2 update

 

附pm2命令:

$ npm install pm2 -g # 命令行安装 pm2  $ pm2 start app.js -i 4 # 后台运行pm2,启动4个app.js  # 也可以把'max' 参数传递给 start # 正确的进程数目依赖于Cpu的核心数目 $ pm2 start app.js --name my-api # 命名进程 $ pm2 list # 显示所有进程状态 $ pm2 monit # 监视所有进程 $ pm2 logs # 显示所有进程日志 $ pm2 stop all # 停止所有进程 $ pm2 restart all # 重启所有进程 $ pm2 reload all # 0 秒停机重载进程 (用于 NETWORKED 进程) $ pm2 stop 0 # 停止指定的进程 $ pm2 restart 0 # 重启指定的进程 $ pm2 startup # 产生 init 脚本 保持进程活着 $ pm2 web # 运行健壮的 computer API endpoint (http://localhost:9615) $ pm2 delete 0 # 杀死指定的进程 $ pm2 delete all # 杀死全部进程



蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

截屏2021-05-13 上午11.41.03.png


文章来源:博客园

分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


.user.ini 无法修改/删除 怎么办?

前端达人

首先



了解chattr命令:



Linux chattr命令用于改变文件属性。



这项指令可改变存放在ext2文件系统上的文件或目录属性,这些属性共有以下8种模式:



a:让文件或目录仅供附加用途。

b:不更新文件或目录的最后存取时间。

c:将文件或目录压缩后存放。

d:将文件或目录排除在倾倒操作之外。

i:不得任意更动文件或目录。

s:保密性删除文件或目录。

S:即时更新文件或目录i。

u:预防意外删除。

我们主要用的是 i 的模式



第二:



    切换到 .user.ini 目录



第三:



    使用命令 chattr -i .user.ini  解除文件不可更动属性,之后就可以修改/删除.user.ini这个文件了



第四:


   chattr +i .user.ini   重新恢复文件不可更动属性



蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

截屏2021-05-13 上午11.41.03.png


文章来源:csdn   

分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档