ECharts中dataZoom組件及散點圖的繪制
dataZoom 組件是對 數軸(axis) 進行『數據窗口縮放』『數據窗口平移』操作。
可以通過 dataZoom.xAxisIndex 或 dataZoom.yAxisIndex 來指定 dataZoom 控制哪個或哪些數軸。
dataZoom 組件可同時存在多個,起到共同控制的作用??刂仆粋€數軸的組件,會自動聯動。下面例子中會詳細說明。
dataZoom 的運行原理是通過『數據過濾』來達到『數據窗口縮放』的效果。
dataZoom 的數據窗口范圍的設置,目前支持兩種形式:
百分比形式:參見 dataZoom.start 和 dataZoom.end。
絕對數值形式:參見 dataZoom.startValue 和 dataZoom.endValue。
dataZoom 組件現在支持幾種子組件:
內置型數據區域縮放組件(dataZoomInside):內置于坐標系中。
滑動條型數據區域縮放組件(dataZoomSlider):有單獨的滑動條操作。
框選型數據區域縮放組件(dataZoomSelect):全屏的選框進行數據區域縮放。入口和配置項均在 toolbox中。
在代碼中加入dataZoom組件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>代碼加入dataZoom組件</title>
<!--引入Echarts文件-->
<script src="js/echarts.min.js"></script>
</head>
<body>
<div id="main" style="width: 800px;height:400px;"></div>
<script type="text/javascript">
var dom=document.getElementById("main");
var myChart=echarts.init(dom);
var app={};
var option=null;
//先只在對單獨一個橫軸,加上 dataZoom 組件,代碼示例如下:
option = {
tooltip:{},//提示框
xAxis: {
type: 'value'
},
yAxis: {
type: 'value'
},
dataZoom: [
{
type: 'slider', //這個dataZoom組件是slider型dataZoom組件
xAxisIndex:0, //dataZoom-slider組件控制第一個XAxis
start: 10, //左邊在10%位置
end: 60 //右邊在60%位置
},
{
type: 'inside', //這個dataZoom組件是inside型dataZoom組件
xAxisIndex:0, //dataZoom-inslide組件控制第一個XAxis
start: 10, //左邊在10%的位置
end: 60 //右邊在60%的位置
},{
type:'slider',
yAxisIndex:0, //dataZoom-slider組件控制第一個yAxis
start:30,
end:80
},{
type:'inside',
yAxisIndex:0, //dataZoom-inside組件控制第一個yAxis
start:30,
end:80
}
],
series: [
{
name: 'scatter',
type: 'scatter',
itemStyle: {
normal: {
opacity: 0.8
}
},
symbolSize: function (val) {//控制點的大小,(參數為data中第三列的數據)
return val[2] * 40; //用回調函數控制點的大小(請查看官方文檔)
},
data: [//data中第三個參數控制點的大小
["14.616","7.241","0.896"],
["3.958","5.701","0.955"],
["2.768","8.971","0.669"],
["9.051","9.710","0.171"],
["14.046","4.182","0.536"],
["12.295","1.429","0.962"],
["4.417","8.167","0.113"],
["0.492","4.771","0.785"],
["7.632","2.605","0.645"],
["14.242","5.042","0.368"]
]
}
]
}
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
</script>
</body>
</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
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
可以通過滑動滑輪實現圖形的縮放
藍藍設計建立了UI設計分享群,每天會分享國內外的一些優秀設計,如果有興趣的話,可以進入一起成長學習,請掃碼藍小助,報下信息,藍小助會請您入群。歡迎您加入噢~~希望得到建議咨詢、商務合作,也請與我們聯系。
部分借鑒自:csdn
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
本問下面有矢量圖層設置的區域,和熱力圖層設置的熱力圖的效果,區域繪制效怎么設置詳細內容可以訪問 openlayers6【十七】vue VectorLayer矢量圖層畫地圖省市區,多省市區(粵港澳大灣區)效果詳解,主要講解的是熱力圖層效果實現。區域繪制只是為了效果更好看。好了,繼續往下看
在 openlayers 中,圖層是使用 layer 對象表示的,主要有 WebGLPoints Layer
、熱度圖(HeatMap Layer)
、圖片圖層(Image Layer)
、切片圖層(Tile Layer)
和 矢量圖層(Vector Layer)
五種類型,它們都是繼承 Layer 類的。
前面兩篇文章 我們講了矢量圖層 VectorLayer
的常用的場景,這篇我們寫一篇 HeatMapLayer
的使用。可以看下圖所示的熱力圖實現效果。 放大縮小地圖熱力圖效果。
var heatmapLayer = new ol.layer.Heatmap({ source: source,//熱力圖資源 opacity:1,//透明度,默認1 visible:true,//是否顯示,默認trur zIndex:1,//圖層渲染的Z索引,默認按圖層加載順序疊加 gradient:['#00f','#0ff','#0f0','#ff0','#f00'],//熱圖的顏色漸變 blur: 15,//模糊大小(像素為單位) radius: 8,//半徑大小默認為8(像素為單位) extent:[100,30,104,40],//渲染范圍,可選值,默認渲染全部 });
2.2.1 addHeatMap()方法詳解:
HeatmapLayer
map
中
AppendFeatures()
2.2.2 addHeatMap()方法代碼:
/**
* 添加熱力圖
*/ addHeatMap() { let colors = [ "#2200FF", "#16D9CC", "#4DEE12", "#E8D225", "#EF1616" ]; let hatmapData = [ { name: "成都市" }, { name: "成都市" }, { name: "成都市" }, { name: "成都市" }, { name: "綿陽市" }, { name: "廣安市" }, { name: "雅安市" }, { name: "自貢市" }, { name: "自貢市" }, { name: "自貢市" }, { name: "自貢市" }, { name: "自貢市" }, { name: "自貢市" }, { name: "自貢市" }, { name: "宜賓市" }, { name: "甘孜藏族自治州市" } ]; let codeList = { 成都市: { center: { lng: 104.061902, lat: 30.609503 } }, 廣安市: { center: { lng: 106.619126, lat: 30.474142 } }, 綿陽市: { center: { lng: 104.673612, lat: 31.492565 } }, 雅安市: { center: { lng: 103.031653, lat: 30.018895 } }, 自貢市: { center: { lng: 104.797794, lat: 29.368322 } }, 宜賓市: { center: { lng: 104.610964, lat: 28.781347 } }, 甘孜藏族自治州市: { center: { lng: 101.592433, lat: 30.426712 } } }; this.layer = new HeatmapLayer({ source: new VectorSource(), blur: 30, radius: 15, gradient: colors }); this.map.addLayer(this.layer); this.AppendFeatures(hatmapData, colors, codeList, 50); },
2.2.3 AppendFeatures()方法詳解:
new Feature
點new Point
信息
2.2.4 AppendFeatures()方法代碼:
/**
* 增加要素到熱力圖
*/ AppendFeatures(hatmapData, colors, points, max) { for (var i in hatmapData) { if (points[hatmapData[i].name]) { var coords = points[hatmapData[i].name]; this.max = max; var f = new Feature({ geometry: new Point( fromLonLat([coords.center.lng, coords.center.lat]) ) }); this.layer.getSource().addFeature(f); } } }
<template> <div id="app"> <div id="Map" ref="map"></div> </div> </template> <script> import "ol/ol.css"; import VectorLayer from "ol/layer/Vector"; import VectorSource from "ol/source/Vector"; import { Tile as TileLayer, Heatmap as HeatmapLayer } from "ol/layer"; import Proj from "ol/proj/Projection"; import XYZ from "ol/source/XYZ"; import { Map, View, Feature, ol } from "ol"; import { Style, Stroke, Fill } from "ol/style"; import { Polygon, Point } from "ol/geom"; import { defaults as defaultControls } from "ol/control"; import { fromLonLat } from "ol/proj"; // 四川的邊界數據文件 import areaGeo from "@/geoJson/sichuan.json"; export default { data() { return { map: null }; }, methods: { /**
* 初始化地圖
*/ initMap() { this.map = new Map({ target: "Map", controls: defaultControls({ zoom: true }).extend([]), layers: [ new TileLayer({ source: new XYZ({ url: "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}" }) }) ], view: new View({ center: fromLonLat([104.065735, 30.659462]), zoom: 6.5, maxZoom: 19, minZoom: 5 }) }); }, /**
* 設置區域
*/ addArea(geo = []) { if (geo.length == 0) { return false; } let features = []; geo.forEach(g => { let lineData = g.features[0]; let routeFeature = ""; if (lineData.geometry.type == "MultiPolygon") { routeFeature = new Feature({ geometry: new MultiPolygon( lineData.geometry.coordinates ).transform("EPSG:4326", "EPSG:3857") }); } else if (lineData.geometry.type == "Polygon") { routeFeature = new Feature({ geometry: new Polygon( lineData.geometry.coordinates ).transform("EPSG:4326", "EPSG:3857") }); } routeFeature.setStyle( new Style({ fill: new Fill({ color: "#4e98f444" }), stroke: new Stroke({ width: 3, color: [71, 137, 227, 1] }) }) ); features.push(routeFeature); }); // 設置圖層 let routeLayer = new VectorLayer({ source: new VectorSource({ features: features }) }); // 添加圖層 this.map.addLayer(routeLayer); }, /**
* 添加熱力圖
*/ addHeatMap() { let colors = [ "#2200FF", "#16D9CC", "#4DEE12", "#E8D225", "#EF1616" ]; let hatmapData = [ { name: "成都市" }, { name: "成都市" }, { name: "成都市" }, { name: "成都市" }, { name: "綿陽市" }, { name: "廣安市" }, { name: "雅安市" }, { name: "自貢市" }, { name: "自貢市" }, { name: "自貢市" }, { name: "自貢市" }, { name: "自貢市" }, { name: "自貢市" }, { name: "自貢市" }, { name: "宜賓市" }, { name: "甘孜藏族自治州市" } ]; let codeList = { 成都市: { center: { lng: 104.061902, lat: 30.609503 } }, 廣安市: { center: { lng: 106.619126, lat: 30.474142 } }, 綿陽市: { center: { lng: 104.673612, lat: 31.492565 } }, 雅安市: { center: { lng: 103.031653, lat: 30.018895 } }, 自貢市: { center: { lng: 104.797794, lat: 29.368322 } }, 宜賓市: { center: { lng: 104.610964, lat: 28.781347 } }, 甘孜藏族自治州市: { center: { lng: 101.592433, lat: 30.426712 } } }; this.layer = new HeatmapLayer({ source: new VectorSource(), blur: 30, radius: 15, gradient: colors }); this.map.addLayer(this.layer); this.AppendFeatures(hatmapData, colors, codeList, 50); }, /**
* 增加要素至熱力圖
*/ AppendFeatures(hatmapData, colors, points, max) { for (var i in hatmapData) { if (points[hatmapData[i].name]) { var coords = points[hatmapData[i].name]; this.max = max; var f = new Feature({ geometry: new Point( fromLonLat([coords.center.lng, coords.center.lat]) ) }); this.layer.getSource().addFeature(f); } } } }, mounted() { this.initMap(); //初始化地圖 this.addArea(areaGeo); //添加四川省的邊界描邊和填充 this.addHeatMap(); //添加熱力圖數據 } }; </script> <style lang="scss" scoped> // 此處非核心內容,已刪除 </style>
//添加熱力圖層 this.map.addLayer(this.layer) //刪除熱力圖層 this.map.removeLayer(this.layer)
//獲取-設置,模糊大小 heatmapLayer.getBlur() heatmapLayer.setBlur(15) //獲取-設置,渲染范圍 heatmapLayer.getExtent() heatmapLayer.setExtent([100,30,104,40]) //獲取-設置,熱力圖漸變色 heatmapLayer.getGradient() heatmapLayer.setGradient(['#00f','#0ff','#0f0','#ff0','#f00']) //獲取-設置,最大級別 heatmapLayer.getMaxZoom() heatmapLayer.setMaxZoom(18) //獲取-設置,最小級別 heatmapLayer.getMinZoom() heatmapLayer.setMinZoom(2) //獲取-設置,透明度 heatmapLayer.getOpacity() heatmapLayer.setOpacity(0.5) //獲取-設置,半徑 heatmapLayer.getRadius() heatmapLayer.setRadius(5) //獲取-設置,熱力源 heatmapLayer.getSource() heatmapLayer.setSource(source) //獲取-設置,是否可見 heatmapLayer.getVisible() heatmapLayer.setVisible(true) //獲取-設置,圖層的Z-index heatmapLayer.getZIndex() heatmapLayer.setZIndex(2) //綁定事件-取消事件 type事件類型,listener函數體 heatmapLayer.on(type,listener) heatmapLayer.un(type,listener)
藍藍設計建立了UI設計分享群,每天會分享國內外的一些優秀設計,如果有興趣的話,可以進入一起成長學習,請掃碼藍小助,報下信息,藍小助會請您入群。歡迎您加入噢~~希望得到建議咨詢、商務合作,也請與我們聯系。
部分借鑒自:csdn
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
Force-directed(力導向)圖形繪制算法通過圖形本身的結構(圖中頂點與邊的拓撲關系)計算出圖形的層次,而不依賴于特定領域的知識。使用力導向算法繪制的平面圖形通常比較美觀,并且圖中各條邊之間的交叉盡可能的少。
本文對使用D3js繪制Foorce-Directed Graph(力導向圖)的過程進行簡要的介紹,以下面的邏輯圖(包含6個節點和5條邊)為例。
import json #nodes為圖的節點集合 nodes = [{'name' : 'nodeA'},
{'name' : 'nodeB'},
{'name' : 'nodeC'},
{'name' : 'nodeD'},
{'name' : 'nodeE'},
{'name' : 'nodeF'}] #links為圖的邊集合,source為起點,target為終點 links = [{'source' : 0 , 'target' : 1},
{'source' : 0 , 'target' : 2},
{'source' : 0 , 'target' : 3},
{'source' : 0 , 'target' : 4},
{'source' : 0 , 'target' : 5}] #graph為邏輯圖,由節點集合和邊集合組成 graph = {'nodes' : nodes , 'links' : links} print json.dumps(graph)
上例的源碼 force-directed-graph.html 及注釋如下:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <style> .link { stroke : #CCC; stroke-width : 2; } .node text { pointer-events : none; font-size : 12px; } svg { overflow : hidden; } </style> <script src="http://libs.useso.com/js/jquery/1.11.1/jquery.min.js"></script> <script src="http://libs.useso.com/js/d3/3.4.8/d3.min.js"></script> <script> var graph = {"nodes": [{"name": "nodeA"},
{"name": "nodeB"},
{"name": "nodeC"},
{"name": "nodeD"},
{"name": "nodeE"},
{"name": "nodeF"}], "links": [{"source": 0, "target":1},
{"source": 0, "target": 2},
{"source": 0, "target": 3},
{"source": 0, "target": 4},
{"source": 0, "target": 5}]}; //返回隨機顏色代碼 function random_color() { var letters = '0123456789ABCDEF'.split(''); var color = '#'; for (var i = 0; i < 6; i++ ) {
color += letters[Math.round(Math.random() * 15)];
} return color;
} function draw() { var width = 400; var height = 300; //設置svg寬度和高度 var svg = d3.select("#canvas svg")
.attr("width", width)
.attr("height", height); //設置Force-Directed力參數 var force = d3.layout.force()
.gravity(.05)
.distance(120)
.charge(-100)
.size([width, height]);
force
.nodes(graph.nodes)
.links(graph.links)
.start(); //選擇邊集合 var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link"); //選擇節點集合 var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag); //響應鼠標拖拽事件 //節點添加圓形圖案 node.append("svg:circle").attr("r", 10)
.style("fill", function(){ return random_color();
})
.style("stroke", "#FFF").style("stroke-width", 3);
node.append("text")
.attr("dx", 12)
.attr("dy", ".36em")
.text(function(d) { return d.name }); //綁定tick事件 force.on("tick", function() { link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});
}
$(function(){ draw();
}); </script> </head> <body> <div id="canvas"> <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="300"></svg> </div> </body> </html>
本文鏈接:http://bookshadow.com/weblog/2014/11/04/d3js-force-directed-graph/
請尊重作者的勞動成果,轉載請注明出處!書影博客保留對文章的所有權利。
藍藍設計建立了UI設計分享群,每天會分享國內外的一些優秀設計,如果有興趣的話,可以進入一起成長學習,請掃碼藍小助,報下信息,藍小助會請您入群。歡迎您加入噢~~希望得到建議咨詢、商務合作,也請與我們聯系。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
首先3d-force-graph在碼云或者github直接搜索,它的文檔確實有點少。這個插件用了3次,每一次都有不同的痛苦,也有粗心大意所導致的。
好的,我們現在講解一下這個插件中的導向樹DAG模式
我的案例都會基于Vue開發,創建項目等等我們進不說了,進入正題。
步驟:1.安裝:npm i 3d-force-graph (我安裝的是"3d-force-graph": “^1.67.5”,)
2.導入 import ForceGraph from ‘3d-force-graph’;
首先注意點:
1.不要全部cv我的代碼,或者光放文檔中的代碼,我們要依據后臺數據實際看問題,但是基本的代碼步驟是差不多的,但是也不要全CV,不然你的瀏覽器會報錯,而且你以為錯誤是你的邏輯問題,實際上是cv多了的問題(這一點使我耽誤了半天的時間)
2. 數據處理設計到了遞歸等,數據接口我就不寫了
在模板中定義:
<template>
<div class="wrap"></div>
</template>
import ForceGraph from '3d-force-graph'; // 導入 import { subjectList } from '../src/request/api'; // 掉數據的接口
data() { return { // 源數據 sourceData: null, // 力導向圖數據 nodes: [], links: [], ForceGraphData: {} }; },
初始話完成
async created() { // 獲取數據接口 try { const { data: res } = await subjectList(); this.sourceData = res.data; console.log(this.sourceData); } catch (err) { console.log(err); } this.digui(this.sourceData); // 遞歸處理數據 this.SetForce(); // 調用力導向圖 },
進入數據
methods: { // 1.先定義數據 // 首先定義nodes數據;節點數據 設計遞歸定義方法 digui(data) { data.children.forEach(item => { if (item.children) { this.digui(item); } const nodeObjs = {}; nodeObjs.name = item.name; nodeObjs.id = item.id; nodeObjs.level = item.level; nodeObjs.parent_id = item.parent_id; nodeObjs.has_children = item.has_children; const linksObjs = {}; linksObjs.source = item.parent_id; linksObjs.target = item.id; this.nodes.push(nodeObjs); this.links.push(linksObjs); }); },
后端返回的數據是格式我們需要用遞歸地方法把他們處理
要知道插件的節點是nodes數據,連線是links數據,links數組中的每一項都有source和target,source的是連線的開始端,target是連線的結束端,source的是parent_id,target的是id,也就是依據數據進行連接,這一不懂的話可以看看這個插件的這個案例
好,繼續,處理完的數據是nodes數據后端數據返回的每一項包括children下的每一項,links數據是每一項是的target:id和source:parent_id
處理數據完成,下一部在methods中設置力導向圖的函數
// 設置力導向圖 SetForce() { // 這里在最想面插入了一條數據是因為后端返還的數據和依據插件的機制需要我在最前面插入一條最起點的數據 //也就是這條數據就是起源,一般來說你們也會在最前面插入一條起源數據,因為后端數據差不多樣式都是一樣的 // 這條數據就不用在添加parent_id了,就是返回的有parent_id,而不需要添加。 this.nodes.unshift({ id: 10515, name: '化學', level: 1, }); this.ForceGraphData.links = this.links; this.ForceGraphData.nodes = this.nodes; const gukergForce = ForceGraph(); gukergForce(document.querySelector('.wrap')) // 力導向圖放在容器中 記住這個容器在樣式中要給大小 .graphData(this.ForceGraphData)// 這條就是數據源 .dagMode('td') // 模式有很多選擇,我選擇的td,自上而下的格式,文檔中有選擇,你們按自己需求選 } },
現在一個簡單的力導向樹就出來了,隨項目的需求你可在節點加圖片,你需要import * as THREE from ‘three’;這個包不用下載,直接導入就可以,
const gukergForce = ForceGraph(); // 力導向圖放在容器中 gukergForce(document.querySelector('.wrap')) .graphData(this.ForceGraphData) .dagLevelDistance(70) // 兩點直接的距離 .dagMode('td') .nodeResolution(50) // 較高的值產生較光滑的球體。 .nodeThreeObject(node => { .nodeThreeObject(node => { if (node.level === 1) { console.log('你好'); } let imgTexture = ''; if (node.level === 1) { imgTexture = new THREE.TextureLoader().load(require('./assets/1.png')); } else if (node.level === 2) { imgTexture = new THREE.TextureLoader().load(require('./assets/2.png')); } else if (node.level === 3) { imgTexture = new THREE.TextureLoader().load(require('./assets/3.png')); } else if (node.level === 4) { imgTexture = new THREE.TextureLoader().load(require('./assets/4.png')); } else if (node.level === 5) { imgTexture = new THREE.TextureLoader().load(require('./assets/5.png')); } const material = new THREE.SpriteMaterial({ map: imgTexture }); const sprite = new THREE.Sprite(material); if (node.level === 1) { sprite.scale.set(50, 45); return sprite; } else if (node.level === 2) { sprite.scale.set(20, 20); return sprite; } if (node.level === 3) { sprite.scale.set(30, 30); return sprite; } if (node.level === 4) { sprite.scale.set(20, 15); return sprite; } if (node.level === 5) { sprite.scale.set(20, 20); return sprite; } }); }
其實由誰解決了它節點之間不重復的問題,可以給我留言,謝謝
轉自:csdn論壇
藍藍設計建立了UI設計分享群,每天會分享國內外的一些優秀設計,如果有興趣的話,可以進入一起成長學習,請掃碼藍小助,報下信息,藍小助會請您入群。歡迎您加入噢~~希望得到建議咨詢、商務合作,也請與我們聯系。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
Node.js 是一個基于 Chrome V8 引擎 的 JavaScript 運行時(即node.js不是一門語言也不是庫和框架,它是一個JavaScript運行時環境)。 用于方便地搭建響應速度快、易于擴展的網絡應用。Node.js使用事件驅動,非阻塞I/O 模型而得以輕量和高效,非常適合在分布式設備上運行數據密集型的實時應用。
安裝node
直接到官網上下載自己電腦的版本,官網地址:https://nodejs.org/zh-cn/
安裝完成之后可以通過在終端上運行node -v //查看是否安裝成功,成功的話會展示當前安裝版本 npm -v //安裝node的時會連同一起將npm安裝包一起打包安裝了,npm是nodejs的包管理器 npm install -g cnpm --registry=https://registry.npm.taobao.org //安裝淘寶鏡像可提高下載包工具的速度
Express框架
Express 是一個簡潔而靈活的 node.js Web應用框架, 提供了一系列強大特性幫助你創建各種 Web 應用,和豐富的 HTTP 工具。
使用 Express 可以快速地搭建一個完整功能的網站。express 是nodejs的一個web框架,使用express,能夠更便捷的使用nodejs.
安裝
第一步:安裝express
npm install express --save -g
第二步:安裝express-generator
npm install express-generator --save -g //express-generator是express應用生成器,相當于express 的骨架
第三步:打開終端進入你將要建立項目的文件夾中創建你的項目
express expressDemo //你要建立的項目名稱
第四步:安裝:npm install
第五步:啟動項目:npm start
這樣你的第一個express項目就創建成功了express-路由
Express框架建立在node.js內置的http模塊上。http模塊生成服務器的原始代碼如下。
var http = require("http"); var app = http.createServer(function(request, response) { response.writeHead(200, {"Content-Type": "text/plain"}); response.end("Hello world!"); }); app.listen(3000, "localhost");
上面代碼的關鍵是http模塊的createServer方法,表示生成一個HTTP服務器實例。該方法接受一個回調函數,該回調函數的參數,分別為代表HTTP請求和HTTP回應的request對象和response對象。
Express框架的核心是對http模塊的再包裝。上面的代碼用Express改寫如下。
var express = require('express'); var app = express(); app.get('/', function (req, res) { res.send('Hello world!'); }); app.listen(3000);
比較兩段代碼,可以看到它們非常接近。原來是用http.createServer方法新建一個app實例,現在則是用Express的構造方法,生成一個Epress實例。兩者的回調函數都是相同的。Express框架等于在http模塊之上,加了一個中間層。
中間件
簡單說,中間件(middleware)就是處理HTTP請求的函數。它最大的特點就是,一個中間件處理完,再傳遞給下一個中間件。App實例在運行過程中,會調用一系列的中間件。
每個中間件可以從App實例,接收三個參數,依次為request對象(代表HTTP請求)、response對象(代表HTTP回應),next回調函數(代表下一個中間件)。每個中間件都可以對HTTP請求(request對象)進行加工,并且決定是否調用next方法,將request對象再傳給下一個中間件。
Express 應用程序基本上是一系列中間件函數調用。
中間件函數可以執行以下任務:
- 執行任何代碼。
- 對請求和響應對象進行更改。
- 結束請求/響應循環。
- 調用堆棧中的下一個中間件函數。
Express 應用程序可以使用以下類型的中間件:
- 應用層中間件
- 路由器層中間件
- 錯誤處理中間件
- 內置中間件
- 第三方中間件
應用層中間件
使用app.use()
和app.METHOD()
函數將應用層中間件綁定到應用程序對象的實例,其中METHOD
是中間件函數處理的請求的小寫 HTTP 方法(例如 GET、PUT 或 POST)。app.use('/user/:id', function (req, res, next) { //在 /user/:id 路徑中為任何類型的 HTTP 請求執行此函數。 console.log('Request Type:', req.method); next(); }); app.get('/user/:id', function (req, res, next) { res.send('USER'); });
路由器層中間件
路由器層中間件的工作方式與應用層中間件基本相同,差異之處在于它綁定到 express.Router() 的實例。var router = express.Router();
錯誤處理中間件
錯誤處理中間件函數的定義方式與其他中間件函數基本相同,差別在于錯誤處理函數有四個自變量而不是三個,專門具有特征符 (err, req, res, next):app.use(function(err, req, res, next) { console.error(err.stack); res.status(500).send('Something broke!'); });
有關錯誤處理中間件的詳細信息,請參閱:錯誤處理。
內置中間件
自 V4.x 起,Express 不再依賴于 Connect。除express.static
外,先前 Express 隨附的所有中間件函數現在以單獨模塊的形式提供。請查看中間件函數的列表。第三方中間件
使用第三方中間件向 Express 應用程序添加功能。
安裝具有所需功能的 Node.js 模塊,然后在應用層或路由器層的應用程序中將其加裝入。
列如cookie-parser中間件函數
首先安裝cookie-parser。npm install cookie-parser
var express = require('express'); var app = express(); var cookieParser = require('cookie-parser'); // load the cookie-parsing middleware app.use(cookieParser());
MongoDB數據庫
MongoDB 是一個基于分布式文件存儲的數據庫。由 C++ 語言編寫。旨在為 WEB 應用提供可擴展的高性能數據存儲解決方案。
MongoDB 是一個介于關系數據庫和非關系數據庫之間的產品,是非關系數據庫當中功能最豐富,最像關系數據庫的。你可以在mongodb官網下載該安裝包,地址為:https://www.mongodb.com/download-center#community。
以下以Mac版本為例講解1,打開終端修改環境變量
echo $PATH
你可以查看到你當前的環境變量下面的文件
image.png2,選擇其中一個文件夾進去然后將你的mongodb的安裝包路徑映射到此文件上
ln -s 你的MongoDB的安裝包路徑/bin/mongo mongo
3,你創建一個數據庫存儲目錄 /data/db:
sudo mkdir -p /data/db
4,啟動 mongodb,默認數據庫目錄即為 /data/db:
sudo mongod
5,再打開一個終端執行以下命令連接
mongo
這樣你就啟動連接上了本地的數據庫
你可以下載安裝mongosBooster數據庫管理你的數據,地址為https://nosqlbooster.com/downloadsmongoose
mongoose是nodeJS提供連接 mongodb的一個庫. 此外還有mongoskin, mongodb(mongodb官方出品). 本人,還是比較青睞mongoose的, 因為他遵循的是一種, 模板式方法, 能夠對你輸入的數據進行自動處理. 有興趣的同學可以去Mongoose官網看看.
安裝mongoosenpm install mongoose --save
Mongoose里面有幾個基本概念.
- Schema: 相當于一個數據庫的模板. Model可以通過mongoose.model 集成其基本屬性內容. 當然也可以選擇不繼承.
- Model: 基本文檔數據的父類,通過集成Schema定義的基本方法和屬性得到相關的內容.
- instance: 這就是實實在在的數據了. 通過 new Model()初始化得到.
在保證你已經啟動連接上了mongoDB時你就可以使用了,列如以下Democonst mongoose = require('mongoose'); mongoose.connect('mongodb://localhost:27017/test'); const con = mongoose.connection; con.on('error', console.error.bind(console, '連接數據庫失敗')); con.once('open',()=>{ //定義一個schema let Schema = mongoose.Schema({ category:String, name:String }); Schema.methods.eat = function(){ console.log("I've eatten one "+this.name); } //繼承一個schema let Model = mongoose.model("fruit",Schema); //生成一個document let people = new Model({ category:'apple', name:'apple' }); //存放數據 people.save((err,apple)=>{ if(err) return console.log(err); apple.eat(); //查找數據 Model.find({name:'apple'},(err,data)=>{ console.log(data); }) }); //查詢所有數據 people.find(function(err,ret){ if(err){ console.log('查詢失敗') }else{ console.log('查詢成功') } }) //按條件查詢符合條件的數據 people.find({},function(err,ret){ }) //按條件查詢單個數據 people.findOne({},function(err,ret){ }) //刪除數據 people.remove({uesername:'zhangsan'},function(err,ret){ }) //根據ID刪除數據 peop.findByIdAndRemove({},function(err,ret){ }) //更新數據 people.findByIdAndUpdate('dfsfs',function(err,ret){ }) })
到這里, 實際上, mongoose我們已經就學會了. 剩下就是看一看官方文檔的API–CRUD相關操作
作者:orange_9706
來源:簡書
藍藍設計建立了UI設計分享群,每天會分享國內外的一些優秀設計,如果有興趣的話,可以進入一起成長學習,請掃碼藍小助,報下信息,藍小助會請您入群。歡迎您加入噢~~希望得到建議咨詢、商務合作,也請與我們聯系。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
進行傻瓜式安裝:最后點擊install即可;
首先在安裝路徑下新建兩個文件夾【node_global】及【node_cache】,如下:
然后cmd執行命令
-
npm config set prefix "E:\Program Files\node_js\node_global"
-
npm config set cache "E:\Program Files\node_js\node_cache"
接著配置環境變量,系統變量里新建:
用戶變量里的改為E:\Program Files\node_js\node_global;
最后可以測試一下是否安裝到了新的路徑里:可以看到成功了
npm install express -g ,其中 -g 表示全局,不加會安裝在當前路徑C:/users/dell下
傻瓜式安裝:
npm install express -g和
express應用生成器 npm install express-generator -g;
然后打開終端,如圖
結果報錯:express : 無法加載文件 E:\Program Files\node_js\node_global\express.ps1,因為在此系統上禁止運行腳本。有關詳細信息,請參閱 https:/
go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。
+ express mytest
+ ~~~~~~~
+ CategoryInfo : SecurityError: (:) [],PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess
那就解決錯誤先:解決方法如圖
這樣就創建成功了。
這里應該是先新建一個文件夾來存放項目,然后進入指定位置。默認的話就放到c盤了。
在終端執行如下代碼
然后瀏覽器輸入http://localhost:3000/
接下來安裝項目依賴,如圖;
進入項目,運行項目;
瀏覽器輸入http://localhost:8080進行訪問,如下圖。
github地址附上:https://vuejs-templates.github.io/webpack
藍藍設計建立了UI設計分享群,每天會分享國內外的一些優秀設計,如果有興趣的話,可以進入一起成長學習,請掃碼藍小助,報下信息,藍小助會請您入群。歡迎您加入噢~~希望得到建議咨詢、商務合作,也請與我們聯系。
部分借鑒自:csdn 作者:狼丶宇先生
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
現在是互聯網逐漸發展,已經出現了很多可以供自己寫博客的網站,大家可以在上面 發表自己的文章,供自己記錄或者是供他人閱讀。但是,可不可以自己搭建一個只屬于自己的個人博客網站呢?這篇文章就帶你從0開始搭建一個自己的個人博客網站,并部署到屬于自己服務器。這里有一點要說的是,沒有服務器的同學使用自己機器的linux系統也是一樣的操作。我們選用一個很好用的博客框架Hexo進行搭建我們的個人博客。
Hexo是一個快速,簡介而且高效的博客框架,Hexo 使用Markdown(或其他渲染引擎)解析文章,在幾秒內,即可生成一個靜態網頁展示我們發布的文章,同時也提供了大量精美的博客主題供我們使用。
我們使用Centos7系統作為演示,使用其他linux系統也是可以的,只需要更換為對應Linux版本的軟件安裝命令即可。
1.安裝Git
直接使用yum安裝即可,在命令行輸入 yum -y install git
完成之后輸入git version 查看是否安裝成功,如果顯示git版本信息即為成功,如下:
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
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 #讓環境變量生效
2.3:測試是否安裝成功:
在命令行輸入node -v 和 npm -v,若是顯示出了版本號,即為安裝成功:
3.安裝并使用Hexo
Hexo的安裝較為簡單,使用如下命令安裝
npm install -g hexo-cli #這里有一點要注意的就是,npm的源是在國外的,訪問可能會很慢,這里可以換成我們國內的源進行安裝加快速度。操作如下: npm config set registry https://registry.npm.taobao.org
3.1:初始化Hexo
上面的安裝完成之后執行下面的命令進行對Hexo進行一個初始化
#這個文件名字可以自己指定,之后會在當前目錄下生成對應文件夾 hexo init <文件名字> cd 文件名字 npm install
可以看到安裝好之后的一個目錄結構:
目錄文件說明:
_config.yml:網站的配置信息,您可以在此配置大部分的參數。
package.json:應用程序的信息。EJS, Stylus 和 Markdown renderer 已默認安裝,您可以自由移除。
scaffolds:模版文件夾。當您新建文章時Hexo 會根據 scaffold 來建立文件Hexo的模板是指在新建的文章文件中默認填充的內容。例如,如果您修改scaffold/post.md中的Front-matter內容,那么每次新建一篇文章時都會包含這個修改。
source:資源文件夾是存放用戶資源的地方。除 _posts
文件夾之外,開頭命名為 _
(下劃線)的文件 / 文件夾和隱藏的文件將會被忽略。Markdown 和 HTML 文件會被解析并放到 public
文件夾,而其他文件會被拷貝過去。
themes:主題 文件夾。Hexo 會根據主題來生成靜態頁面。
查看hexo的版本以及對應的數據:
3.2生成靜態文件,并開啟Hexo服務:
進入到了hexo的安裝目錄之后,使用hexo generate來生成靜態文件,也可以使用hexo g,之后使用hexo server(可以寫成hexo s)命令啟動服務,操作如下:
可以看到4000端口的服務已經開啟,之后在你的瀏覽器輸入http://<你的linux機器的ip地址或者服務器公網地址>:4000,如下可以看到最開始的一個界面:
4.初步使用Hexo:
使用前,我們對我們的站點進行一個配置,也就是我們創建的hexo目錄的_config.yml文件,可以修改的部分介紹如下:
# Site
title: QIMING.INFO #博客網站的標題
subtitle: #博客網站的副標題
description: #你的網站描述
keywords: #網站的關鍵詞
author: #作者的名字
language: #博客網站使用的語言
timezone: #網站時區
我自己的修改如下供大家參考,這里的修改沒有太大的限制:
4.1:開始使用Hexo發布自己的第一篇博客!
執行下面的目錄創建一篇新文章:
hexo new post <文章標題>
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9Tz5aBlT-1622032930755)(pictures/image-20210526145922392.png)]
這里我創建了一篇標題為First_Blog的博客,創建之后hexo目錄下面的source/_post文件夾下會產生一個First_Blog.md的文件
4.2:編輯文章
進入到上面說的那個目錄下可以看到我們創建的博客文件:
直接使用vim或者vi就可以對我們的博客文章進行編輯了,打開此First_Blog.md后可以看到—分隔的區域,這部分主要對文章進行標注變量,如下:
title:標題
tage:標簽
categories:分類
date:時間
這些標注大家在-----區域可以進行使用
4.3:發布文章
輸入如下命令,生成靜態網頁,靜態網頁會存放在public文件下
hexo g
hexo s
之后就可以去瀏覽器訪問了!可以看到我們發布的文章已經成功在瀏覽器顯示,到這里個人博客網站就已經成功搭建了。
5.主題的選擇:
主題網站:https://hexo.io/themes/ hexo提供了大量精美的主題供我們選擇,選擇喜歡的主題,在hexo目錄下的themes文件夾下使用git clone下載主題,之后再配置文件_config.yml把theme后面修改成下載的主題的名字,之后運行hexo clean ,hexo g即可看到生效的主題。
如果是有服務器的小伙伴,也可以將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
下載編譯安裝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 #編譯安裝
啟動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
之后我們需要配置服務器公網ip,編輯配置文件。
之后再重啟nginx服務,開啟hexo服務,這個時候使用公網的ip就可以訪問到我們的hexo服務了!
藍藍設計建立了UI設計分享群,每天會分享國內外的一些優秀設計,如果有興趣的話,可以進入一起成長學習,請掃碼藍小助,報下信息,藍小助會請您入群。歡迎您加入噢~~希望得到建議咨詢、商務合作,也請與我們聯系。
部分借鑒自:csdn
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
ES6, 全稱 ECMAScript 6.0 ,是 JavaScript 的下一個版本標準,2015.06 發版
雖然15年就有正式版本了,但是國內普遍商用是在2018年之后去了,甚至到現在有很多前端仍然搞不懂ES6(都2021年了,兄dei~)
ES6 的出現主要是為了解決 ES5 的先天不足,比如 JavaScript 里并沒有類的概念
目前存在少數低版本瀏覽器的 JavaScript 是 ES5 版本,大多數的瀏覽器已經支持 ES6
ES6提供了大量的語法糖,讓你寫代碼的時候簡直不要太爽!
你必須要知道的是:現在各企業都普遍使用,不會ES6意味著你很難找到工作,上班了你連別人的代碼都看不懂
1.1 let 與 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();
let不會存在上述問題:
// 1. 不會存在聲明提前 // 此處會報錯(這里必須報錯,原則上來說不能先上車后買票) console.log(name); let name = "大帥比"; // 2. 不會有變量覆蓋 let demo = "小明"; let demo = "小紅"; // 此處會報錯(不能使用套牌車?。└嬖V你已經定義了此變量。避免了項目中存在變量覆蓋的問題 console.log(demo) // 3. 有塊級作用域 function fn2(){ for(let i = 0; i < 5; i++){ // do something } // 此處會報錯,無法打印,防止紅杏出墻?。?! // i是定義在循環體之內的,循環體外當然無法打印 console.log(i); } fn2();
const
const PI = "3.1415926";
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);
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}
3.1 普通字符串
// 普通字符串 let string = "hello"+"小兄弟"; // hello小兄弟 // 如果想要換行 let string = "hello'\n'小兄弟" // hello // 小兄弟
3.2 模板字符串
let str1 = "穿堂而過的"; let str2 = "風"; // 模板字符串 let newStr = `我是${str1}${str2}`; // 我是穿堂而過的風 console.log(newStr) // 字符串中調用方法 function fn3(){ return "帥的不行!"; } let string2= `我真是${fn3 ()}`; console.log(string2); // 我真是帥的不行!
4.1 箭頭函數
a. 基本用法
let fn = v => v;
//等價于
let fn = function(num){
return num;
}
fn(100); // 輸出100
b. 帶參數的寫法
let fn2 = (num1,num2) => {
let result = num1 + num2;
return result;
}
fn2(3,2); // 輸出5
c. 箭頭函數中的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
d. 箭頭函數適用的場景
let Person1 = {
'age': 18,
'sayHello': function () {
setTimeout(()=>{
console.log(this.age);
});
}
};
var age = 20;
Person1.sayHello(); // 18
4.2 函數參數的擴展
1. 默認參數
// num為默認參數,如果不傳,則默認為10 function fn(type, num=10){ console.log(type, num); } fn(1); // 打印 1,10 fn(1,2); // 打印 1,2 (此值會覆蓋默認參數10)
2. 不定參數
// 此處的values是不定的,且無論你傳多少個 function f(...values){ console.log(values.length); } f(1,2); // 2 f(1,2,3,4); // 4
5.1 類的定義
// 匿名類 let Demo = class { constructor(a) { this.a = a; } } // 命名類 let Demo = class Demo { constructor(a) { this.a = a; } }
5.2 類的聲明
class Demo { constructor(a) { this.a = a; } }
5.3 類的主體
class Demo{} Demo.prototype.a = 2;
class Demo { a = 2; constructor () { console.log(this.a); } }
class Demo{ constructor(){ console.log('我是構造器'); } } new Demo(); // 我是構造器
如果不寫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
6.1 Maps 和 Objects 的區別
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
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
6.4 Map 與 Array的轉換
letkvArray = [["key1", "value1"], ["key2", "value2"]]; // Map 構造函數可以將一個 二維 鍵值對數組轉換成一個 Map 對象 let myMap = new Map(kvArray); // 使用 Array.from 函數可以將一個 Map 對象轉換成一個二維鍵值對數組 let outArray = Array.from(myMap);
6.5 關于map的重點面試題
詳細解析:
性質決定了兩者應用場景的不同
let arr = ['a', 'b', 'c', 'd']; arr.forEach((val) => { console.log(val); // 依次打印出 a,b,c,d });
let arr = [1, 2, 3, 4, 5]; let arr2 = arr.map(num => num * 2).filter(num => num > 5); // arr2 = [6, 8, 10]
藍藍設計建立了UI設計分享群,每天會分享國內外的一些優秀設計,如果有興趣的話,可以進入一起成長學習,請掃碼藍小助,報下信息,藍小助會請您入群。歡迎您加入噢~~希望得到建議咨詢、商務合作,也請與我們聯系。
部分借鑒自:csdn
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
以前的百度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的官網了,最新版的Apache Echarts 是5.x的版本了。
官網大概就長下面的這個樣子。
然后點擊快速入門,我們先去把echarts安裝一下,按下圖所示進行操作。
作者的demo環境是用的vue-cli3的腳手架,將Echarts安裝到項目里
運行命令:
npm install echarts --save
//or yarn add echarts
安裝整個包到項目里
在項目里使用,先寫個測試用例,看看是否安裝成功了。
<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>
我們使用了一個官網示例的代碼,是最簡單版本的Echart原型。
https://echarts.apache.org/examples/zh/editor.html?c=bar-background
舉個栗子,假如我們拿到的UI的設計圖如下,需要我們做一個柱狀圖,這個柱狀圖需要下面的這種樣式(本文不做100%的還原,僅做常用屬性的舉例子)。
其實看到這里,可能覺得我們剛剛寫到的測試Demo和UI的設計不一樣。所以才有了我們怎么樣將官網的簡單Demo配置成UI圖一致。
怎么快速完成這個UI圖的還原呢?首先我們要做的是找到這個UI圖所屬的Echarts類,如下圖中所示,找到“示例”,再找到“柱狀圖”。這樣我們就可以在柱狀圖中再找到基礎配置項。就是如Demo中的一樣。
接下來就應該進行下一步的配置了,在配置這些屬性之前,你要先明白一點你的需求是啥。先看UI圖里的柱狀圖哪些地方是需要修改的,目前的肉眼所見“網格的樣式(需要改成虛線,全且顏色有變)、柱狀圖的顏色、需要有圖例、X和Y軸的刻度線不一樣”等等。
下一章節快速記住配置項的屬性。
首先我們記住這些屬性,就要對這些屬性進行一個分類。其實在官網中的《配置項手冊》已經分類的很細了,但是由于Echarts的靈活度非常高,就導致了配置項手冊的東西看起來就越來越多了,看久了就會導致“眼睛疲憊”。
廢話不多說,直接開始,其實這些英文單次就對應的屬性,稍微英文好點的就可以輕松點了,
按項目里常用的屬性排序,如下:
一級屬性(options.xxxx):
- 網格設置 ----- grid
![]()
{ grid: { borderColor: "rgba(222, 48, 48, 1)", show: true, backgroundColor: "rgba(188, 71, 71, 1)" } }
- X軸設置 ----- xAxis
![]()
{ 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' } } } }
- Y軸設置 ----- yAxis
![]()
yAxis: { type: 'value', axisLine: { show: !false, lineStyle: { //坐標軸顏色 color: '#E6EAF9' } }, splitLine: { //網格設置 lineStyle: { color: '#DADCFF', type: 'dashed' } } },
- 系列設置(系列的數據) ----- series
也不難理解,就是你需要設置哪種圖表的數據樣式,就在里面找到對應的type
- 全局字體樣式設置 ----- textStyle
這個也不難理解,設置的就是當前這個圖表全局的字體樣式,設置之后會覆蓋默認的字體樣式,這個也會有一個優先級別,就是 單獨的子屬性設置 > 全局樣式 > 默認
{ textStyle:{ color:'#f00' //設置全局的字體為紅色 } }
- 圖例設置 ----- 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" }] }
- 標題設置 ----- title
這里的標題可以分為主標題和副標題,可以使用show屬性去控制顯示隱藏。
{ title: { text: "Main Title", subtext: "Sub Title", left: "center", textStyle: { fontSize: 30, color: "rgba(225, 15, 15, 1)" }, subtextStyle: { fontSize: 20 } } }
- 提示設置(鼠標懸浮到圖上的交互樣式)----- 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)" } } }
- 字體設置----- textStyle
這里可能有些誤解了,子屬性的textStyle樣式一般是指在某個具體的熟悉里的字體樣式設置了,同js設置字體樣式的一樣。
![]()
yAxis: { type: "value", axisLabel: { //刻度標簽文字設置 fontSize: 18, // color: "rgba(235, 33, 33, 1)" } }
- 圖形樣式設置 ----- itemStyle
這個屬性的設置也是大部分屬性設置都有的,可以理解為設置某個屬性的幾何屬性。
xAxis: { axisLine: { lineStyle: { //坐標軸軸線樣式設置 color: "rgba(228, 13, 13, 1)", type: "dashed" } } }
- 線的樣式設置 ----- lineStyle
這個屬性主要就是這種這種視覺引導線的樣式的。
series: [{ type: "pie", labelLine: { lineStyle: { //引導線的樣式設置 color: "rgba(231, 16, 16, 1)", width: 2 }, length: 20 } }]
- 文本標簽設置 ----- 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 } }]
- 標簽的視覺引導線設置 ----- labelLine
這個屬性前面寫lineStyle的時候就已經提到過了。
- 顯示的位置設置 ----- (left、right、top、bottom)等,都是同定位屬性一樣
這里不難看出我們將原來在頂部居中的圖例移動到了左側往下一點的位置,就是通過這個幾個屬性來控制的,大部分與數據無關的提示類都有這些屬性,如:工具欄、標題、標簽等。
- 透明度設置 ----- opacity
這也很好理解,就是想要哪個部分透明,就往哪里寫。
legend: { itemStyle: { opacity: 0.1 } },
- 格式化設置 ----- formatter
![]()
上面這些都是常用的一些屬性設置,你學廢了嗎?
其實通過上面的一個小節不難看出,Echarts的一些屬性設置都是很有規律的,只要找到這些規律即可快速的上手Echarts了。這作為一個Echarts的系列的文章,主要目的是讓學習Echart的朋友可以快速上手,會持續進行更新的。
藍藍設計建立了UI設計分享群,每天會分享國內外的一些優秀設計,如果有興趣的話,可以進入一起成長學習,請掃碼藍小助,報下信息,藍小助會請您入群。歡迎您加入噢~~希望得到建議咨詢、商務合作,也請與我們聯系。
部分借鑒自:csdn 作者:狼丶宇先生
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
本文從零開始,逐步講解如何用react全家桶搭建一個完整的react項目。文中針對react、webpack、babel、react-route、redux、redux-saga的核心配置會加以講解,通過這個項目,可以系統的了解react技術棧的主要知識,避免搭建一次后面就忘記的情況。
代碼庫:https://github.com/teapot-py/react-demo
首先關于主要的npm包版本列一下:
思考一下webpack到底做了什么事情?其實簡單來說,就是從入口文件開始,不斷尋找依賴,同時為了解析各種不同的文件加載相應的loader,最后生成我們希望的類型的目標文件。
這個過程就像是在一個迷宮里尋寶,我們從入口進入,同時我們也會不斷的接收到下一處寶藏的提示信息,我們對信息進行解碼,而解碼的時候可能需要一些工具,比如說鑰匙,而loader就像是這樣的鑰匙,然后得到我們可以識別的內容。
回到我們的項目,首先進行項目的初始化,分別執行如下命令
mkdir react-demo // 新建項目文件夾
cd react-demo // cd到項目目錄下
npm init // npm初始化
引入webpack
npm i webpack --save
touch webpack.config.js
對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' // 定義輸出文件名稱
}
};
更新package.json文件,在scripts中添加webpack執行命令
"scripts": {
"dev": "./node_modules/.bin/webpack --config webpack.config.js"
}
如果有報錯請按提示安裝webpack-cli
npm i webpack-cli
執行webpack
npm run dev
如果在項目文件夾下生成了dist文件,說明我們的配置是沒有問題的。
安裝react相關包
npm install react react-dom --save
更新app.js入口文件
import React from 'react
import ReactDom from 'react-dom';
import App from './src/views/App';
ReactDom.render(<App />, document.getElementById('root'));
創建目錄 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;
在根目錄下創建模板文件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>
到了這一步其實關于react的引入就OK了,不過目前還有很多問題沒有解決
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
更新webpack.config.js
module: {
rules: [
{
test: /\.js$/, // 匹配.js文件
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
]
}
根目錄下創建并配置.babelrc文件
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
配置HtmlWebPackPlugin
這個插件最主要的作用是將js代碼通過
npm i html-webpack-plugin -D
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')
})
]
};
執行 npm run start,生成 dist文件夾
當前目錄結構如下
可以看到在dist文件加下生成了index.html文件,我們在瀏覽器中打開文件即可看到App組件內容。
webpack-dev-server可以極大的提高我們的開發效率,通過監聽文件變化,自動更新頁面
安裝 webpack-dev-server 作為 dev 依賴項
npm i webpack-dev-server -D
更新package.json的啟動腳本
“dev": "webpack-dev-server --config webpack.config.js --open"
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')
})
]
redux是用于前端數據管理的包,避免因項目過大前端數據無法管理的問題,同時通過單項數據流管理前端的數據狀態。
創建多個目錄
下面我們來通過redux實現一個計數器的功能
安裝依賴
npm i redux react-redux -D
在actions文件夾下創建index.js文件
export const increment = () => {
return {
type: 'INCREMENT',
};
};
在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;
更新store.js
import { createStore } from 'redux';
import incrementReducer from './reducers/index';
const store = createStore(incrementReducer);
export default store;
更新入口文件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'));
更新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
redux-saga通過監聽action來執行有副作用的task,以保持action的簡潔性。引入了sagas的機制和generator的特性,讓redux-saga非常方便地處理復雜異步問題。
redux-saga的原理其實說起來也很簡單,通過劫持異步action,在redux-saga中進行異步操作,異步結束后將結果傳給另外的action。
下面就接著我們計數器的例子,來實現一個異步的+1操作。
安裝依賴包
npm i redux-saga -D
新建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)
}
解釋下所做的事情,將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;
更新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);
觀察結果我們會發現如下報錯:
這是因為在redux-saga中用到了Generator函數,以我們目前的babel配置來說并不支持解析generator,需要安裝@babel/plugin-transform-runtime
npm install --save-dev @babel/plugin-transform-runtime
這里關于babel-polyfill、和transfor-runtime做進一步解釋
Babel默認只轉換新的JavaScript語法,而不轉換新的API。例如,Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局對象,以及一些定義在全局對象上的方法(比如Object.assign)都不會轉譯。如果想使用這些新的對象和方法,必須使用 babel-polyfill,為當前環境提供一個墊片。
Babel轉譯后的代碼要實現源代碼同樣的功能需要借助一些幫助函數,而這些幫助函數可能會重復出現在一些模塊里,導致編譯后的代碼體積變大。
Babel 為了解決這個問題,提供了單獨的包babel-runtime供編譯模塊復用工具函數。
在沒有使用babel-runtime之前,庫和工具包一般不會直接引入 polyfill。否則像Promise這樣的全局對象會污染全局命名空間,這就要求庫的使用者自己提供 polyfill。這些 polyfill一般在庫和工具的使用說明中會提到,比如很多庫都會有要求提供 es5的polyfill。
在使用babel-runtime后,庫和工具只要在 package.json中增加依賴babel-runtime,交給babel-runtime去引入 polyfill 就行了;
詳細解釋可以參考
Babel插件一般盡可能拆成小的力度,開發者可以按需引進。比如對ES6轉ES5的功能,Babel官方拆成了20+個插件。
這樣的好處顯而易見,既提高了性能,也提高了擴展性。比如開發者想要體驗ES6的箭頭函數特性,那他只需要引入transform-es2015-arrow-functions插件就可以,而不是加載ES6全家桶。
但很多時候,逐個插件引入的效率比較低下。比如在項目開發中,開發者想要將所有ES6的代碼轉成ES5,插件逐個引入的方式令人抓狂,不單費力,而且容易出錯。
這個時候,可以采用Babel Preset。
可以簡單的把Babel Preset視為Babel Plugin的集合。比如babel-preset-es2015就包含了所有跟ES6轉換有關的插件。
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": false,
"helpers": true,
"regenerator": true,
"useESModules": false
}
]
]
}
點擊按鈕會在2秒后執行+1操作。
在web應用開發中,路由系統是不可或缺的一部分。在瀏覽器當前的URL發生變化時,路由系統會做出一些響應,用來保證用戶界面與URL的同步。隨著單頁應用時代的到來,為之服務的前端路由系統也相繼出現了。而react-route則是與react相匹配的前端路由。
引入react-router-dom
npm install --save react-router-dom -D
更新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'));
更新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);
點擊列表可以跳轉相關路由
至此,我們已經一步步的,完成了一個簡單但是功能齊全的react項目的搭建,下面回顧一下我們做的工作
麻雀雖小,五臟俱全,希望通過最簡單的代碼快速的理解react工具鏈。其實這個小項目中還是很多不完善的地方,比如說樣式的解析、Eslint檢查、生產環境配置,雖然這幾項是一個完整項目不可缺少的部分,但是就demo項目來說,對我們理解react工具鏈可能會有些干擾,所以就不在項目中加了。
后面會新建一個分支,把這些完整的功能都加上,同時也會對當前的目錄結構進行優化。
藍藍設計建立了UI設計分享群,每天會分享國內外的一些優秀設計,如果有興趣的話,可以進入一起成長學習,請掃碼藍小助,報下信息,藍小助會請您入群。歡迎您加入噢~~希望得到建議咨詢、商務合作,也請與我們聯系。
部分借鑒自:csdn 作者:鄭清
原文鏈接:
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
藍藍設計的小編 http://www.syprn.cn