-
数据可视化大屏 前端屏幕多分辨率适配方案(vue,echarts)
2020-12-09 23:51:51数据可视化大屏 前端... 很多人好奇, " 你为什么要学易语言, 垃圾语言 " , 当时是实在看不懂英语, 但是对编程(当时的理解就是编程)很有兴趣, 非常想学. 现在回想从 c语言 易语言 vb javascript java python , 一路过数据可视化大屏 前端屏幕多分辨率适配方案(vue)
写在前面:
第一次写博客, csdn账号注册很久了, 应该是2010年注册的, 当时我还在上高中, 当时还在写易语言的, 有些问题搞不懂的会来csdn看大佬是怎么解决的, 也写了些没什么用的小工具上传到csdn, 当然现在都在用git了. 很多人好奇, " 你为什么要学易语言, 垃圾语言 " , 当时是实在看不懂英语, 但是对编程(当时的理解就是编程)很有兴趣, 非常想学.
现在回想从 c语言 易语言 vb javascript java python , 一路过来都在学习, 但是好像从来没有写过什么东西, 遇到过无数的bug, 掉了无数根头发, 现在大学毕业了, 赶上了2020年的疫情, 这次经历让我对生命有了新的看法, 也是时候静下心来写些东西, 沉淀一下自己的历程了! 第一次写博客不知道写什么, 胡乱写了这么一段, 留在这里, 反正也没有人看, 回头再看到自己第一篇博客的时候, 希望不忘初心!项目代码链接: gitee 代码链接
一直在写
react
的, 新到一家公司, 同事都是写vue
, 改写vue
不太习惯, 觉得还是react
用起来更灵活更顺手一些. 好久没写前端了, 现在也回忆一下前端适配, 也回忆一下vue
的写法项目有一个数据可视化大屏的需求, 要展示一些数字资源的使用情况,里面有一些
echarts
的图表,使用量一般是用仪表盘的形式,使用情况是一段时间数据的柱状图.
这个项目是由我同事来写的, 他的习惯是直接按照设计稿的px像素直接写到页面上, 在电脑上预览的时候没有什么问题, 但是这个项目要部署在一块很大的大屏上的, 这个时候就发现了问题所在, 屏幕不适配!!!
我也是刚来到这个公司和那个同事关系比较好, 我的工作也基本完成了, 所以我决定帮帮他. 选择一个合适的适配方案然后还需要快速的把代码完成改版, 最终我用java写了一个代码转换工具, 一键帮同事把代码转为适配
方案选择
- px 转 rem
- viewpoint
- 媒体查询 @media
- 计算屏幕缩放比 动态设置像素值
每个人有不同的适配经验, 我这个同事适配经验比较少, 之前写小程序适配是用的
rpx
, 这个类似于rem
了.
备选方案1: px转rem
px 转 rem
是基于页面的fontSize 设置一个rem
与px
换算比例 比如16px=1rem
,20px=1rem
根据不同的屏幕设计不同的, 页面fontSize, 在移动端开发中这种方案非常常见.html { /* 普通状态 */ font-size: 20px } html { /* 1.5倍分辨率 */ font-size: 30px } html { /* 2倍分辨率 */ font-size: 40px } .div-box { width: 5rem; /* 5倍的font-size 普通状态下 = 100px */ }
但是当前的项目可能并不适用:
- 页面中有其他已经开发有其他的元素有导航文字, 设置fontSize时会影响到页面中已经写好的内容
- 页面中使用了
echarts
图表, 里面的参数没办法应用rem
的比例
备选方案2: 媒体查询
媒体查询是比较常见的屏幕适配方案了, 可以根据不同的屏幕大小提供不同的样式方案, 媒体查询可以很好的支持多数的pc端网页布局需要了.
@media only screen and (max-width: 1000px) { .div-class { width: 720px; } }
但是问题也是比较明显:
- 大量书写媒体查询代码, 比较繁琐
- 针对多种屏幕进行适配, 也无法保证完全兼容所有的屏幕
- 也无法支持
echarts
图表中的参数进行适配
备选方案3: viewpoint 视口
viewpoint
基本是目前多数移动端开发都会使用的适配方式, 可以设置对移动端设备的的界面进行整体的缩放, 这种方式的适配是最佳的方案. 但是缺点是很明显的, 只能在移动端进行viewpoint
适配, 我们目前的数据大屏项目就没办法用了.<meta name="viewport" content="target-densitydpi=high-dpi" />
## 最终采用方案: 计算屏幕缩放比 我们的设计稿宽高比是 `1920 * 960` 由于这个数据可视化的项目是适配宽屏的, 我可以先铺满高然后屏幕左右可能会有空白, 空白的部分用背景图片填充就好了. 画面的布局像素依然使用设计标注的像素值然后再乘屏幕缩放比.页面适配样例代码(vue) :
<template> <div class="chart-container" :class="chartContainer"> <div :style="[{width:202*rate+'px',height:184*rate+'px',marginLeft:134*rate+'px',marginTop:40*rate+'px',}]"> </div> </div> </template> <script> // 宽高比 const scale = 1920 / 960; // 屏幕导航高度 const headerHeight = 47; // 标签栏高度 const tabHeight = 27; // 标签栏间隔 const pageMargin = 5; // 设计稿高度 const designHeight = 960; // 画面上方间隔高度 const marginTop = headerHeight + tabHeight + pageMargin; // 画布下方间隔高度 const marginBottom = pageMargin; // 页面宽度 const clientWidth = document.body.clientWidth; // 页面高度 const windowHeight = document.body.clientHeight; // 面试高度去年 上方间隔 下方间隔 const clientHeight = windowHeight - marginTop - marginBottom; // 画面高度 const innerHeight = clientHeight; // 缩放比率 const rate = innerHeight / designHeight; // 画面宽度 const centerWidth = clientHeight * scale; // 画面左右侧空白宽度 const paddingWidth = (((clientWidth - pageMargin - pageMargin) - (clientHeight * scale)) / 2) export default{ data:()=>({ chartContainer: {height: 181 * rate + 'px',}, }), methods:{ dataOtherEChart (eleId, label, value, itemValue, color, color1, temp3) { const _self = this; let chartEle = _self.$echarts.init(document.getElementById(eleId)); let option = { title: { textAlign: 'center', textStyle: { rich: { num: { fontSize: 25 * rate,}, key: { fontSize: 15 * rate,}} }, subtextStyle: { lineHeight: 30 * rate, fontSize: 15 * rate } } }; chartEle.setOption(option, true); }, } } </script>
## 改造前代码 有些是写在行内的 `style` ```html
有些是使用了css 样式定义的:
.box-to-box{ height: 100px; width: 85%; margin-top: 49px; margin-left: 60px; display: flex; }
把高度 间距 都设计成了设计稿里面的像素值, 他好像还不太会用flex 弹性盒布局, 这里的
display:flex
也没有生效echarts 参数:
let option = { title: { subtextStyle: { lineHeight: 30, fontSize: 15 } }, }}
这里的参数是没有单位的也需要按缩放比缩放
vue 代码转换工具
用代码转换工具将写死的像素值乘以缩放比例
gitee 代码连接
1.读取vue文件, 定义文件行链表 class的映射
fileReader = new FileReader(url); // 读取文件 bufferedReader = new BufferedReader(fileReader); // 结果文本 StringBuilder resultText = new StringBuilder(); // 行链表 用于查找 class样式名称 LinkedList<String> lineList = new LinkedList<>(); // class样式映射 Map<String, Map<String, String>> classMap = new HashMap<>();
2.遍历行, 定义样式识别的正则表达式
// 每行插入链表头 lineList.addFirst(line); // class样式 识别正则 Matcher classMatcher = Pattern.compile(".*?-?.*?:.*?px.*?;").matcher(line); // id class 绑定样式 识别正则 Matcher classUseMatcher = Pattern.compile("(class|id)=\"([0-9a-z-])*?\"").matcher(line);
3.处理style 有px的位置乘以
rate
if (line.contains("style=\"")) { // 处理style // 行文本头部加入结果文本 resultText.append(line, 0, line.indexOf("style=\"")); // style 代码正则 Pattern pattern = Pattern.compile("style=\".*?\""); Matcher matcher = pattern.matcher(line); // 将 style="name:value;" 转为 :style="[{name:value}]" resultText.append(":style=\""); while (matcher.find()) { String styleStr = matcher.group(); styleStr = styleStr.replace("style=\"", "").replace("\"", ""); resultText.append(parseStyleList(styleStr)); } resultText.append("\""); String[] tailArr = pattern.split(line); // 行文本尾部 加入结果文本 if (tailArr.length != 0 && tailArr.length > 1) { resultText.append(tailArr[1]); } }
4.处理class样式
class
样式表转为hashMap
有px乘以rate
if (classMatcher.find()) { // 处理class样式 // 遍历查找 class 名称 for (String classNameLine : lineList) { // 查询 .class-name #id-name 样式定义 不支持 tag-name if (classNameLine.contains("{") && (classNameLine.contains(".") || classNameLine.contains("#"))) { String className = classNameLine.trim().replace(".", "").replace("#", "").replace("{", ""); // 横线转驼峰 className = lineToHump(className); // 如果是多重定义的class 只保留一个 if (className.contains(" ")) { className = className.split(" ")[0]; } // 处理样式键值对 String styleStr = classMatcher.group().trim().replace(";", ""); String[] styleArr = parseStyle(styleStr).replace(",", "").split(":"); // class 键值对映射 Map<String, String> innerClassMap = classMap.get(className); if (innerClassMap == null) { innerClassMap = new HashMap<>(); } // class 键值对映射加入 class样式映射 innerClassMap.put(styleArr[0], styleArr[1]); classMap.put(className, innerClassMap); break; } } }
5.使用
class="class-name"
的地方 加入:class="className"
if (classUseMatcher.find()) { String classUseStr = classUseMatcher.group(); String classUseHumpStr = lineToHump(classUseStr.replace("class=", "").replace("id=", "").replaceAll("\"", "")); // 行文本头部加入结果文本 resultText.append(line, 0, line.indexOf(classUseStr)); resultText.append(classUseStr); resultText.append(" :class=\""); // class 转 v-bind:class 横线命名转驼峰 resultText.append(classUseHumpStr); resultText.append("\""); // 行文本尾部加入结果文本 resultText.append(line, line.indexOf(classUseStr) + classUseStr.length(), line.length()); }
6.vue data中加入 缩放比率
rate
组件中 有rate
会自动缩放StringBuffer dataBuffer = new StringBuffer(); Matcher dataMatcher = Pattern.compile("data.*?\n.*?return.*?\\{", Pattern.MULTILINE).matcher(resultText); if (dataMatcher.find()) { dataMatcher.appendReplacement(dataBuffer, "data: function () {\n" + " return {\n" + " rate,\n"); for (String key : classMap.keySet()) { Map<String, String> innerClassMap = classMap.get(key); dataBuffer.append(" "); dataBuffer.append(key); dataBuffer.append(": {"); for (String innerKey : innerClassMap.keySet()) { dataBuffer.append(innerKey); dataBuffer.append(": "); dataBuffer.append(innerClassMap.get(innerKey)); dataBuffer.append(","); } // stringBuffer.append(" "); dataBuffer.append("},\n"); } } dataMatcher.appendTail(dataBuffer); resultText = new StringBuilder(dataBuffer);
7.常量加入script中
String rateDefineStr = "\n" + " const scale = 16 / 9\n" + " const headerHeight = 47;\n" + " const tabHeight = 27;\n" + " const tabPadding = 5;\n" + " const designHeight=1080;\n" + " const marginTop = headerHeight + tabHeight + tabPadding;\n" + " const marginBottom = tabPadding;\n" + " const clientWidth = document.body.clientWidth\n" + " const windowHeight = document.body.clientHeight;\n" + " const clientHeight = windowHeight - marginTop - marginBottom;\n" + " const innerHeight = clientHeight;\n" + " const rate = innerHeight / designHeight\n" + " const centerWidth = clientHeight * scale;\n" + " const paddingWidth = (((clientWidth - 5 - 5) - (clientHeight * scale)) / 2);" + "\n ;\n"; StringBuffer constBuffer = new StringBuffer(); Matcher constMatcher = Pattern.compile("export default \\{", Pattern.MULTILINE).matcher(resultText); if (constMatcher.find()) { constMatcher.appendReplacement(constBuffer, rateDefineStr); constBuffer.append(" export default {"); constMatcher.appendTail(constBuffer); System.out.println(constBuffer); }
8.ecahrts 中的参数可以乘以
rate
常量let option = { title: { subtextStyle: { lineHeight: 30 * rate , fontSize: 15 * rate } }, }}
代码中有些设计没有解释, 太晚了准备睡觉, 后续有空会再更新博客, 做一些思路上面的分享, 如果有遇到同样问题或者有疑问的朋友可以联系我, 这是我的第一篇博客中存在的问题也感谢大家能够指正.
-
[数据可视化] 数据大屏 前端屏幕多分辨率适配方案(vue,echarts)
2020-12-10 09:11:20数据可视化大屏 前端屏幕多分辨率... 很多人好奇, " 你为什么要学易语言, 垃圾语言 " , 当时是实在看不懂英语, 但是对编程(当时的理解就是编程)很有兴趣, 非常想学. 现在回想从 c语言 易语言 vb javascript java pytho数据可视化大屏 前端屏幕多分辨率适配方案(vue,charts)
写在前面:
第一次写博客, csdn账号注册很久了, 应该是2010年注册的, 当时我还在上高中, 当时还在写易语言的, 有些问题搞不懂的会来csdn看大佬是怎么解决的, 也写了些没什么用的小工具上传到csdn, 当然现在都在用git了. 很多人好奇, " 你为什么要学易语言, 垃圾语言 " , 当时是实在看不懂英语, 但是对编程(当时的理解就是编程)很有兴趣, 非常想学.
现在回想从 c语言 易语言 vb javascript java python , 一路过来都在学习, 但是好像从来没有写过什么东西, 遇到过无数的bug, 掉了无数根头发, 现在大学毕业了, 赶上了2020年的疫情, 这次经历让我对生命有了新的看法, 也是时候静下心来写些东西, 沉淀一下自己的历程了! 第一次写博客不知道写什么, 胡乱写了这么一段, 留在这里, 反正也没有人看, 回头再看到自己第一篇博客的时候, 希望不忘初心!项目代码链接: gitee 代码链接
一直在写
react
的, 新到一家公司, 同事都是写vue
, 改写vue
不太习惯, 觉得还是react
用起来更灵活更顺手一些. 好久没写前端了, 现在也回忆一下前端适配, 也回忆一下vue
的写法项目有一个数据可视化大屏的需求, 要展示一些数字资源的使用情况,里面有一些
echarts
的图表,使用量一般是用仪表盘的形式,使用情况是一段时间数据的柱状图.
这个项目是由我同事来写的, 他的习惯是直接按照设计稿的px像素直接写到页面上, 在电脑上预览的时候没有什么问题, 但是这个项目要部署在一块很大的大屏上的, 这个时候就发现了问题所在, 屏幕不适配!!!
我也是刚来到这个公司和那个同事关系比较好, 我的工作也基本完成了, 所以我决定帮帮他. 选择一个合适的适配方案然后还需要快速的把代码完成改版, 最终我用java写了一个代码转换工具, 一键帮同事把代码转为适配
方案选择
- px 转 rem
- viewpoint
- 媒体查询 @media
- 计算屏幕缩放比 动态设置像素值
每个人有不同的适配经验, 我这个同事适配经验比较少, 之前写小程序适配是用的
rpx
, 这个类似于rem
了.
备选方案1: px转rem
px 转 rem
是基于页面的fontSize 设置一个rem
与px
换算比例 比如16px=1rem
,20px=1rem
根据不同的屏幕设计不同的, 页面fontSize, 在移动端开发中这种方案非常常见.html { /* 普通状态 */ font-size: 20px } html { /* 1.5倍分辨率 */ font-size: 30px } html { /* 2倍分辨率 */ font-size: 40px } .div-box { width: 5rem; /* 5倍的font-size 普通状态下 = 100px */ }
但是当前的项目可能并不适用:
- 页面中有其他已经开发有其他的元素有导航文字, 设置fontSize时会影响到页面中已经写好的内容
- 页面中使用了
echarts
图表, 里面的参数没办法应用rem
的比例
备选方案2: 媒体查询
媒体查询是比较常见的屏幕适配方案了, 可以根据不同的屏幕大小提供不同的样式方案, 媒体查询可以很好的支持多数的pc端网页布局需要了.
@media only screen and (max-width: 1000px) { .div-class { width: 720px; } }
但是问题也是比较明显:
- 大量书写媒体查询代码, 比较繁琐
- 针对多种屏幕进行适配, 也无法保证完全兼容所有的屏幕
- 也无法支持
echarts
图表中的参数进行适配
备选方案3: viewpoint 视口
viewpoint
基本是目前多数移动端开发都会使用的适配方式, 可以设置对移动端设备的的界面进行整体的缩放, 这种方式的适配是最佳的方案. 但是缺点是很明显的, 只能在移动端进行viewpoint
适配, 我们目前的数据大屏项目就没办法用了.<meta name="viewport" content="target-densitydpi=high-dpi" />
最终采用方案: 计算屏幕缩放比
我们的设计稿宽高比是
1920 * 960
由于这个数据可视化的项目是适配宽屏的, 我可以先铺满高然后屏幕左右可能会有空白, 空白的部分用背景图片填充就好了. 画面的布局像素依然使用设计标注的像素值然后再乘屏幕缩放比.页面适配样例代码(vue) :
<template> <div class="chart-container" :class="chartContainer"> <div :style="[{width:202*rate+'px',height:184*rate+'px',marginLeft:134*rate+'px',marginTop:40*rate+'px',}]"> </div> </div> </template> <script> // 宽高比 const scale = 1920 / 960; // 屏幕导航高度 const headerHeight = 47; // 标签栏高度 const tabHeight = 27; // 标签栏间隔 const pageMargin = 5; // 设计稿高度 const designHeight = 960; // 画面上方间隔高度 const marginTop = headerHeight + tabHeight + pageMargin; // 画布下方间隔高度 const marginBottom = pageMargin; // 页面宽度 const clientWidth = document.body.clientWidth; // 页面高度 const windowHeight = document.body.clientHeight; // 面试高度去年 上方间隔 下方间隔 const clientHeight = windowHeight - marginTop - marginBottom; // 画面高度 const innerHeight = clientHeight; // 缩放比率 const rate = innerHeight / designHeight; // 画面宽度 const centerWidth = clientHeight * scale; // 画面左右侧空白宽度 const paddingWidth = (((clientWidth - pageMargin - pageMargin) - (clientHeight * scale)) / 2) export default{ data:()=>({ chartContainer: {height: 181 * rate + 'px',}, }), methods:{ dataOtherEChart (eleId, label, value, itemValue, color, color1, temp3) { const _self = this; let chartEle = _self.$echarts.init(document.getElementById(eleId)); let option = { title: { textAlign: 'center', textStyle: { rich: { num: { fontSize: 25 * rate,}, key: { fontSize: 15 * rate,}} }, subtextStyle: { lineHeight: 30 * rate, fontSize: 15 * rate } } }; chartEle.setOption(option, true); }, } } </script>
改造前代码
有些是写在行内的
style
<div id="top-item1" class="chart-container"> <div id="main11" style="width: 80%;height: 184px;margin-left: 134px;margin-top: 40px"></div> <div id="other11" style="width: 80%;height: 165px;margin-left: 138px;margin-top: 40px"></div> <div id="other12" style="width: 80%;height: 165px;margin-left: 120px;margin-top: 40px"></div> <div id="other13" style="width: 80%;height: 165px;margin-left: 120px;margin-top: 40px"></div> </div>
高度直接使用了设计稿中的像素值
165px
有些是使用了css 样式定义的:
.box-to-box{ height: 100px; width: 85%; margin-top: 49px; margin-left: 60px; display: flex; }
把高度 间距 都设计成了设计稿里面的像素值, 他好像还不太会用flex 弹性盒布局, 这里的
display:flex
也没有生效echarts 参数:
let option = { title: { subtextStyle: { lineHeight: 30, fontSize: 15 } }, }}
这里的参数是没有单位的也需要按缩放比缩放
vue 代码转换工具
用代码转换工具将写死的像素值乘以缩放比例
gitee 代码连接
1.读取vue文件, 定义文件行链表 class的映射
fileReader = new FileReader(url); // 读取文件 bufferedReader = new BufferedReader(fileReader); // 结果文本 StringBuilder resultText = new StringBuilder(); // 行链表 用于查找 class样式名称 LinkedList<String> lineList = new LinkedList<>(); // class样式映射 Map<String, Map<String, String>> classMap = new HashMap<>();
2.遍历行, 定义样式识别的正则表达式
// 每行插入链表头 lineList.addFirst(line); // class样式 识别正则 Matcher classMatcher = Pattern.compile(".*?-?.*?:.*?px.*?;").matcher(line); // id class 绑定样式 识别正则 Matcher classUseMatcher = Pattern.compile("(class|id)=\"([0-9a-z-])*?\"").matcher(line);
3.处理style 有px的位置乘以
rate
if (line.contains("style=\"")) { // 处理style // 行文本头部加入结果文本 resultText.append(line, 0, line.indexOf("style=\"")); // style 代码正则 Pattern pattern = Pattern.compile("style=\".*?\""); Matcher matcher = pattern.matcher(line); // 将 style="name:value;" 转为 :style="[{name:value}]" resultText.append(":style=\""); while (matcher.find()) { String styleStr = matcher.group(); styleStr = styleStr.replace("style=\"", "").replace("\"", ""); resultText.append(parseStyleList(styleStr)); } resultText.append("\""); String[] tailArr = pattern.split(line); // 行文本尾部 加入结果文本 if (tailArr.length != 0 && tailArr.length > 1) { resultText.append(tailArr[1]); } }
4.处理class样式
class
样式表转为hashMap
有px乘以rate
if (classMatcher.find()) { // 处理class样式 // 遍历查找 class 名称 for (String classNameLine : lineList) { // 查询 .class-name #id-name 样式定义 不支持 tag-name if (classNameLine.contains("{") && (classNameLine.contains(".") || classNameLine.contains("#"))) { String className = classNameLine.trim().replace(".", "").replace("#", "").replace("{", ""); // 横线转驼峰 className = lineToHump(className); // 如果是多重定义的class 只保留一个 if (className.contains(" ")) { className = className.split(" ")[0]; } // 处理样式键值对 String styleStr = classMatcher.group().trim().replace(";", ""); String[] styleArr = parseStyle(styleStr).replace(",", "").split(":"); // class 键值对映射 Map<String, String> innerClassMap = classMap.get(className); if (innerClassMap == null) { innerClassMap = new HashMap<>(); } // class 键值对映射加入 class样式映射 innerClassMap.put(styleArr[0], styleArr[1]); classMap.put(className, innerClassMap); break; } } }
5.使用
class="class-name"
的地方 加入:class="className"
if (classUseMatcher.find()) { String classUseStr = classUseMatcher.group(); String classUseHumpStr = lineToHump(classUseStr.replace("class=", "").replace("id=", "").replaceAll("\"", "")); // 行文本头部加入结果文本 resultText.append(line, 0, line.indexOf(classUseStr)); resultText.append(classUseStr); resultText.append(" :class=\""); // class 转 v-bind:class 横线命名转驼峰 resultText.append(classUseHumpStr); resultText.append("\""); // 行文本尾部加入结果文本 resultText.append(line, line.indexOf(classUseStr) + classUseStr.length(), line.length()); }
6.vue data中加入 缩放比率
rate
组件中 有rate
会自动缩放StringBuffer dataBuffer = new StringBuffer(); Matcher dataMatcher = Pattern.compile("data.*?\n.*?return.*?\\{", Pattern.MULTILINE).matcher(resultText); if (dataMatcher.find()) { dataMatcher.appendReplacement(dataBuffer, "data: function () {\n" + " return {\n" + " rate,\n"); for (String key : classMap.keySet()) { Map<String, String> innerClassMap = classMap.get(key); dataBuffer.append(" "); dataBuffer.append(key); dataBuffer.append(": {"); for (String innerKey : innerClassMap.keySet()) { dataBuffer.append(innerKey); dataBuffer.append(": "); dataBuffer.append(innerClassMap.get(innerKey)); dataBuffer.append(","); } // stringBuffer.append(" "); dataBuffer.append("},\n"); } } dataMatcher.appendTail(dataBuffer); resultText = new StringBuilder(dataBuffer);
7.常量加入script中
String rateDefineStr = "\n" + " const scale = 16 / 9\n" + " const headerHeight = 47;\n" + " const tabHeight = 27;\n" + " const tabPadding = 5;\n" + " const designHeight=1080;\n" + " const marginTop = headerHeight + tabHeight + tabPadding;\n" + " const marginBottom = tabPadding;\n" + " const clientWidth = document.body.clientWidth\n" + " const windowHeight = document.body.clientHeight;\n" + " const clientHeight = windowHeight - marginTop - marginBottom;\n" + " const innerHeight = clientHeight;\n" + " const rate = innerHeight / designHeight\n" + " const centerWidth = clientHeight * scale;\n" + " const paddingWidth = (((clientWidth - 5 - 5) - (clientHeight * scale)) / 2);" + "\n ;\n"; StringBuffer constBuffer = new StringBuffer(); Matcher constMatcher = Pattern.compile("export default \\{", Pattern.MULTILINE).matcher(resultText); if (constMatcher.find()) { constMatcher.appendReplacement(constBuffer, rateDefineStr); constBuffer.append(" export default {"); constMatcher.appendTail(constBuffer); System.out.println(constBuffer); }
8.ecahrts 中的参数可以乘以
rate
常量let option = { title: { subtextStyle: { lineHeight: 30 * rate , fontSize: 15 * rate } }, }}
代码中有些设计没有解释, 太晚了准备睡觉, 后续有空会再更新博客, 做一些思路上面的分享, 如果有遇到同样问题或者有疑问的朋友可以联系我, 这是我的第一篇博客中存在的问题也感谢大家能够指正.
-
这份书单会告诉你,Java网络编程其实很重要
2020-05-14 08:01:08其实就是Java网络编程,为什么呢,因为如果我想写一个Java Web项目,我只要用SSM就可以轻松搞定,写好我们的controller、service和dao就可以了,也就是只需要关心业务逻辑,不需要关心前端请求的路由、甚至是后端的...Java工程师往往容易忽视的一块知识点,其实就是Java网络编程,为什么呢,因为如果我想写一个Java Web项目,我只要用SSM就可以轻松搞定,写好我们的controller、service和dao就可以了,也就是只需要关心业务逻辑,不需要关心前端请求的路由、甚至是后端的负载均衡和网络请求处理,因为这些东西很多时候都被Nginx和Tomcat给吃掉了,Nginx帮我们做好了负载均衡,Tomcat则帮我们完成TCP连接的建立,HTTP请求的处理,把所有复杂的技术细节都给屏蔽了。
不过随着技术发展和更迭,大公司对于人才的要求也越来越高,对于高并发服务端编程能力的要求也在提高,比如在直播、实时通讯、游戏服务端开发等技术领域,通信协议和网络编程就成为了很重要的一个技术课题,相应的在Java领域,我们就必须要了解NIO、Linux epoll以及Netty等和网络通信相关的技术。如果你想做基础技术研发,比如消息队列、RPC框架的研发,那么网络编程也是必备的基础能力。
那么今天我们就借此机会,来介绍几本关于Java网络编程方面的优质书籍,以帮助大家更好地掌握这方面的知识,我们将从Java Web出发,依次介绍NIO网络编程、Tomcat的设计原理,以及Netty这类通信编程框架领域的权威书籍。
Java网络编程系列书单
深入分析JavaWeb技术内幕
点击书籍图片即可查看对应思维导图!
这本书是Java Web的集大成之作,涵盖了大部分Java Web开发的知识点,作者是资深的淘宝Java工程师,恨不得在一本书里把所有的Java Web知识点丢给讲清楚,不过,一本书显然无法把所有细节都讲完,但是作为Java Web的入门或者进阶书籍来看的话还是很不错的。
Java网络编程其实和Java web息息相关,Java Web的技术其实很大程度上都是基于Java网络编程来实现的,只不过Tomcat已经把网络编程的事情做好了,于是你需要做的就是通过spring等一些Javaweb框架来完成业务代码的开发。但如果想要深入了解Java网络编程,光会这些还不够。这本书不仅介绍了JavaWeb技术栈的核心内容,也可以帮助我们打开Java网络编程世界的大门,
作者介绍:
许令波,毕业于合肥工业大学,获计算机硕士学位。热爱Java Web技术,关注服务端性能优化,热衷开源技术的研究和分享,曾获developerWorks最佳作者称号。2009年进入淘宝工作,目前从事模板渲染框架与MVC框架的开发与应用、Java Web的性能优化、高访问量系统静态化和商品详情系统的业务改造等工作。
NIO与socket编程技术指南
点击书籍图片即可查看对应思维导图!
想要学习Java网络编程,首先你应该学的就是socket和NIO,在过去,Java还没有NIO的时代,我们使用socket建立连接,用BIO也就是阻塞IO来完成服务端的网络编程,后来NIO出现了以后,基于NIO的各种框架和Web容器也逐渐更新换代,比如netty网络编程框架,Tomcat容器等,都是用了NIO技术,了解了NIO,就是了解网络编程的第一步,而这也是一切Java网络编程框架的核心技术。
这本书主要介绍Java语言中高性能处理的原理技术:NIO和Socket。非常详细地讲解了NIO中的缓冲区、通道、选择器、编码,以及使用Socket技术实现TCP/IP和UDP编程,这对理解基于NIO和Socket技术为基础所开发的NIO框架是非常有好处的,在互联网技术日新月异的时代,Netty以及Kafka等这些高性能处理框架都在底层应用到了NIO和Socket,所以当你目前是有计划进军互联网技术时,本书也许会带给你一个方向。
作者简介
高洪岩,某世界500强项目经理,有10年Java相关开发经验,精通Java语言,擅长J2EE、EJB、Android、报表和多线程,以及并发相关的技术内容,理论与实践经验颇丰。著有《Java多线程编程核心技术》《Java并发编程:核心方法与框架》《NIO与Socket编程技术指南》《Java EE核心框架实战 第2版》《Jasper Reports+iReport报表开发详解》《Android学习精要》等书籍。
Tomcat架构解析
点击书籍图片即可查看对应思维导图!
作为一个Java工程师,想必你对于Tomcat这个web容器并不陌生,毕竟我们开发的大部分web应用都要运行在这只猫上面,那么你是否思考过,为什么Tomcat可以做到这一切呢,为什么不是你写好业务代码,直接在本地或者云端直接运行和部署,而是需要运行在一个Web容器上呢。其实Tomcat就是帮你把客户端发来的Web请求准确地投放到每个控制器上,如果你想要更深入了解其中原理,那么这本书可能值得你一读。
这本书全面介绍了Tomcat的架构、各组件的实现方案以及使用方式,主要包括Tomcat的基础组件架构以及工作原理,Tomcat各组件的实现方案、使用方式以及详细配置说明,Tomcat与Web服务器集成以及性能优化,Tomcat部分扩展特性介绍等,市面上关于Tomcat的书确实不多,这本书值得推荐。
作者简介
刘光瑞,北京窝客研发总监,负责窝客产品研发管理及总体架构设计。拥有十几年的企业级大型业务系统研发架构经验,成功带领团队设计并研发基于Tomcat的组件化微服务架构。2007年在四达软件担任高级架构师,主导了数个省份的广播电视省网业务运营支撑系统的架构设计及优化工作。2012年在电讯盈科担任高级技术顾问,参与了中国移动供应链系统的架构及研发。在应用系统架构及性能优化方面积累了丰富的经验。
netty权威指南
点击书籍图片即可查看对应思维导图!
讲完了Tomcat,接下来就到知名的异步网络编程框架netty了,netty其实就是一个对NIO进行包装的开源网络编程框架,它不需要你基于NIO去开发复杂的网络应用程序,而是直接通过一套非常易于使用的API直接把最实用的功能提供给开发者,像平时的业务开发工程师其实对于这类框架接触并不会太多,反而是做中间件、底层开发的同学会对这些东西更加关注,如果你有兴趣学习netty,那么这本书是一个不错的选择。
《Netty 权威指南(第2 版)》是异步非阻塞通信领域的经典之作,基于全新版本的Netty 5.0 编写,是国内首本深入介绍Netty 原理和架构的书籍,也是作者多年实战经验的总结和浓缩,内容不仅包含Java NIO入门知识、Netty 的基础功能开发指导、编解码框架定制等,还包括私有协议栈定制和开发、Netty 核心类库源码分析,以及Netty 的架构剖析。
作者简介
李林峰,Netty中国推广者,现华为技术有限公司平台中间件架构与设计部设计师,公司总裁技术创新奖获得者。长期从事高性能通信软件的架构设计和开发工作,有多年在NIO领域的设计、开发和运维经验,精通NIO编程和Netty、Mina等主流NIO框架。
如果想看更多技术好书,可以关注微信公众号【程序员书单】作者黄小斜,目前是阿里Java工程师,业余时间广泛读书,在公众号里除了分享程序员必读的技术书籍之外,也会推荐很多关于个人成长、投资理财等方面的书籍。你烦恼的每个问题,书中都有答案。
在这里,我们将为你推荐帮助程序员以及互联网从业者自我提升的各类好书、优质学习资源和工具,每周pick精品书单,解读经典书籍。
-
COLA :根据我的了解来看,很多公司的项目都是基于 COLA 进行开发的,相比于其他快速开发脚手架,COLA 并不提供什么已经开发好的功能,它提供的主要是一个干净的架构,然后你可以在此基础上进行开发。通过一行命令就...
-
-
简单的聊聊,顺便招前端
2020-11-28 22:23:08我们应该多想为什么这么做,他是怎么实现的,这么实现的好处,有没有更简洁的办法实现。之前看了很多优秀的大神的源码设计,然后我发现我在写代码的过程中开始模仿他们了,很多设计... -
Serverless 掀起新的前端技术变革
2020-12-02 19:54:47通常是后端工程师顺便写了前端页面。 <p><a name="34b9b83b"></a></p> 基于 AJAX 的前后端分离 <p>2005 年 AJAX 技术的正式提出,翻开了 Web 开发的新篇章。基于 AJAX,我们可以把 Web 分为前端和后端... -
java 面试题 总结
2009-09-16 08:45:34为什么要有GC? GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域... -
天猫前端基础技术体系MAP简介
2021-01-10 03:54:06列举这些不是想说明前端有多复杂,而是技术体系本身就不是一个独立的存在,需要结合更多其他领域才能有更好的发展,其实其他技术的发展也是类似。 历史 在我2011年刚加入口碑前端团队的时候... -
-
【怨气横生】java后端做页面(瞎搞)
2020-06-20 12:01:22我承认我做前端很敷衍,因为打心底排斥,但是我也会很认真的做好这件事,因为这是我的责任,我觉得这是我的责任(矛盾体),但是我们前端都闲的学习新知识了,为什么要这样打压我们后端 ===================故事... -
2016年3月-前端开发月刊
2020-12-08 19:14:45<div><h2>3月份前端资源分享 <h4>1. Javascript <ul><li>使用judge.js做信息判断</a></li><li><a href="https://segmentfault.com/a/1190000004430888">javascript----事件概述</a></li><li><a href=... -
超级有影响力霸气的Java面试题大全文档
2012-07-18 09:47:04为什么要有GC? GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域... -
从编译的角度看为什么 Velocity 丑到哭
2020-12-30 18:08:48<div><h1>从编译的角度看为什么 Velocity 丑到哭 阅读本文需要你对编译器的前端有所了解,能读懂词法规则和语法规则。 由于 Velocity 不同版本之间有些规则差异较大,文中未单独指明之处均使用 v1.7。 ... -
江湖告急...基于java的web的设计(急需有实际经验者来拍砖指出问题)
2014-11-05 10:00:57问题1:当服务层的业务变得越来越复杂,调用很多的webservice,事务如何控制? 问题2:持久层写成webservice到底行不行?主要担忧是安全吗?读写分开,分表分裤等等方案,能不能做到高安全性? 顺便问个简单问题... -
该开源仓库的文章都是我个人原创,公众号发过的技术文章(干货)也会有相关的目录整理,很多知识点我还在不停的总结和完善。点击关注【Java3y公众号】 及时获取最新文章 :sparkling_heart:我希望这个开源仓库: 能...
-
计算机网络自顶向下方法_你真的以为计算机网络不重要吗,这份书单帮你搞定相关面试题!...
2020-12-15 17:38:56其实就是Java网络编程,为什么呢,因为如果我想写一个Java Web项目,我只要用SSM就可以轻松搞定,写好我们的controller、service和dao就可以了,也就是只需要关心业务逻辑,不需要关心前端请求的路由、甚至是后端的...点击蓝色“程序员书单”关注我哟
加个“星标”,每天带你读好书!
Java工程师往往容易忽视的一块知识点,其实就是Java网络编程,为什么呢,因为如果我想写一个Java Web项目,我只要用SSM就可以轻松搞定,写好我们的controller、service和dao就可以了,也就是只需要关心业务逻辑,不需要关心前端请求的路由、甚至是后端的负载均衡和网络请求处理,因为这些东西很多时候都被Nginx和Tomcat给吃掉了,Nginx帮我们做好了负载均衡,Tomcat则帮我们完成TCP连接的建立,HTTP请求的处理,把所有复杂的技术细节都给屏蔽了。不过随着技术发展和更迭,大公司对于人才的要求也越来越高,对于高并发服务端编程能力的要求也在提高,比如在直播、实时通讯、游戏服务端开发等技术领域,通信协议和网络编程就成为了很重要的一个技术课题,相应的在Java领域,我们就必须要了解NIO、Linux epoll以及Netty等和网络通信相关的技术。如果你想做基础技术研发,比如消息队列、RPC框架的研发,那么网络编程也是必备的基础能力。那么今天我们就借此机会,来介绍几本关于Java网络编程方面的优质书籍,以帮助大家更好地掌握这方面的知识,我们将从Java Web出发,依次介绍NIO网络编程、Tomcat的设计原理,以及Netty这类通信编程框架领域的权威书籍。计算机网络书单
图解HTTP
《图灵程序设计丛书:图解HTTP》对互联网基盘——HTTP协议进行了全面系统的介绍。作者由HTTP协议的发展历史娓娓道来,严谨细致地剖析了HTTP协议的结构,列举诸多常见通信场景及实战案例,最后延伸到Web安全、全新技术动向等方面。
《图解HTTP》的特色为在讲解的同时,辅以大量生动形象的通信图例,更好地帮助读者深刻理解HTTP通信过程中客户端与服务器之间的交互情况。读者可通过《图灵程序设计丛书:图解HTTP》快速了解并掌握HTTP协议的基础,前端工程师分析抓包数据,后端工程师实现REST API、实现自己的HTTP服务器等过程中所需的HTTP相关知识点本书均有介绍。
作者简介
上野·宣 ,OWASP 日本分会会长,TRICORDER株式会社董事长。主要从事安全咨询、风险评估、信息安全教育等工作。
图解TCP/IP
《图灵程序设计丛书:图解TCP/IP(第5版)》是一本图文并茂的网络管理技术书籍,旨在让广大读者理解TCP/IP的基本知识、掌握TCP/IP的基本技能。
书中讲解了网络基础知识、TCP/IP基础知识、数据链路、IP协议、IP协议相关技术、TCP与UDP、路由协议、应用协议、网络安全等内容,引导读者了解和掌握TCP/IP,营造一个安全的、使用放心的网络环境。作者简介竹下隆史,Net One Systems公司网络工程师。
村山公保,仓敷艺术科学大学产业科学技术学院信息学系教授。
荒井透,1958年生人。Net One Systems公司网络工程师。
苅田幸雄,高能加速器研究所、计算科学中心研究员。
网络是怎样连接的
《网络是怎样连接的》以探索之旅的形式,从在浏览器中输入网址开始,一路追踪了到显示出网页的内容为止的整个过程,以图配文,讲解了网络的全貌,并重点介绍了实际的网络设备和软件是如何工作的。目的是帮助读者理解网络的本质意义,理解实际的设备和软件,进而熟练运用网络技术。同时,专设了“网络术语其实很简单”专栏,以对话的形式介绍了一些网络术语的词源,颇为生动有趣。
作者简介
户根勤(作者)
早先从事软件开发,后进入网络行业。曾供职于日本网络设备厂商(外资企业)和国内网络集成商,从事产品开发和技术咨询等工作。
周自恒(译者)
知名技术图书译者、全栈程序员、自然科学爱好者。初中时曾获得信息学奥赛天津赛区一等奖,曾任某管理咨询公司战略技术总监。计算机网络-自顶向下方法(第六版)
本书是经典的计算机网络教材之一,采用了作者的自顶向下方法来讲授计算机网络的原理及其协议,自16年前第1版出版以来已经被数百所大学和学院选作教材,被译为14种语言。第7版保持了以前版本的特色,继续关注因特网和计算机网络的现代处理方式,注重原理和实践,为计算机网络教学提供了一种新颖和与时俱进的方法。
作者简介
詹姆斯·F. 库罗斯(James F. Kurose) 美国马萨诸塞大学阿默斯特分校计算机科学系教授,研究兴趣包括网络协议和体系结构、网络测量、多媒体通信以及建模和性能评价。
基思·W. 罗斯(Keith W. Ross) 美国纽约大学(NYU)上海分校工程和计算机科学学院院长以及NYU计算机科学和工程系的Leonard J. Shustek首席教授。
这份书单会告诉你,Java网络编程其实很重要
这份书单,想要晋级高级Java工程师的朋友值得一看!
这份Java Web必读书单,值得所有Java工程师一看!
觉得有用就点个在看吧!
-
e2e自动化之Nightwatch
2019-08-08 14:36:11本司之前用的是selenium Java写的前端自动化。倒也是我写了。不过为什么会想着Nightwatch呢?因为有一天发现自动化挂了。一查看才发现前端加了个蒙板。结果导致xpath变了,然后导航页点击挂了(不能点到导航页,也就... -
e2e自动化之Nightwatch(转)
2018-06-29 19:19:42本司之前用的是selenium Java写的前端自动化。倒也是我写了。不过为什么会想着Nightwatch呢?因为有一天发现自动化挂了。一查看才发现前端加了个蒙板。结果导致xpath变了,然后导航页点击挂了(不能点到导航页,也就... -
还没使用过消息队列?这一份书单值得你好好看看!
2020-05-14 08:22:42其实就是Java网络编程,为什么呢,因为如果我想写一个Java Web项目,我只要用SSM就可以轻松搞定,写好我们的controller、service和dao就可以了,也就是只需要关心业务逻辑,不需要关心前端请求的路由、甚至是后端的... -
很多朋友可能喜欢写代码,不喜欢写测试。也有的朋友觉得测试是测试人员做的,跟开发人员没关系。 但是测试真的非常重要,从单元测试到end to end测试到集成测试,我们一直都在路上。 单元测试的几个框架Junit,...
-
egg.js学习
2020-05-04 15:54:37为什么要学习Egg.js 前言 写一个自己的项目,需要一些复杂的数据,不能只通过mock数据,毕竟那都是假的,一些实际的操作实现不了,所以就选择node.js。可能有人会说去学习一下后台语言,比如Java、PHP等,但是我觉得... -
感冒难受
2009-11-12 17:55:00感冒都两天没上课了,现在正是专业课关键阶段,前端时间还为考研不考研发愁,专业学习又那么多迷雾,很是郁闷,今天去学校医务室看病,还好没什么大,不过很久没去过医院检查了,还给我验血,吓死我了。下午的实验没... -
e语言-miniblink浏览器模块(含源码)18-08-14
2019-08-23 12:05:15cef:优点是由于集成的chromium内核,所以对H5支持的很全,同时因为使用的人也多,各种教程、示例,资源很多。但缺点很明显,太大了。最新的cef已经夸张到了100多M,还要带一堆的文件。同时新的cef已经不支持xp了... -
我会从下图中的知识点去写这个系列,很多细节的点,可能想得不是很完善,大家可以去【公众号】获取或者加我【微信】提意见(别忘记Star哟)。 原创文章每周最少两篇,公众号首发文章,【B站】首发视频,比博客早一到两...
-
-
-
-
2014年下半年 嵌入式系统设计师 上午试卷 综合知识 软考真题【含答案和答案解析】
-
Go-SpeedTest-Bot:帮助您使用手机管理所有节点的机器人-源码
-
NFS 网络文件系统
-
响应式编程中的Flux和Mono 的理解
-
Unity 热更新技术-ILRuntime
-
linux基础入门和项目实战部署系列课程
-
STM32F373XXDataSheet.zip
-
设计需求分析方法与过程
-
Glasterfs 分布式网络文件系统
-
2015年下半年 嵌入式系统设计师 上午试卷 综合知识 软考真题【含答案和答案解析】
-
用微服务spring cloud架构打造物联网云平台
-
第1关上 将错就错.mp4
-
有赞容器化实践
-
UL 859:2017 Household Electric Personal Grooming Appliances(个人护理)-完整英文版(192页)
-
uniapp上拉加载
-
基于采用级联调制器的光电振荡器的自振荡光学频率梳状发生器
-
聊聊分布式事务,再说说解决方案
-
FyreString:FyreString是PHP的免费开源字符串实用程序库-源码
-
GO语言 实现端口扫描
-
ApacheBeam实战指南|玩转KafkaIO与Flink