要实现JavaScript的拖拽效果,首先我们需要知道事件对象几个有关于实现拖拽效果的坐标
获取事件对象 var e = e || window.event;
根据需求需要用到的拖拽效果的坐标
clientX:鼠标点击位置相对于浏览器可视区域的水平偏移量(不会计算水平滚动的距离)
clientY:鼠标点击位置相对于浏览器可视区域的垂直偏移量(不会计算垂直滚动条的距离)
offsetX:鼠标点击位置相对于触发事件对象的水平距离
offsetY:鼠标点击位置相对于触发事件对象的垂直距离
pageX:鼠标点击位置相对于网页左上角的水平偏移量,也就是clientX加 上水平滚动条的距离
pageY:鼠标点击位置相对于网页左上角的垂直平偏移量,也就是clientY加上垂直滚动条的距离
offsetLeft:如果父元素中有定位的元素,那么就返回距离当前元素最近的定位元素边缘的距离
offsetTop:如果父元素中没有定位元素,那么就返回相对于body左边缘距离
获取元素自身大小:offsetWidth和offsetHeight / clientWidth和clientHeight
offsetWidth和clientWidth的区别:就是offsetWidth包含边框,clientWidth不包含边框
实现拖拽需要用到:clientWidth、clientHeight、clientX、clientY、offsetLeft、offsetTop
首先搭建好html结构和css样式
<div class="wrap"> <div class="cover"> </div> </div>
* { margin: 0; padding: 0; } .wrap { width: 500px; height: 500px; border: 1px solid deeppink; position: relative; margin: 50px auto; } .cover { width: 150px; height: 150px; background: rgba(200, 7, 99, 0.5); display: none; position: absolute; left: 0; top: 0; cursor: move; }注意:需要给大盒子和小盒子进行定位:子绝父相
<script> var wrap = document.querySelector(".wrap"); var cover = document.querySelector(".cover"); wrap.onmouseover = function() { cover.style.display = "block"; wrap.onmousemove = function(e) { var e = e || window.event; var x1 = e.clientX; var y1 = e.clientY; //这里获取到的e.clientX和e.clientY,可以看情况和需求改为e.pageX和e.pageY var halfWidth = cover.clientWidth / 2; var halfHeight = cover.clientHeight / 2; var wrapLeft = wrap.offsetLeft; var wrapTop = wrap.offsetTop; var l = x1 - wrapLeft - halfWidth; var t = y1 - wrapTop - halfHeight; if (l <= 0) { l = 0 } if (l >= wrap.clientWidth - cover.clientWidth) { l = wrap.clientWidth - cover.clientWidth } if (t <= 0) { t = 0 } if (t >= wrap.clientHeight - cover.clientHeight) { t = wrap.clientHeight - cover.clientHeight } cover.style.left = l + "px"; cover.style.top = t + "px" } } wrap.onmouseout = function() { cover.style.display = "none"; } </script>
var halfWidth = cover.clientWidth / 2; var halfHeight = cover.clientHeight / 2; var wrapLeft = wrap.offsetLeft; var wrapTop = wrap.offsetTop; var l = x1 - wrapLeft - halfWidth; var t = y1 - wrapTop - halfHeight; //限制范围 if (l <= 0) { l = 0 } if (l >= wrap.clientWidth - cover.clientWidth) { l = wrap.clientWidth - cover.clientWidth } if (t <= 0) { t = 0 } if (t >= wrap.clientHeight - cover.clientHeight) { t = wrap.clientHeight - cover.clientHeight }注意:这里要限制小盒子在大盒子之间移动的范围,左上角的限制,当小盒子超出范围时,将0赋值给l和t。右下角小盒子移动的范围在大盒子宽度减去小盒子的宽度。
css面试题@响应式布局如何实现
1为什么要使用响应式布局
响应式布局可以让网站同时适配不同分辨率和不同的手机端,让客户有更好
的体验。
2如何实现
方案一:百分比布局
利用对属性设置百分比来适配不同屏幕,注意这里的百分比是相对于父元素; 能够设置的属性有width,、height、padding、margin,其他属性比如border、 font-size不能用百分比来设置的
由于没办法对font-size进行百分比设置,所以用的最多就是对图片和大块布局进行百分比设置。
方案二:使用媒体查询 (CSS3@media 查询)
利用媒体查询设置不同分辨率下的css样式,来适配不同屏幕。
媒体查询相对于百分比布局,可以对布局进行更细致的调整,但需要在每个分辨率下面都写一套css样式。
该布局的话适用于简单的网页,可以使移动端和pc端使用一套网址。从而节约成本。也方便后期的维护,bootcss就是用了CSS3的media来实现响应的 但是相对于复杂的网页就不适合了(如:淘宝,京东)等等
方案三.rem 响应式布局
rem布局的原理
rem:相对于根元素(即html元素)font-size计算值的倍数。
如 html的font-size为100px;那么2rem就为200px。
通俗的来讲的话rem就是通过JavaScript来获取页面的宽度,从而动态的计算rem。这样就会使不同分辨率下展现出相同的效果。
//代码展示
css面试题@响应式布局如何实现 1为什么要使用响应式布局 响应式布局可以让网站同时适配不同分辨率和不同的手机端,让客户有更好 的体验。 2如何实现 方案一:百分比布局 利用对属性设置百分比来适配不同屏幕,注意这里的百分比是相对于父元素; 能够设置的属性有width,、height、padding、margin,其他属性比如border、 font-size不能用百分比来设置的 由于没办法对font-size进行百分比设置,所以用的最多就是对图片和大块布局进行百分比设置。 方案二:使用媒体查询 (CSS3@media 查询) 利用媒体查询设置不同分辨率下的css样式,来适配不同屏幕。 媒体查询相对于百分比布局,可以对布局进行更细致的调整,但需要在每个分辨率下面都写一套css样式。 该布局的话适用于简单的网页,可以使移动端和pc端使用一套网址。从而节约成本。也方便后期的维护,bootcss就是用了CSS3的media来实现响应的 但是相对于复杂的网页就不适合了(如:淘宝,京东)等等 方案三.rem 响应式布局 rem布局的原理 rem:相对于根元素(即html元素)font-size计算值的倍数。 如 html的font-size为100px;那么2rem就为200px。 通俗的来讲的话rem就是通过JavaScript来获取页面的宽度,从而动态的计算rem。这样就会使不同分辨率下展现出相同的效果。 //代码展示上述代码中 7.5为动态的值,根据设计图的宽度进行动态的改变。window.onresize的作用是:当页面的宽度或高度发生改变时,再次进行调用rem函数。
如何在网页前端里可视化你的知识图谱
最近费尽千辛万苦构造了一份可以用(大概)的知识图谱,并且把要利用知识图谱做的领域命名实体识别和一些推荐的功能做成Web版的demo,顺带想实现一些可视化知识图谱的功能。
(凭啥知识图谱就只能在Neo4j里自嗨,不能来前端show一下,歧视吗(¬_¬))
找了做前端图表展示的开源库,D3.js和Echarts都能做,我拿Echarts实现了一下功能,先看一下在现在项目里一个基于知识图谱查询的实际效果:
接下里看看如何的实现:
<script src="/static/js/echarts.common.min.js"></script> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts@4.5.0/dist/echarts.min.js"></script>给要展示的图准备一个Dom:
<!-- 为ECharts准备一个具备大小的Dom --> <div class = "col-md-12"> <div class="panel panel-default "> <header class="panel-heading"> 关系图 : </header> <div class = "panel-body "> <div id="graph" style="width: 100%;height:600px;"></div> </div> </div> </div>
data = [ {name:'苹果',category:1,id:0}, {name:'梨子',catagory:1,id:1}, {name:'水果',category:2,id:2} ] links = [ {source:0,target:2,category:0,value:'属于',symbolSize:10}, {source:1,target:2,category:0,value:'属于',symbolSize:10} ]
var myChart = echarts.init(document.getElementById('graph')); option = { title: { text: '' }, tooltip: {}, animationDurationUpdate: 1500, animationEasingUpdate: 'quinticInOut', label: { normal: { show: true, textStyle: { fontSize: 12 }, } }, legend: { x: "center", show: false }, series: [ { type: 'graph', layout: 'force', symbolSize: 45, focusNodeAdjacency: true, roam: true, edgeSymbol: ['none', 'arrow'], categories: [{ name: '查询实体', itemStyle: { normal: { color: "#009800", } } }, { name: 'instance', itemStyle: { normal: { color: "#4592FF", } } }, { name: 'class', itemStyle: { normal: { color: "#C71585", } } }], label: { normal: { show: true, textStyle: { fontSize: 12, }, } }, force: { repulsion: 1000 }, edgeSymbolSize: [4, 50], edgeLabel: { normal: { show: true, textStyle: { fontSize: 10 }, formatter: "{c}" } }, data: data, links: links, lineStyle: { normal: { opacity: 0.9, width: 1.3, curveness: 0, color:"#262626", } } } ] }; // 使用刚指定的配置项和数据显示图表。 myChart.setOption(option);这样就成功实现了一个简单的图谱可视化:
————————————————
版权声明:本文为CSDN博主「游离态GLZ不可能是金融技术宅」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37477357/article/details/104857495
1.实现注册与登录功能:
要求用到验证码,登录后该出不再显示登录与注册,而是显示用户名。
2.实现预约功能:
实现“运动”与“学习”两方面的邀约功能,并将邀约数据保存到数据库中,数据库使用Mysql。
运动可以邀约:篮球、足球、乒乓球等
学习可以邀约:自习、辅导等
在正式开始编码之前,需要先导入相关jar包并配置好相关的配置文件,同时也需要导入前端给的页面代码。接着是建立好相应的数据库结构,并初步构建好三层架构的想法思路。
web层
service层
dao层
然后在这里写一下对于验证码处理和点击图片更换验证码功能的一些细节。
如下图所示,为了保证servlet层能够正确接收到界面所展示的验证码信息,同时因为session对象是项目自生成的,所以我直接获取session对象并以类似于键值对的形式将页面验证码信息存入session中。
接下来是jsp页面对于验证码展示的一些处理
在这里,因为点击验证码更换操作需要用到js,所以我百度得到了上图这样一串代码。其中时间戳的作用是通过改变每次请求的时间参数来获得刷新效果,即改变url中的响应头信息。
2.注册功能
事实上,有了登录功能的实现,注册功能的代码与其都是大同小异的。最大的不同应该就是Dao层执行的操作不同
预约功能的实现更是与注册功能的实现基本一致。所不同的应该是jsp页面对单选框输入的设置。
首先在写代码之前我们需要理清如何穿插图片呢?
可以让所有图片都float:left,用一个大盒子装进所有图片,在用一个小盒子显示图片,溢出图片就hidden,之后以每张图片的宽度来scrollLeft.
可以给每张图片一个name/id,用循环遍历所有图片
可以用float:left,但是除了我要显示的图片外,其他图片都hidden,之后每当我需要某张图片时,我就把它制定到某位置
…
在这里,我将用第二种方法,因为它很直观明了,我要哪张图片我就调哪张图片。
HTML部分:在div里面我装了一张图片,name:0, 这是为了在刚打开的时候,我们的页面是有东西的而不是一片空白。其他部分都好理解,不理解的可在下方评论。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>轮播图</title> <link rel="stylesheet" href="轮播图.css" /> <script src="轮播图.js"> </script> </head> <body> <header> <div id="oImg"> <!-- 轮流播放图片 --> <img id="insert" src="img/轮1.jpg" name="0"/> </div> <!-- 左右切换图片 --> <p id="left" οnclick="goBack()"></p> <p id="right" οnclick="goForward()"></p> <ul id="nav"> <!-- 指定某张图片 --> <li id="1" οnclick="move(this)">1</li> <li id="2" οnclick="move(this)">2</li> <li id="3" οnclick="move(this)">3</li> <li id="4" οnclick="move(this)">4</li> <li id="5" οnclick="move(this)">5</li> </ul> </header> </body> </html>
CSS:
* { margin: 0 auto; padding: 0 auto; } header { width: 100%; height: 680px; position: relative; } img { width: 100%; height: 680px; } #nav { position: absolute; bottom: 5px; left: 30%; } #nav li { width: 30px; height: 30px; line-height: 30px; text-align: center; background: #ccc; font-size: 24px; border-radius: 9px; color: darkslategrey; font-family: 'Times New Roman', Times, serif; margin: 0 25px; float: left; cursor: pointer; list-style: none; } #nav li:hover { background: peru; } #left { width: 25px; height: 24px; left: 0; top: 50%; cursor: pointer; position: absolute; background: url(img/fx1.png); } #right { width: 25px; height: 24px; right: 0; top: 50%; cursor: pointer; position: absolute; background: url(img/fx2.png); }之后我们来看重中之重JS部分
JavaScript:
// 五张图片的url var oImg1 = "img/轮1.jpg"; var oImg2 = "img/轮2.jpg"; var oImg3 = "img/轮3.jpg"; var oImg4 = "img/轮4.jpg"; var oImg5 = "img/轮5.jpg"; // 把5张图片存入一个数组 var arr = [oImg1, oImg2, oImg3, oImg4, oImg5]; window.onload = function() { //刚加载时第一张图片1号背景颜色 document.getElementById("1").style.background = "peru"; run() } //轮播 function run() { timer = setInterval(function() { //随机点数字时能接着变化 var pic = document.getElementById("insert").name; var shade = document.getElementById("insert"); //如果为最后一张图片则重新循环 if (pic == 4) { pic = -1; } //点一个数字该数字背景颜色变化其余的不变 var aLi = document.getElementsByTagName("li"); for (var j = 0; j < aLi.length; j++) { aLi[j].style.backgroundColor = "#CCCCCC"; } var i = parseInt(pic); document.getElementById("insert").src = arr[i + 1]; document.getElementById("insert").name = i + 1; //数字随图片变化 switch (i) { case 0: var temp = '2'; break; case 1: var temp = '3'; break; case 2: var temp = '4'; break; case 3: var temp = '5'; break; case -1: var temp = '1'; break; } document.getElementById(temp).style.background = "peru" }, 5000) } //右箭头 function goForward() { var temp = document.getElementById("insert").name; var oBox = document.getElementById("insert"); var aLi = document.getElementsByTagName("li"); // 数字跟着图片一起变 for (var i = 0; i < aLi.length; i++) { aLi[i].style.backgroundColor = "#CCCCCC"; } switch (temp) { case "0": var n = '2'; break; case "1": var n = '3'; break; case "2": var n = '4'; break; case "3": var n = '5'; break; case "4": var n = '1'; break; } document.getElementById(n).style.background = "peru" // 向右移动图片 for (var j = 0; j < arr.length; j++) { if (j < 4) { if (temp == j) { oBox.src = arr[j + 1]; } } else { if (temp == 4) { oBox.src = arr[0]; } } } // 轮到最后一张图片时返回第一张 if (temp < 4) { oBox.name = parseInt(temp) + 1; } else { oBox.name = 0; } } //左箭头 function goBack() { var temp = document.getElementById("insert").name; var oBox = document.getElementById("insert") var aLi = document.getElementsByTagName("li"); // 图片移动时数字也跟着变 for (var i = 0; i < aLi.length; i++) { aLi[i].style.backgroundColor = "#CCCCCC"; } switch (temp) { case "0": var n = '5'; break; case "1": var n = '1'; break; case "2": var n = '2'; break; case "3": var n = '3'; break; case "4": var n = '4'; break; } document.getElementById(n).style.background = "peru" // 向左移动图片 for (var j = 0; j < arr.length; j++) { if (j > 0) { if (temp == j) { oBox.src = arr[j - 1]; } } else { if (temp == 0) { oBox.src = arr[4]; } } } // 轮到第一张图片时返回最后一张 if (temp > 0) { oBox.name = parseInt(temp) - 1; } else { oBox.name = 4; } } //指定图片 function move(num) { var oBox = document.getElementById("insert"); var temp = document.getElementById("insert").name; var aLi = document.getElementsByTagName("li"); for (var i = 0; i < aLi.length; i++) { aLi[i].style.backgroundColor = "#CCCCCC"; } document.getElementById(num.innerHTML).style.background = "peru" switch (num.innerHTML) { case "1": oBox.src = arr[0]; oBox.name = 0; break; case "2": oBox.src = arr[1]; oBox.name = 1; break; case "3": oBox.src = arr[2]; oBox.name = 2; break; case "4": oBox.src = arr[3]; oBox.name = 3; break; case "5": oBox.src = arr[4]; oBox.name = 4; break; } }JavaScript部分我写的很详细,仔细看的话是可以看懂的,主要分3个重要部分:
用src来调用每张图片并给每张图片一个name,这样方便后面的重复使用
为下方的数字按钮匹配图片,点击1跳到第1张图片,点击2跳到第2张图片…因为我把所有的图片都存在了一个数组里,所以在匹配的时候要注意数组0位置才是数字1指定的图片
可以来回翻页,当到达最后一张图片时,我再点击下一张图片又能返回到第一张图片了,亦或者当我点击到第一张图片时,再上一张图片又回到第五张图片了
效果如下:
大家有问题可以在下方评论哦,看到了会及时回复哒!
————————————————
版权声明:本文为CSDN博主「weixin_43964414」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43964414/article/details/104844041
CSS介绍
整理完了HTML的笔记,接下来就是CSS了。我们可以使用HTML构建稳定的结构基础,而页面的风格样式控制则交给CSS来完成。网页的样式包括各种元素的颜色、大小、线形、间距等等,这对于设计或维护一个数据较多的网站来说,工作量是巨大的。好在可以使用CSS来控制这些样式,这将大大提高网页设计和维护的效率,并且使网页的整体风格很容易做到统一。
CSS概述
CSS是英文Cascading Style Sheet的缩写,中文译为层叠样式表,也有人翻译为级联样式表,简称样式表。它是一种用来定义网页外观样式的技术,在网页中引入CSS规则,可以快捷地对页面进行布局设计,可以的控制HTML标记对象的宽度、高度、位置、字体、背景等外观效果。
CSS是一种标识性语言,不仅可以有效的控制网页的样式,更重要的是实现了网页内容与样式的分离,并允许将CSS规则单独存放于一个文档中, CSS文件的扩展名为“css”。
CSS3
CSS3标准早在1995年就开始制订, 2001年提上W3C研究议程,但是,10年来CSS3可以说是基本上没有什么很大的变化,一直到2011年6月才发布了全新版本的CSS3,目前,许多浏览器都广泛支持CSS3。
CSS3是CSS技术的一个升级版本,CSS3语言将CSS划分为更小的模块,在朝着模块化的方向发展。以前的版本是一个比较庞大而且比较复杂模块,所以,把它分解成为一个个小的简单的模块,同时也加入了更多新的模块。在CSS3中有字体、颜色、布局、背景、定位、边框、多列、动画、用户界面等等多个模块。
CSS的基本用法
CSS的使用规则由两部分组成:选择器和一条或多条声明。其基本基本语法如下:
选择器{ 属性1: 值; 属性2: 值; …
属性n: 值; }
CSS的使用规则由两部分组成:选择器和一条或多条声明。其基本基本语法如下:
选择器{ 属性1: 值; 属性2: 值; …
属性n: 值; }
CSS属性
CSS的属性按照相关功能进行了分组,包含了字体、文本、背景、列表、动画等多个分组,这些属性的具体使用方法和示例将会在后续中提到。
在HTML文档中使用CSS的方法
根据CSS在HTML文档中的使用方法和作用范围不同,CSS样式表的使用方法分为三大类:行内样式、内部样式表和外部样式表,而外部样式表又可分为链入外部样式表和导入外部样式表。本节我们从四个分类来认识在HTML中使用CSS的方法。
行内样式
内部样式表
外部样式表
链入外部样式表
导入外部样式表
行内样式
行内样式(inline style),也叫内联样式,它是CSS四种使用方法中最为直接的一种,它的实现借用HTML元素的全局属性style,把CSS代码直接写入其中即可。
严格意义上行内样式是一种不严谨的使用方式,它不需要选择器,这种方式下CSS代码和HTML代码混合在一起,因此不推荐使用行内样式。行内样式的基本语法如下:
<标记 style="属性:值; 属性:值; …">
当单个文档需要特殊的样式时,应该使用内部样式表。内部样式表是将样式放在页面的head区里,这样定义的样式就应用到本页面中了,内部样式表使用style标记进行声明,是较为常用的一种使用方法。其基本语法如下:
<head> <meta charset="utf-8" /> <title></title> <style type="text/css"> 选择器1{属性:值;…} 选择器2{属性:值;…} …… 选择器n{属性:值;…} </style> </head>
<head> <meta charset="utf-8" /> <title></title> <link href="样式表路径" rel="stylesheet" type="text/css" /> </head>其中:
<head> <meta charset="utf-8" /> <title></title> <style type="text/css"> @import url("样式表路径"); </style> </head>其中:
<head> <meta charset="utf-8" /> <title></title> <style type="text/css"> @import url("样式表路径"); </style> </head>
记录仓促,遗漏之处日后补充,如有错误或不足之处,还望指正
————————————————
版权声明:本文为CSDN博主「狗狗狗狗狗乐啊」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44122062/article/details/104848745
文章目录
前言
一、白屏时间过长分析
二、针对性优化
针对animate.css
针对mint-ui的优化
针对图片的优化
三、webpack打包优化与分析
webpack-bundle-analyzer打包分析
打包优化
四、优化后线上测试速度提升
五、优化总结
前言
最近在做项目时,测试提出了在App端的H5项目入口加载时间过长,白屏等待过久,需要优化的问题,于是着手开始分析:
项目技术栈:基于Vue全家桶做的一个移动端类似WebApp的项目,使用到的第三方库有:mint-ui, echarts,momentjs。
项目痛点:白屏时间过长
一、白屏时间过长分析
通过访问线上环境,结合Chrome devtool中Network和Performance功能可以具体分析整个白屏的耗时主要在哪一块儿
Network耗时记录:
Performance性能面板
通过上面两张图分析,从浏览器发起请求到解析HTML完成这一过程中:
animate.css, mini-ui.css的请求耗时最长。
图片过大耗时。
二、针对性优化
针对animate.css
animate.css由于使用的是第三方CDN(国外服务器)所有请求时间相对较长,所以如果必须要用animate.css那么可以下载下来作为本地资源,也可以使用国内CDN,或者不用animate.css,而是针对使用到的几个CSS动画,直接自己造轮子
针对mint-ui的优化
由于mint-ui在原项目中使用的是全局引用的方式,这才导致打包资源过大,css单独请求耗时过长的问题,所以主要解决方案是按需引入mint-ui,借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。
安装babel-plugin-component, 若已安装可忽略
修改 .babelrc (重点在plugins中):
{ "presets": [ ["env", { "modules": false }], "stage-2" ], "plugins": ["transform-runtime",["component", [ { "libraryName": "mint-ui", "style": true } ]]], "comments": false, "env": { "test": { "presets": ["env", "stage-2"], "plugins": [ "istanbul" ] } } }
在main.js中引用使用到的插件
import Vue from 'vue' import { Button, Cell } from 'mint-ui' import 'mint-ui/lib/style.min.css' // 引用CSS import App from './App.vue' Vue.component(Button.name, Button) Vue.component(Cell.name, Cell) /* 或写为 * Vue.use(Button) * Vue.use(Cell) */ new Vue({ el: '#app', components: { App } })
在使用的组件中改为按需引用组件
import Vue from 'vue' var Popup = Vue.component('mt-popup') var Swipe = Vue.component('mt-swipe') var SwipeItem = Vue.component('mt-swipe-item') export default { name:'my-component', components:{ Popup, Swipe, SwipeItem } }
此按需引入方案也同样适用于其他第三方UI组件库
图片小图通过webpack可以直接转为base64,而大图可以通过压缩或者换格式的方式来优化,这里推荐一个好用的图片压缩工具,工具:tinyPNG,如下是图片转换前后对比
在完成了上述优化以后,下面着重关注下webpack打包后生成的文件大小,看还有没有可以优化的余地。由于项目中已经通过路由按需加载
的方式来做了功能拆分,所以通过webpack打包后生成了很多分散的js文件,如下图:
通过上图分析可以知道打包后有几个文件相对较大,vendor.js都知道是第三方库文件打包形成,之前通过mint-ui按需加载会有一定的变化,后面记录。这里着重看另两个带hash的js文件,这里并看不出来它为什么这么大,所以这里需要用到webpack打包分析工具来做进一步的打包文件分析:webpack-bundle-analyzer
它的作用如下图,即在打包后生成打包文件大小分析图,方便我们更加直观的看到文件大小和引用情况
npm intall -D webpack-bundle-analyzer
webpack.pro.conf.js
. (这里由于只是用于生产打包分析且是通过vue-cli生成的项目框架)
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin module.exports = { // ... plugins:[ new BundleAnalyzerPlugin() ] }
运行npm run build
,(webpack默认会在打包完成时生成分析图)
版权声明:本文为CSDN博主「Sophie_U」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Sophie_U/article/details/104840167
数据类型的转化(JavaScript)—自动转化和强制转化
这一周,我来分享一下在JavaScript中的数据类型转化。
首先我们要知道在JavaScript中的数据类型有什么?在这里我就不详细介绍了,帮你总结好了。
1.布尔类型-----Boolean---isNaN()
用来判断一个变量是否为非数字的类型,是数字返回false,不是数字返回true。
2.数值类型-----Number
存储时,是按照二进制数值存储,输出时,默认都是按照十进制数值输出。
在JavaScript中二进制前加0b/0B,八进制前面加0 ,十六进制前面加0x。
如果需要按照原始进制数值输出,用格式为:
变量名称.toString(进制) ;
注意的是:S必须大写,将数值转化为字符串形式输出
如:console.log( a.toString(2) );将a转换成2进制的形式输出。
3.字符串类型-----String
JavaScript可以用单引号嵌套双引号, 或者用双引号嵌套单引号(外双内单,外单内双)
字符串是由若干字符组成的,这些字符的数量就是字符串的长度。
通过字符串的length属性可以获取整个字符串的长度。
例子:var str = 'my name is xiaoming';
console.log(str.length);
输出的结果是19。可以知道空格也代表一个字符。
4.undefined
表示没有数值-----应该有数值,但是现在没有数值
5.null
表示数值为空-----表示有数值,但是数值是“空”
上面就是数据类型的五种形式。那么它是如何转化呢?听我详细给你讲解。
在 JavaScript 程序中 , 变量中存储的数据类型没有限制,也就是在变量中可以存储任何符合JavaScript语法规范的数据类型。但是在 JavaScript 程序的执行过程中,往往需要变量中存储的数值是某种特定的数据类型,别的数据类型不行,此时就需要进行数据类型的转化。
————————————————
版权声明:本文为CSDN博主「什什么都绘」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39406353/article/details/104864224上面就是数据类型的五种形式。那么它是如何转化呢?听我详细给你讲解。
在 JavaScript 程序中 , 变量中存储的数据类型没有限制,也就是在变量中可以存储任何符合JavaScript语法规范的数据类型。但是在 JavaScript 程序的执行过程中,往往需要变量中存储的数值是某种特定的数据类型,别的数据类型不行,此时就需要进行数据类型的转化。
JavaScript中数据类型的转化,分为自动转化和强制转化:
自动转化是计算机程序,自动完成的转化。
强制转化是程序员,强行完成的转化
1.布尔类型的自动转化:
在 执行 if 判断时 ,其他数据类型会自动转化为布尔类型
其他类型转化为布尔类型的原则
0 '' undefined null NaN 这五种情况转化为false
特别提醒 0.0 0.00000 都算是0
其他的所有都会转化为 true
2.字符串的自动转化:
执行字符串拼接, +号的两侧,应该都是字符串类型,会将其他数据类型转化为字符串类型
转化原则:
//基本数据类型 / 简单数据类型------将数据数值直接转化为字符串 , 然后执行拼接操作
布尔值 true ---> 字符串 'true'
布尔值 false ---> 字符串 'fasle'
undefined ---> 字符串 'undefined'
unll ---> 字符串 'null'
数值 ---> 将数值解析转化为'对应的纯数字的字符串'
// 引用数据类型 / 复杂数据类型
数组 ---> 将 [] 中的内容,转化为字符串的形式,执行拼接操作
对象 ---> 任何对象,任何内容,都会转化为 [object Object] 固定的内容形式,执行拼接操作
函数 ---> 将所有的程序代码,转化为字符串,执行拼接操作
3.数值的自动转化:
在执行运算时,会触发数据类型的自动转化。
转化原则:
布尔类型 : true ---> 1
false ---> 0
undefined : 转化为 NaN
null : 转化为 0
字符串 :
如果整个字符串,是纯数字字符串,或者符合科学计数法 ---> 转化为对应的数值
如果字符串内有不符合数字规范的内容 ---> 转化为 NaN
数组,对象,函数:
如果是+加号执行的是字符串拼接效果,按照这些数据类型转化为字符串的原则来转化
如果是其他形式的运算 执行结果都是 NaN
4.布尔类型的强制转化:
布尔类型的强制转化就是使用JavaScript中定义好的 方法/函数 Boolean( 数据/变量 )
Boolean() 这个方法 不会改变 变量中存储的原始数值
转化原则与自动转化原则相同
0 '' undefined null NaN --------> false
其他数据,都转化为true
5.字符串类型的强制转化:
方法1,变量.toString(进制类型)
将数值强制转化为字符串,并且可以设定转化的进制,.toString() 之前,不能直接写数值,必须是写成变量的形式
进制常用的数值是 2 8 16 ,可以设定的范围是 2 - 36 进制
方法2,String( 变量 / 数据 )
将变量或者数据,转化为字符串,原则按照自动转化的原则来执行,不会改变变量中存储的原始数值
但是在字符串拼接时,会将其他数据类型自动转化为字符串
6.数字类型的强制转化:
————————————————方法1 , Number(变量/数值)
console.log( Number(true) ); // 1
console.log( Number(false) ); // 0
console.log( Number(null) ); // 0
console.log( Number(undefined) ); // NaN
console.log( Number('100') ); // 对应的数值
console.log( Number('100.123') ); // 对应的数值
console.log( Number('2e4') ); // 对应的数值
console.log( Number('123abc') ); // NaN
console.log( Number( [1,2,3,4,5] ) ); // NaN
console.log( Number( {name:'zhangsan'} ) ); // NaN
console.log( Number( function fun(){console.log('abc')} ) ); // NaN
将其他类型强制转化为数值类型,转化原则与自动转化选择相同
方法2, parseInt(变量 / 数据) 是获取变量或者数据的整数部分
从数据的 左侧起 解析获取 整数内容
console.log( parseInt(true) ); // 都是 NaN
console.log( parseInt(false) );
console.log( parseInt(null) );
console.log( parseInt(undefined) );
console.log( parseInt( {name:'zhangsan'} ) );
console.log( parseInt( function fun(){console.log('abc')} ) );
数组执行,是获取 数值部分 也就是 没有 []的部分
1,2,3,4,5 整数部分是 1 1之后是逗号 逗号不是整数,之后的部分也就不算整数
获取第一个数值的整数部分,如果有就获取,如果没有,结果是NaN
console.log( parseInt( [1,2,3,4,5] ) ); // 结果是 1
console.log( parseInt( [null,2,3,4,5] ) ); // 结果是 NaN
如果是整数就直接获取,如果是浮点数,或者科学计数法,就获取整数部分
console.log( parseInt( 100 ) ); // 整数是直接获取
console.log( parseInt( 0.0123 ) ); // 浮点数是获取整数部分
console.log( parseInt( 3.123456e3 ) ); // 科学计数法是解析之后,获取整数部分
字符串不同了
如果是纯数字的字符串
console.log( parseInt( '100' ) ); // 与数字的结果相同
console.log( parseInt( '0.0123' ) ); // 与数字的结果相同
console.log( parseInt( '3.123456e3' ) ); //3
console.log( parseInt( '3abc' ) ); //3
console.log( parseInt( '3.123' ) ); //3
方法3 , parseFloat( 变量 / 数值 )
获取浮点数部分
console.log( parseFloat(true) ); // 都是 NaN
console.log( parseFloat(false) );
console.log( parseFloat(null) );
console.log( parseFloat(undefined) );
console.log( parseFloat( {name:'zhangsan'} ) );
console.log( parseFloat( function fun(){console.log('abc')} ) );
//数值, 整数,浮点数,都会完整获取
console.log( parseFloat(100) ); //100
console.log( parseFloat(100.1234) ); //100.1234
console.log( parseFloat(1.234567e3) ); //1234.567
// 关键是字符串
// 从字符串的左侧起 解析 符合浮点数的部分
console.log( parseFloat( '100' ) ); // 与数字的结果相同
console.log( parseFloat( '0.0123' ) ); // 与数字的结果相同
console.log( parseFloat( '3.123456e3' ) ); // 科学技术法会解析
console.log( parseFloat( '3.1223abc' ) );
console.log( parseFloat( '3.123' ) );
好了,这就是在JavaScript中数据类型的转化,希望可以帮助到你。
版权声明:本文为CSDN博主「什什么都绘」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39406353/article/details/104864224
我们总在期待 Next Big Thing,企盼下一次数字革命。喊了这么多年的物联网现在还没有明显起来的迹象,而 VR 也因为头戴设备的大型化和沉浸式场景的泛用性较差的原因,反倒是 AR 和 MR 依托智能手机、浴霸式镜头组和 APP 有一定起色,但是也没有到革命性改变的程度,只能算是一个小趋势。当然,人工智能/深度学习所带来的影响更加深远,但是短时间以内,它所带来的变化趋近于隐形。
而最近2年,各种双屏和柔性屏的发布,则可能是距离我们最近的硬件变革,可能和柔性屏/双屏设备有关。
也许现在说硬件交互设计到了类似 2007 年 iPhone 发布一样拐点有点夸张,但是对于现在几乎纯粹拼配置死水微澜一样的手机电脑市场而言,这种明显区别于以往的硬件设计,将会直接带来交互、设计和体验上的改变。
2019年是否算得上是双屏设备元年,现在下结论为时过早,但是去年三星 Galaxy Fold 和 Moto Razr 的发布,确实给广大硬件厂商好好打了一个样。
尽管Galaxy Fold 去年折戟沉沙了,但是高昂的沉没成本和大势所趋让三星肯定不能就这么算了, 回炉再造一番之后今年又带着船薪版本的 Galaxy Fold 2 杀将回来,顺带还兼顾女性市场整了一个对标 Moto Razr 的化妆盒手机 Galaxy Z flip。
图片来自 TheVerge
当然,华为的 Mate Xs 也是相当优秀的产品,这款明显对标三星 Galaxy Fold 2 的产品,并没有将柔性屏制作成为向内折叠,而是完全翻过来,将它作为外屏来进行设计,反向折叠,展开的时候,屏幕自然延展。
图片来自 TheVerge
不过思路最为清奇的并非是华为,而是 TCL。就在这几天,TCL 带来了两款全新的原型机,一款手机带有两个折叠轴,相当于是将传统手机屏幕延展到以往的3倍,彻底折叠开相当于是一个 10英寸的平板电脑(回过头来想,就像是将一个平板电脑反向折叠到手机的大小,但是重量不变……)。
图片来自 TheVerge
另外一款原型机则选择了抽拉式的设计,机身可以如同抽屉一样拉开,柔软的屏幕会被拉出,延展开来差不多和 iPad Mini 一个大小了。
图片来自 TheVerge
图片来自Engadget
除了这几款之外,在今年年初的 CES 消费电子展上,联想、戴尔、华硕,这些目前世界上最大的消费电子制造商,纷纷带来了各自的折叠屏和双屏设备。
联想带来的 ThinkPad X1 Fold,是一个价格昂贵的柔性折叠屏平板电脑,它额外附带了一个蓝牙键盘。
图片来自 TheVerge
考虑到联想在此之前已经发布过带有LEC+墨水屏的双屏设备 Yoga Book 2,可以说联想是已经具备了制造两种不同类型屏幕设备的能力。
作为对手的戴尔,带来了分别对标联想这两个系列的对应产品:Concept Ori 和 Concept Duet。
Concept Ori 采用的是两块传统硬屏,你既可以让一款屏幕作为屏幕,另一块作为虚拟输入键盘或者手绘板,也可以使用配备的蓝牙键盘,吸附在底下的屏幕上来进行输入,而且当键盘移动到靠近转轴的地方,还能让底下露出的半块屏幕作为触控板来使用:
图片来自 TheVerge
Concept Duet 在概念上则和 联想的 ThinkPad X1 Fold 类似,一块柔性可折叠的屏幕,便于收纳,一体连接。
图片来自 TheVerge
看了这么多硬件,是不是觉得信息量有点大?不过简单来说,所有的这些产品,都在说一件事情:屏幕要延展开,这是一个正在发生的趋势。
同时,我们还注意到一个很明显的特征,就是所有的这些柔性屏设备都非常的……骚,且贵。动辄两三千美元的起步价,如果可靠坚挺也就算了,不仅转轴易损,且屏幕也存在易损的问题。根据 ifanr 的上手评测,即使是在优化了转轴和屏幕折叠角度之后,三星所发布的 Galaxy Z Flip 的屏幕中段依然有着不可忽视的折痕,这一问题可能会是绝大多数折叠柔性屏设备的通病。
图片来自爱范儿
与之相反,采用硬质双屏设计的硬件设备,从生产成本、工艺成熟度、价格上,都更加有优势。
值得注意的是,柔性折叠屏和硬质双屏设备,在基本的使用体验和逻辑上是一致的,除了极少数特殊的设备之外(比如 TCL的双折叠式的概念机),多数情况下,两者是差不多的。
只不过存在一个问题,双屏设备的交互和体验,需要有对应操作系统支持,因为从单屏到双屏,其实交互逻辑已经发生了巨大的改变。
一直在创新且「稳健」地更新软硬件的苹果公司,应该不会在市场未曾成熟的情况下选择发布硬件,这意味着你不会很快看到双屏 iOS 硬件,而面向着大量 OEM 厂商的 Android 和 Windows 则截然不同。着两年厂商已经身体力行证明了一件事情:只要操作系统和设计跟上,硬件马上量产不是问题。
最近泄漏的 Android 11 的新特性已经出现了可折叠屏幕的影子,但是具体情况恐怕要到因为疫情跳票的 Google I/O 大会上会揭晓答案。但是另一边,贼心不死的微软,已经开始布局面向可双屏设备的新一代操作系统 Windows 10X了。
图片来自 TheVerge
去年微软发布的两款双屏设备 Surface Duo 和 Surface Neo 并不都是采用尚未发布的 Windows 10X 操作系统,但是两者都沿用了几乎相同的交互逻辑,较小的 Neo 采用的是 Android 操作系统。这两款硬件和系统交互设计,将会在未来一段时间以内,成为双屏硬件的软件交互的重要参考和主要标杆,联想和戴尔这波 OEM 厂商,无疑是参考着微软的风向标来搞硬件产品的。
图片来自 TheVerge
传统而臃肿的「开始」菜单栏在 Windows 10X 当中,被精简为我们更熟悉的模式,新的 Windows 10X 在原有的 Windows 10 的基础上,应该有对移动端(比如 ARM 架构的CPU)和小屏幕有更好的支持。
但是,更有价值的,是微软为双屏设备所制定的交互设计规范。
下面是基于微软官方文档,精简编译后的规范:
双屏交互概述
双屏设备可以基于不同的工业设计,有多种硬件样式。微软发布的 Surface Neo 和 Surface Duo 可以作为典型的双屏设备作为参考。双屏本身可以借由铰链、转轴来连接,也可以基于柔性屏来实现。
所有的双屏设备都具备有折叠、旋转、翻转的功能,两块屏幕都可以用来作为显示,也可以一个做屏幕一个承载虚拟键盘,当然也可以借由外设,构建、组合成为新的模式。所以,为这样的硬件设计的时候,需要考虑到各种不同的情况,并且适配硬件,帮助用户实现更多的目标。
图片来自 TheVerge
当用户打开应用的时候,它的主要界面窗口应该最大化,占据一块屏幕的全宽和全高。这样用户可以一次打开多个不同的应用,显示在双屏上。
图片来自 TheVerge
当然,你的APP 也可以完整铺满两个屏幕,这个界面布局被称为「跨屏布局」。在默认情况下,它应该像在大屏幕上一样,一个窗口跨屏幕显示。但是你可以修改这种模式,让它可以铺满两个屏幕的同时,还可以兼顾到中间有转轴和铰链的硬件。对于这个问题,我们随后有详细的讨论。
响应式布局
比起传统的响应式布局,对于双屏硬件,我们要讨论的「响应」模式要复杂得多。就像下面这张图中所说的,要为这样多样、复杂的情况进行设计:
我们默认用户在多数时候,是处于双屏展开的状态,当用户打开 APP 的时候,它的主要界面窗口,将会最大化占据一个屏幕,这个时候另一个屏幕处于空置状态,用户可以在这个屏幕上打开另外的应用,并且用户可以通过托拽窗口的方式,来重新整理窗口和APP的排布模式。
同时,单个应用程序也应该可以进行跨屏布局,既可以让单个应用分别在两块屏幕上各呈现一个窗口,也可以作为单个窗口完整铺满两块屏幕。不论是充分利用接缝的存在,还是说尽可能地利用全部屏幕区域来聚焦单个内容,应用程序应该都可以做到。当然,这些情况我们随后会单独说到。
首先,作为一个已有的应用程序,在双屏设备上应该能够继承原有的功能,并且尽可能地兼容双屏的体验。在开始讨论如何为双屏场景进行设计应用之前,我们先应该对双屏交互进行介绍。
双屏的响应式布局
首先,无论屏幕尺寸如何,方向如何,应用程序应该都可以保持良好的外观,善用 UI 平台的现有的布局技术,通过合理地缩放来自适应,填满屏幕。如果你的屏幕元素依赖屏幕长宽比,那么应该善用平台给的 API 来进行灵活的优化。
考虑到你的应用将会在很多不同尺寸、不同长宽比、不同类型的设备上运行,所以你的应用程序应该足以应对各种不同的情况。请记住,你的设计将会遭遇和以往截然不同的屏幕尺寸和长宽比,比如纵向(全景视图)、横向(较宽的全景视图)、纵向双屏分别显示等不同情况。
考虑所有的屏幕方向
用户在很多平台上有习惯的、常见的屏幕方向,比如在 Android 和 iOS 上,通常应用是竖屏显示的,在 Windows 上,多数情况下是横向全屏显示的。而在双屏设备上,这种情况会发生改变。
比如你的应用原本是为竖屏设计的,但是需要经常输入内容,那么你要考虑到双屏设备上,你的应用可能是会被横屏显示,用户会像用笔记本电脑那样来使用应用,也就是说两块屏幕都横向显示,靠下平摊在桌面的屏幕会显示虚拟键盘或者手写区域,作为输入窗口,而显示窗口也是横向的。
双屏为多任务提供更好的显示环境,你不会知道用户会在什么样的场合,以什么样的姿势来握持设备,但是考虑潜在的使用姿态,可以让你更好得对应用进行设计和优化。
根据我们的研究,如果你的应用是注重输入的应用,那么用户在平面上打字和输入将会是最舒服也最常见的姿势。那么在这种情况下,你应该针对横屏显示进行针对性的优化。
支持多种输入模式
对于新的双屏设备,通常都支持多种输入模式,包括打字输入,屏幕触摸和手写笔这样的截至。这意味着用户可以灵活地根据需求,选择不同的姿势和输入模式,并且快速切换,以适应不同的需求。
换句话来说,就是你在设计的时候,需要支持所有的输入方式,以便用户可以自由选择交互模式。
托拽交互
你的应用应该支持屏幕托拽,这不仅是为了兼容双屏设备,而是对于绝大多数的设备的使用情况而进行兼容,确保用户体验的一致和灵活。只不过相比于在屏幕单屏上进行托拽移动,在双屏上托拽移动,将会带来更多的可能性,并且这样也将会在双屏使用场景之下,最为重要的交互模式之一。
为了确保托拽操作的自然,你需要确保诸如文本、图像、视频等常见的交互对象和元素,可以在任何地方进行剪切、复制、粘贴,并且对于共享和放松之类的操作也启用托拽操作,这将最大化地利用双屏的优势。
应用的多屏呈现
用户会希望在两块屏幕上并排显示同一应用中的不同内容,因此你的你用应该支持多实例呈现和运行。
多媒体内容画中画体验
如果你的应用是一个多媒体应用,那么应该支持画中画模式,用户可以边看视频边执行别的操作。
上面提及的很多功能属于基础应用要求,并不是专门针对双屏设备而做,但是如果你的应用支持上面的功能,那么在双屏上将会明显拥有更好的用户体验。接下来,我们着重聊一下在双屏设备上进行设计的问题。
在双屏设备上,你的应用应当支持在单个屏幕上运行,也可以在双屏上运行,当一个应用在两个屏幕上显示的时候,我们称之为「跨屏」,而跨屏显示这个问题对于双屏设备而言,是至关重要的,如何显示将会带来巨大的影响。这种独特交互模式可能会解锁前所未有的使用方法。比如,有转轴和接缝的双屏设备,因为屏幕的特征而非常适合分隔并行式的生产力解决方案。
跨屏是用户的选择
用户有选择如何使用应用的方式的权力,包括何时跨屏显示。某些应用可能在单屏或者跨屏显示的时候,看起来不够好看,但是如何使用的权力,应该交给用户去选择。
尽管本文会针对如何处理多屏布局提供几种不同的方案和想法,但是请选择适合你的用户和应用的呈现方式。
考虑用户意图和设备方向
当你的两个屏幕都被利用起来的时候(横向双屏,纵向双屏),了解用户的意图至关重要。尽管还有更多的调研需要做,但是结合我们目前已有的观察,可以得出如下的趋势:
在为双屏设备设计应用的时候,有四种常见的布局方案是你需要考虑的。通常这取决于应用是单屏还是跨屏,是默认视图还是全屏视图:
1、单屏默认模式
2、跨屏默认模式
3、单屏全屏模式
4、跨屏全屏模式
当单个应用以单个窗口运行,并且跨越两个屏幕的时候,跨屏布局就出现了。如果你原有的应用从未针对双屏设备进行优化的话,那么系统会提示你「应用将会扩展并占据所有屏幕」,并且这个时候,应用界面会自行调整大小,适应新的尺寸。
这种情况下,界面中间的接缝会显得非常明显。这是双屏设备先天的副产物。要如何优雅地处理接缝?这就是下面这节内容将会探讨的问题,我们将会提供一些常见的处理方案yi。
是否总是要适应接缝?
如果你的应用不作任何优化就直接在双屏设备上投放使用,接缝并不总会给用户体验带来影响。比如地图类应用,用户可以随意移动地图内容,接缝带来的割裂并不会对使用体验造成实质性的影响。在后面「扩展画布」这一节,将会对这个问题进行深入讨论。
但是对于另外一部分应用,接缝带来的问题就非常严重了。比如在一个表格类应用当中,如果不作修改和调整,有的内容会直接被接缝给割裂开,你必须进行滚动才能正常查看。而对于某些相对更加固定无法移动的元素而言,接缝带来的体验是破坏性的。而这个时候,我们需要使用一些技术方案来处理这个问题。
规避接缝
将元素移到一边
由于两块屏幕之间有明显的接缝,因此当用户在使用应用的时候,某些 UI 元素可能会正好被穿过接缝,逻辑上这不会影响功能,但是如果将这些 UI 元素移动到屏幕的一边来显示,会提供更好的体验。最好避免在接缝处显示文本内容,这会影响可读性。
应用程序对话框应该移到屏幕的一边,尤其是需要点击按钮操作的时候。
底部菜单应该移动到屏幕一侧,而不是延伸到两个屏幕上。
用户调用上下文菜单的时候,应该将接缝视作为屏幕边界处理,尤其是在靠近屏幕边缘的地方触发菜单的时候。
应用内的下拉菜单或者可扩展容器如果可能会跨越接缝的话,应该改变扩展方向。
当整个应用界面扩展开来的时候,应该整个移动到屏幕的上侧,而不是在靠近中心的位置横跨接缝。
贴合接缝
使用偶数列并和接缝对齐
当界面中使用网格布局的时候,垂直或者水平方向尽量使用偶数行或者偶数列,这样可以让接缝和界面间隙正好重合,用户可以更加舒适地查看信息。
在网格中使用偶数列,尤其是对于容器、表单,并且考虑到接缝来控制间距。
除此之外,还有许多应用会考虑充分利用另外一个屏幕来显示弹出菜单或者下级页面的内容。这种使用逻辑确实会让应用更加易用,并且在视觉上会更加干净清爽。但是请记住,如果弹出的界面并不是全屏的,可能会暗示它是可折叠和可关闭的,因此,你需要根据实际的设计需求,来灵活的处理呈现样式。全覆盖另外一屏的弹出界面,更加适合小尺寸屏幕。
重新排列 UI 元素
移动到接缝的任一侧
还有一种用来优化响应式布局的方法是,当屏幕方向或者大小发生变化的时候,重新排列你的内容。这种方式让你可以在两个屏幕上随意扩展你的内容,你可以通过分组来重新排列,以更有目的的方式来适配屏幕和内容。
遮罩和分割
对于一些无法重新排列的元素,比如全屏图片和视频,这个时候只能使用遮罩和分割的方式来处理。
遮罩的思路是,将接缝视作为一个遮罩元素,而图片被它给遮挡了一部分,根据格式塔原理,我们的大脑会自动补足缺少的部分,遮罩遮罩处理方式适合处理多媒体(视频,图片等)这样的画布类型的场景,在这些场景下,保持图像的连续性比显示内容的完整性更加重要。
分割的思路是将内容均匀切割为两个部分,完整呈现,这对于包含有多个控件和元素的普通界面而言,是更加合理的处理方式,包括可能会出现在屏幕中间的按钮。
根据类型的不同,这两种处理方式各有优势,我们将继续跟进不同的用户行为特征,来寻求更优的解决方案。
文章来源:优设
旅程映射创建了一个完整的体验视图,正是这一过程将不同的数据点聚集在一起并进行可视化处理,以了解产品需求,从而可以吸引各个群体中不感兴趣的利益相关者,并促进协作性对话和变革。可通过揭示一系列交互过程中沮丧和愉悦的时刻来帮助了解客户体验,揭示了满足客户痛点,减轻分散性的机会,并最终通过暴露新机会提供附加价值而最终使产品脱颖而出。
如何使用旅程映射来了解与公司互动过程中的客户行为,思维方式和情感动机。旅程映射在理解和优化客户体验方面的实际应用,以及收集研究和从该研究中得出真实叙述的方法。
了解旅程图何时是有用的设计工具,以及如何向拥有预算批准的客户或团队成员阐明该工具的优点。如何使用成品传达见解,与跨部门团队成员互动以及如何通过发现激发变化。
旅程映射分为4条泳道:阶段,动作,思想,心态/情绪。省略大多数流程细节,反映了用户的思想,思考和情感。
旅程映射的价值:
客户旅程图的目标
将服务蓝图视为客户旅程图的第二部分。它们是旅程地图的扩展,但它们不是专注于用户(并从用户的角度出发),而是专注于业务(并以其视角)。他们可以在特定客户旅程中的各个接触点上可视化不同服务组件(例如人员或流程)之间的关系。客户旅程图之后,在进行组织或流程更改之前,内部查明漏斗或断点时使用服务蓝图。
客户旅程地图的目的是更好地了解最终用户的旅程。这段旅程包括他们的思想和情感。相反,服务蓝图反映了组织的观点,因此包括前期行动,后台行动和支持流程。客户旅程地图的主要重点是了解有关最终用户的更多信息,而服务蓝图的重点是记录组织如何创建这种体验。
制定有效旅程图的五个步骤
界限
对于要创建多少个旅程图没有严格的规定。旅程映射作为一个过程是有益的,因为它在团队成员之间建立了共同的愿景。通常,客户旅程图越集中,越好。在一种情况下,专注于一个角色的旅程图讲述了一个清晰的故事。
宽度与深度
确定旅程映射的范围广度,过程和范围的不一致和含糊不清会导致失败。
要素的平衡和重点
要素:角色,情境,动作,心态,情绪,接触点,渠道,发现。渗透各个要素及以接触点为重点从而发现机会点。
使用环境
明确使用环境,在如何的环境下使用,物理环境以及数字环境等。
接触点和渠道
接触点代表客户与组织之间的特定交互。包括正在使用的设备,用于交互的通道及已完成的特定任务。客户旅程由一系列接触点组成,每个接触点定义了特定交互的细节。地图应使接触点(地图中的参与者实际与公司互动的时间)和渠道(通信或服务提供方法,例如网站或实体商店)与用户目标和行动对齐。这些元素值得特别强调,因为它们经常是发现品牌不一致和脱节的体验的地方。
语境查询
观察用户执行任务时,您可以提出问题,从而可以澄清您的观察并引发开放式对话。
任务分析
任务分析最常见的产出物就是那些对用户为达成目标所采取步骤/行为的描绘。当我们把所有这些步骤都解析清楚了,就很容易发现用户在哪些步骤中付出了额外的努力,哪些步骤是能够直接去除以缩短操作流程的。
日记研究
由于客户旅程会随着时间的流逝并通过许多不同的渠道发生,因此日记研究是了解用户随时间推移的想法,感觉和动作的一种特别有用的方法。日记研究是一项长期研究:要求用户记录与特定目标相关的每项操作,以及他们在互动过程中的感受很多天,几周或几个月。由于参与者的行为,感受和想法尽可能接近实时地捕获,因此消除了访谈所依赖的(容易出错的)记忆。还在旅程的所有阶段(而不是一个阶段)从参与者那里获取数据。日记研究的建立成本低廉,可以在进行其他类型的研究时在后台运行。
定量支持
旅程地图应该产生真实的叙述,而不是童话故事。从收集任何现有研究开始,需要其他基于旅程的研究来填补现有研究无法涵盖的空白。这是一个定性研究过程。虽然定量数据可以帮助支持或验证(或帮助说服可能将定性数据视为「模糊」的利益相关者),但仅凭定量数据无法建立故事。
旅程映射过程的整个重点是发现用户体验中的差距(这在全渠道旅程中尤为常见),然后采取行动来优化体验。洞察力和所有权是经常被忽略的关键要素。从旅程映射中得出的任何见解都应明确列出。可以为旅程地图的不同部分分配所有权,以便清楚地知道谁负责客户旅程的哪个方面。没有所有权,没有人有责任或权力去改变任何东西。
文章来源:优设 作者:Design Thinker
蓝蓝设计的小编 http://www.lanlanwork.com