首页

如何在网页前端里可视化你的知识图谱

前端达人

如何在网页前端里可视化你的知识图谱
最近费尽千辛万苦构造了一份可以用(大概)的知识图谱,并且把要利用知识图谱做的领域命名实体识别和一些推荐的功能做成Web版的demo,顺带想实现一些可视化知识图谱的功能。

(凭啥知识图谱就只能在Neo4j里自嗨,不能来前端show一下,歧视吗(¬_¬))

找了做前端图表展示的开源库,D3.js和Echarts都能做,我拿Echarts实现了一下功能,先看一下在现在项目里一个基于知识图谱查询的实际效果:
20200314114824402.png

接下里看看如何的实现:

  1. 首先在本地下载Echarts相关的js文件,在线引用也可以,html文件里如下引用:
 <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>


3.设置好节点和链接关系,这里为了简单手写了一个苹果梨子和水果之间的关系,项目里采用Django框架的交互读取查询的结果放入节点(data)和链接(links)里面了:

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}
    ]


置Echarts图:

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);
这样就成功实现了一个简单的图谱可视化:

20200314115929363.png



————————————————
版权声明:本文为CSDN博主「游离态GLZ不可能是金融技术宅」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37477357/article/details/104857495


JavaWeb项目之实现用户注册、登录与预约功能

前端达人

JavaWeb项目之实现用户注册、登录与预约功能


  • 四:效果展示
  • 一:项目需求

    1.实现注册与登录功能:
    要求用到验证码,登录后该出不再显示登录与注册,而是显示用户名。
    2.实现预约功能:
    实现“运动”与“学习”两方面的邀约功能,并将邀约数据保存到数据库中,数据库使用Mysql。
    运动可以邀约:篮球、足球、乒乓球等
    学习可以邀约:自习、辅导等

    二:总体概述

    在正式开始编码之前,需要先导入相关jar包并配置好相关的配置文件,同时也需要导入前端给的页面代码。接着是建立好相应的数据库结构,并初步构建好三层架构的想法思路。

    20200313144400508.png

   20200313144131716.png

20200313144239593.png



三:代码分析

1.登录功能

web层

20200313132713991.png


  • 20200313133324242.png

  • service层

  • 2020031313345737.png

  • dao层

  • 20200313133603198.png

  • 然后在这里写一下对于验证码处理和点击图片更换验证码功能的一些细节。
    如下图所示,为了保证servlet层能够正确接收到界面所展示的验证码信息,同时因为session对象是项目自生成的,所以我直接获取session对象并以类似于键值对的形式将页面验证码信息存入session中。

  • 接下来是jsp页面对于验证码展示的一些处理

  • 20200313135922196.png

  • 20200313135956797.png

在这里,因为点击验证码更换操作需要用到js,所以我百度得到了上图这样一串代码。其中时间戳的作用是通过改变每次请求的时间参数来获得刷新效果,即改变url中的响应头信息。

2.注册功能
事实上,有了登录功能的实现,注册功能的代码与其都是大同小异的。最大的不同应该就是Dao层执行的操作不同

20200313142134901.png

3.预约功能

预约功能的实现更是与注册功能的实现基本一致。所不同的应该是jsp页面对单选框输入的设置。

20200313142805359.png


四:效果展示

点击查看原图




原生代码之实现轮播图(左右翻页,定时翻页,指定翻页)

前端达人

首先在写代码之前我们需要理清如何穿插图片呢?



可以让所有图片都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学习笔记(一)——CSS基础&选择器合集

前端达人

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:; }

20200313203814532.png

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>


style标记定义HTML文档的样式信息,规定的是 HTML 元素如何在浏览器中呈现,其中type用来指定元素中的内容类型。

链入外部样式表
当为了保证站点的风格统一,或当定义样式内容较多,且需要多个页面共享样式时,可使用外部样式表。链入外部样式表是把样式表保存为一个外部样式表文件,然后在页面中用link标记链接到这个样式表文件,link标记放在页面的head区内。其基本语法为:

<head>
        <meta charset="utf-8" />
        <title></title>
        <link href="样式表路径" rel="stylesheet" type="text/css" />
    </head>
其中:
href:指出样式表存放的路径。
rel:用来定义链接的文件与HTML之间的关系, rel="stylesheet"是指在页面中使用这个外部的样式表。
type属性用于指定文件类型,“text/css”指文件的类型是样式表文本。

导入外部样式表
导入外部样式表是指在HTML文件头部的style元素里导入一个外部样式表,导入外部样式表采用import方式。导入外部样式表和链入样式表的方法很相似,但导入外部样式表的样式实质上相当于存在网页内部。其基本语法为:
————————————————
版权声明:本文为CSDN博主「狗狗狗狗狗乐啊」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44122062/article/details/104848745

<head>
        <meta charset="utf-8" />
        <title></title>
        <style type="text/css">
            @import url("样式表路径");
        </style>
    </head>
其中:
href:指出样式表存放的路径。
rel:用来定义链接的文件与HTML之间的关系, rel="stylesheet"是指在页面中使用这个外部的样式表。
type属性用于指定文件类型,“text/css”指文件的类型是样式表文本。

导入外部样式表
导入外部样式表是指在HTML文件头部的style元素里导入一个外部样式表,导入外部样式表采用import方式。导入外部样式表和链入样式表的方法很相似,但导入外部样式表的样式实质上相当于存在网页内部。其基本语法为:

  <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


Vue移动端项目优化过程

前端达人

文章目录

前言

一、白屏时间过长分析

二、针对性优化

针对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打包后生成的文件大小,看还有没有可以优化的余地。由于项目中已经通过路由按需加载的方式来做了功能拆分,所以通过webpack打包后生成了很多分散的js文件,如下图:


20200313153537713.png

通过上图分析可以知道打包后有几个文件相对较大,vendor.js都知道是第三方库文件打包形成,之前通过mint-ui按需加载会有一定的变化,后面记录。这里着重看另两个带hash的js文件,这里并看不出来它为什么这么大,所以这里需要用到webpack打包分析工具来做进一步的打包文件分析:webpack-bundle-analyzer

webpack-bundle-analyzer打包分析

它的作用如下图,即在打包后生成打包文件大小分析图,方便我们更加直观的看到文件大小和引用情况

点击查看原图



  • 这里先介绍下webpack-bundle-analyzer的简单使用
  1. 安装
npm intall -D webpack-bundle-analyzer
  1. 修改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中的数据类型转化。

首先我们要知道在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 也可以完整铺满两个屏幕,这个界面布局被称为「跨屏布局」。在默认情况下,它应该像在大屏幕上一样,一个窗口跨屏幕显示。但是你可以修改这种模式,让它可以铺满两个屏幕的同时,还可以兼顾到中间有转轴和铰链的硬件。对于这个问题,我们随后有详细的讨论。

1、拥抱和改进现有的功能

响应式布局

比起传统的响应式布局,对于双屏硬件,我们要讨论的「响应」模式要复杂得多。就像下面这张图中所说的,要为这样多样、复杂的情况进行设计:

我们默认用户在多数时候,是处于双屏展开的状态,当用户打开 APP 的时候,它的主要界面窗口,将会最大化占据一个屏幕,这个时候另一个屏幕处于空置状态,用户可以在这个屏幕上打开另外的应用,并且用户可以通过托拽窗口的方式,来重新整理窗口和APP的排布模式。

同时,单个应用程序也应该可以进行跨屏布局,既可以让单个应用分别在两块屏幕上各呈现一个窗口,也可以作为单个窗口完整铺满两块屏幕。不论是充分利用接缝的存在,还是说尽可能地利用全部屏幕区域来聚焦单个内容,应用程序应该都可以做到。当然,这些情况我们随后会单独说到。

2、拥抱和改进现有的功能

首先,作为一个已有的应用程序,在双屏设备上应该能够继承原有的功能,并且尽可能地兼容双屏的体验。在开始讨论如何为双屏场景进行设计应用之前,我们先应该对双屏交互进行介绍。

双屏的响应式布局

首先,无论屏幕尺寸如何,方向如何,应用程序应该都可以保持良好的外观,善用 UI 平台的现有的布局技术,通过合理地缩放来自适应,填满屏幕。如果你的屏幕元素依赖屏幕长宽比,那么应该善用平台给的 API 来进行灵活的优化。

考虑到你的应用将会在很多不同尺寸、不同长宽比、不同类型的设备上运行,所以你的应用程序应该足以应对各种不同的情况。请记住,你的设计将会遭遇和以往截然不同的屏幕尺寸和长宽比,比如纵向(全景视图)、横向(较宽的全景视图)、纵向双屏分别显示等不同情况。

考虑所有的屏幕方向

用户在很多平台上有习惯的、常见的屏幕方向,比如在 Android 和 iOS 上,通常应用是竖屏显示的,在 Windows 上,多数情况下是横向全屏显示的。而在双屏设备上,这种情况会发生改变。

比如你的应用原本是为竖屏设计的,但是需要经常输入内容,那么你要考虑到双屏设备上,你的应用可能是会被横屏显示,用户会像用笔记本电脑那样来使用应用,也就是说两块屏幕都横向显示,靠下平摊在桌面的屏幕会显示虚拟键盘或者手写区域,作为输入窗口,而显示窗口也是横向的。

双屏为多任务提供更好的显示环境,你不会知道用户会在什么样的场合,以什么样的姿势来握持设备,但是考虑潜在的使用姿态,可以让你更好得对应用进行设计和优化。

根据我们的研究,如果你的应用是注重输入的应用,那么用户在平面上打字和输入将会是最舒服也最常见的姿势。那么在这种情况下,你应该针对横屏显示进行针对性的优化。

支持多种输入模式

对于新的双屏设备,通常都支持多种输入模式,包括打字输入,屏幕触摸和手写笔这样的截至。这意味着用户可以灵活地根据需求,选择不同的姿势和输入模式,并且快速切换,以适应不同的需求。

换句话来说,就是你在设计的时候,需要支持所有的输入方式,以便用户可以自由选择交互模式。

托拽交互

你的应用应该支持屏幕托拽,这不仅是为了兼容双屏设备,而是对于绝大多数的设备的使用情况而进行兼容,确保用户体验的一致和灵活。只不过相比于在屏幕单屏上进行托拽移动,在双屏上托拽移动,将会带来更多的可能性,并且这样也将会在双屏使用场景之下,最为重要的交互模式之一。

为了确保托拽操作的自然,你需要确保诸如文本、图像、视频等常见的交互对象和元素,可以在任何地方进行剪切、复制、粘贴,并且对于共享和放松之类的操作也启用托拽操作,这将最大化地利用双屏的优势。

应用的多屏呈现

用户会希望在两块屏幕上并排显示同一应用中的不同内容,因此你的你用应该支持多实例呈现和运行。

多媒体内容画中画体验

如果你的应用是一个多媒体应用,那么应该支持画中画模式,用户可以边看视频边执行别的操作。

3、双屏用户体验常见注意事项

上面提及的很多功能属于基础应用要求,并不是专门针对双屏设备而做,但是如果你的应用支持上面的功能,那么在双屏上将会明显拥有更好的用户体验。接下来,我们着重聊一下在双屏设备上进行设计的问题。

在双屏设备上,你的应用应当支持在单个屏幕上运行,也可以在双屏上运行,当一个应用在两个屏幕上显示的时候,我们称之为「跨屏」,而跨屏显示这个问题对于双屏设备而言,是至关重要的,如何显示将会带来巨大的影响。这种独特交互模式可能会解锁前所未有的使用方法。比如,有转轴和接缝的双屏设备,因为屏幕的特征而非常适合分隔并行式的生产力解决方案。

  1. 在设计双屏设备之前,你需要遵循下面的四个基本原则:
  2. 提供持续的价值:能够良好地支持不同的交互模式,充分利用不同交互模式和多屏交互,让用户可以灵活地执行任务。它不应该只有有限的使用方法和模式,与其简单的支持一两种模式,不如多考虑几种不同的交互模式。
    不要只想着「跨屏」:应用不应该只在跨屏状态下才好用,不要将一些基本的功能在非跨屏状态下隐藏,避免用户需要跨屏才能用到基本功能。
  3. 用户始终享有掌控力:为了避免给用户带来不可预期的破坏性体验,是否要跨屏,这个应该由用户自己来进行选择,而不是一打开就跨屏。
  4. 让跨屏可预测:了解用户使用跨屏模式的场景,并且使用贴合用户预期的设计。确保不同的跨屏模式和呈现结果是用户可预期的。

跨屏是用户的选择

用户有选择如何使用应用的方式的权力,包括何时跨屏显示。某些应用可能在单屏或者跨屏显示的时候,看起来不够好看,但是如何使用的权力,应该交给用户去选择。

尽管本文会针对如何处理多屏布局提供几种不同的方案和想法,但是请选择适合你的用户和应用的呈现方式。

考虑用户意图和设备方向

当你的两个屏幕都被利用起来的时候(横向双屏,纵向双屏),了解用户的意图至关重要。尽管还有更多的调研需要做,但是结合我们目前已有的观察,可以得出如下的趋势:

  • 在横向双屏模式下,用户更多希望充分利用屏幕空间,因此量屏幕多是用来扩展展示内容;
  • 在纵向双屏模式下,用户通常喜欢执行多任务或者提高生产力的活动。因此这两块屏幕会被分开使用,或者分组使用。
    考虑所有支持的布局

在为双屏设备设计应用的时候,有四种常见的布局方案是你需要考虑的。通常这取决于应用是单屏还是跨屏,是默认视图还是全屏视图:

1、单屏默认模式

  • 默认情况下,应用程序应该是最大化状态占据一个屏幕。在双屏分别显示模式下,用户可以单独同两屏的应用界面进行交互和处理,确保可以进行使用、比较甚至交叉引用。
  • 这个状态应该是默认的。就像 之前说的,如果你的应用已经支持了不同分辨率、不同长宽比的屏幕,那么你不用做其他更多的事情。

2、跨屏默认模式

  • 当设备处于双屏状态下(横屏双屏或者竖屏双屏),用户可以将单个窗口从一个屏幕直接延伸覆盖两个屏幕,为内容呈现提供更多的空间。这应该是用户自己的选择,而不应该作为默认打开的模式固化到程序和设置当中。
  • 这一模式应该是可选的。这种跨屏显示单个窗口的模式,应该是双屏设备所独有的。如果你对于你的应用不做 针对性(针对双屏)的修改的话,它会像是在一个完整的大屏幕上显示一样。但是,你也可以针对双屏进行优化,确保你的应用可以兼容双屏设备的独特形态。这些将在后续详细说明。

3、单屏全屏模式

  • 这种模式和之前的单屏默认模式是类似的,但是系统的UI(系统的任务栏、菜单栏、程序菜单、顶部标题等)将会隐藏,这样可以给你带来沉浸式的体验,是游戏和视频类应用的理想选择。
  • 这种模式应该是可选的。你可以使用系统提供的 API 来实现单屏全屏模式。

4、跨屏全屏模式

  • 同样的,你可以通过开发和优化来实现适合双屏的跨屏显示模式。如果用户在跨屏的时候选择的是跨屏全屏显示模式,那么应用在扩展之后,将会覆盖整个屏幕,并隐藏系统UI 元素。
  • 这种模式应该是可选的,你需要考虑的因素和跨屏默认模式类似。

4、如何处理接缝

当单个应用以单个窗口运行,并且跨越两个屏幕的时候,跨屏布局就出现了。如果你原有的应用从未针对双屏设备进行优化的话,那么系统会提示你「应用将会扩展并占据所有屏幕」,并且这个时候,应用界面会自行调整大小,适应新的尺寸。

这种情况下,界面中间的接缝会显得非常明显。这是双屏设备先天的副产物。要如何优雅地处理接缝?这就是下面这节内容将会探讨的问题,我们将会提供一些常见的处理方案yi。

是否总是要适应接缝?

如果你的应用不作任何优化就直接在双屏设备上投放使用,接缝并不总会给用户体验带来影响。比如地图类应用,用户可以随意移动地图内容,接缝带来的割裂并不会对使用体验造成实质性的影响。在后面「扩展画布」这一节,将会对这个问题进行深入讨论。

但是对于另外一部分应用,接缝带来的问题就非常严重了。比如在一个表格类应用当中,如果不作修改和调整,有的内容会直接被接缝给割裂开,你必须进行滚动才能正常查看。而对于某些相对更加固定无法移动的元素而言,接缝带来的体验是破坏性的。而这个时候,我们需要使用一些技术方案来处理这个问题。

规避接缝

将元素移到一边

由于两块屏幕之间有明显的接缝,因此当用户在使用应用的时候,某些 UI 元素可能会正好被穿过接缝,逻辑上这不会影响功能,但是如果将这些 UI 元素移动到屏幕的一边来显示,会提供更好的体验。最好避免在接缝处显示文本内容,这会影响可读性。

应用程序对话框应该移到屏幕的一边,尤其是需要点击按钮操作的时候。

底部菜单应该移动到屏幕一侧,而不是延伸到两个屏幕上。

用户调用上下文菜单的时候,应该将接缝视作为屏幕边界处理,尤其是在靠近屏幕边缘的地方触发菜单的时候。

应用内的下拉菜单或者可扩展容器如果可能会跨越接缝的话,应该改变扩展方向。

当整个应用界面扩展开来的时候,应该整个移动到屏幕的上侧,而不是在靠近中心的位置横跨接缝。

贴合接缝

使用偶数列并和接缝对齐

当界面中使用网格布局的时候,垂直或者水平方向尽量使用偶数行或者偶数列,这样可以让接缝和界面间隙正好重合,用户可以更加舒适地查看信息。

在网格中使用偶数列,尤其是对于容器、表单,并且考虑到接缝来控制间距。

除此之外,还有许多应用会考虑充分利用另外一个屏幕来显示弹出菜单或者下级页面的内容。这种使用逻辑确实会让应用更加易用,并且在视觉上会更加干净清爽。但是请记住,如果弹出的界面并不是全屏的,可能会暗示它是可折叠和可关闭的,因此,你需要根据实际的设计需求,来灵活的处理呈现样式。全覆盖另外一屏的弹出界面,更加适合小尺寸屏幕。

重新排列 UI 元素

移动到接缝的任一侧

还有一种用来优化响应式布局的方法是,当屏幕方向或者大小发生变化的时候,重新排列你的内容。这种方式让你可以在两个屏幕上随意扩展你的内容,你可以通过分组来重新排列,以更有目的的方式来适配屏幕和内容。

遮罩和分割

对于一些无法重新排列的元素,比如全屏图片和视频,这个时候只能使用遮罩和分割的方式来处理。

遮罩的思路是,将接缝视作为一个遮罩元素,而图片被它给遮挡了一部分,根据格式塔原理,我们的大脑会自动补足缺少的部分,遮罩遮罩处理方式适合处理多媒体(视频,图片等)这样的画布类型的场景,在这些场景下,保持图像的连续性比显示内容的完整性更加重要。

分割的思路是将内容均匀切割为两个部分,完整呈现,这对于包含有多个控件和元素的普通界面而言,是更加合理的处理方式,包括可能会出现在屏幕中间的按钮。

根据类型的不同,这两种处理方式各有优势,我们将继续跟进不同的用户行为特征,来寻求更优的解决方案。

文章来源:优设   

「旅程映射」的知识点

雪涛

旅程映射创建了一个完整的体验视图,正是这一过程将不同的数据点聚集在一起并进行可视化处理,以了解产品需求,从而可以吸引各个群体中不感兴趣的利益相关者,并促进协作性对话和变革。可通过揭示一系列交互过程中沮丧和愉悦的时刻来帮助了解客户体验,揭示了满足客户痛点,减轻分散性的机会,并最终通过暴露新机会提供附加价值而最终使产品脱颖而出。

如何使用旅程映射来了解与公司互动过程中的客户行为,思维方式和情感动机。旅程映射在理解和优化客户体验方面的实际应用,以及收集研究和从该研究中得出真实叙述的方法。

了解旅程图何时是有用的设计工具,以及如何向拥有预算批准的客户或团队成员阐明该工具的优点。如何使用成品传达见解,与跨部门团队成员互动以及如何通过发现激发变化。

旅程映射分为4条泳道:阶段,动作,思想,心态/情绪。省略大多数流程细节,反映了用户的思想,思考和情感。

旅程映射的价值:

  • 查明引起痛苦或愉悦的特定客户旅程接触点
  • 打破孤岛,以在组织范围内对客户旅程建立一种共享的理解
  • 在前往内部部门的旅途中分配关键接触点的所有权

  • A区:镜头通过分配(1)角色(「谁」)和(2)要检查的场景(「 what」)来为地图提供约束。
  • B区:地图的核心是可视化的体验,通常跨旅程的(3)个大块阶段对齐。用户在整个旅程中的(4)动作,(5)想法和(6)情感体验可以用研究的引文或视频加以补充。
  • C区:输出应根据地图支持的业务目标而有所不同,但是它可以描述发现的见解和痛点,以及(7)着眼于前进的机会以及(8)内部所有权。

客户旅程图的目标

  • 建立同理心
  • 推动对话和参与
  • 建立共识
  • 揭示机会

旅程地图与服务蓝图

将服务蓝图视为客户旅程图的第二部分。它们是旅程地图的扩展,但它们不是专注于用户(并从用户的角度出发),而是专注于业务(并以其视角)。他们可以在特定客户旅程中的各个接触点上可视化不同服务组件(例如人员或流程)之间的关系。客户旅程图之后,在进行组织或流程更改之前,内部查明漏斗或断点时使用服务蓝图。

客户旅程地图的目的是更好地了解最终用户的旅程。这段旅程包括他们的思想和情感。相反,服务蓝图反映了组织的观点,因此包括前期行动,后台行动和支持流程。客户旅程地图的主要重点是了解有关最终用户的更多信息,而服务蓝图的重点是记录组织如何创建这种体验。

如何构建旅程映射?

制定有效旅程图的五个步骤

1. 确定关键的前期约束

界限

对于要创建多少个旅程图没有严格的规定。旅程映射作为一个过程是有益的,因为它在团队成员之间建立了共同的愿景。通常,客户旅程图越集中,越好。在一种情况下,专注于一个角色的旅程图讲述了一个清晰的故事。

宽度与深度

确定旅程映射的范围广度,过程和范围的不一致和含糊不清会导致失败。

要素的平衡和重点

要素:角色,情境,动作,心态,情绪,接触点,渠道,发现。渗透各个要素及以接触点为重点从而发现机会点。

使用环境

明确使用环境,在如何的环境下使用,物理环境以及数字环境等。

接触点和渠道

接触点代表客户与组织之间的特定交互。包括正在使用的设备,用于交互的通道及已完成的特定任务。客户旅程由一系列接触点组成,每个接触点定义了特定交互的细节。地图应使接触点(地图中的参与者实际与公司互动的时间)和渠道(通信或服务提供方法,例如网站或实体商店)与用户目标和行动对齐。这些元素值得特别强调,因为它们经常是发现品牌不一致和脱节的体验的地方。

2. 收集研究

语境查询

观察用户执行任务时,您可以提出问题,从而可以澄清您的观察并引发开放式对话。

任务分析

任务分析最常见的产出物就是那些对用户为达成目标所采取步骤/行为的描绘。当我们把所有这些步骤都解析清楚了,就很容易发现用户在哪些步骤中付出了额外的努力,哪些步骤是能够直接去除以缩短操作流程的。

日记研究

由于客户旅程会随着时间的流逝并通过许多不同的渠道发生,因此日记研究是了解用户随时间推移的想法,感觉和动作的一种特别有用的方法。日记研究是一项长期研究:要求用户记录与特定目标相关的每项操作,以及他们在互动过程中的感受很多天,几周或几个月。由于参与者的行为,感受和想法尽可能接近实时地捕获,因此消除了访谈所依赖的(容易出错的)记忆。还在旅程的所有阶段(而不是一个阶段)从参与者那里获取数据。日记研究的建立成本低廉,可以在进行其他类型的研究时在后台运行。

定量支持

旅程地图应该产生真实的叙述,而不是童话故事。从收集任何现有研究开始,需要其他基于旅程的研究来填补现有研究无法涵盖的空白。这是一个定性研究过程。虽然定量数据可以帮助支持或验证(或帮助说服可能将定性数据视为「模糊」的利益相关者),但仅凭定量数据无法建立故事。

3. 综合发现
  • 建立行动者价值链
  • 记录角色
  • 确定方案
  • 调整行动,思维方式和情绪
4. 评估体验
  • 过渡性波动
  • 差距与机遇
  • 关键时刻
  • 价值交换
5. 制作视觉叙述
  • 识别关键组件
  • 将见解与细节分开
  • 突出机会领域
  • 确认您的关键要点已传达

旅程映射过程的整个重点是发现用户体验中的差距(这在全渠道旅程中尤为常见),然后采取行动来优化体验。洞察力和所有权是经常被忽略的关键要素。从旅程映射中得出的任何见解都应明确列出。可以为旅程地图的不同部分分配所有权,以便清楚地知道谁负责客户旅程的哪个方面。没有所有权,没有人有责任或权力去改变任何东西。

文章来源:优设    作者:Design Thinker

用交互经典四原则,帮你做好导航栏设计

雪涛

在这之前我得先提及一本书──《简约至上:交互式设计四策略》。这本书基本算得上是交互设计的入门必读书籍了,非常适合身处项目环节中上游的人员阅读与学习。

作者 Giles Colborne 在书中提出了四个令交互设计成果最大化的简易策略:合理删除、分层组织、适时隐藏和巧妙转移。这四个策略几乎成为我设计与优化每一个页面时的自我指导方针。

我参阅了大量的应用,想总结出它们是如何运用导航栏来给产品赋能的。竟然很巧地发现,再花式的导航栏设计也难逃「四策略」手法。

首先,导航栏作为一个独立控件,它本身就已经是「分层组织」策略的一种表现形式。接下来我们来看看,优秀的产品设计是如何运用另外三种策略来设计好导航栏的。

合理删除

导航栏不能轻易删除,但凡事没有绝对。什么时候我们可以合理地删除导航栏呢?

Nike Run Club(下文简称NRC)是耐克官方出品的一款跑步记录 APP。既然做产品要站在用户角度出发,那我们就来复原一下主要功能的用户使用场景。

当你的老板要求你一天出 150 个界面设计的时候,你怕了,准备跑路,同时又不想浪费一天中任何一次记录运动的机会。于是你打开 NRC,你的目的很明确:认真地跑路,并记录运动。

点击「开始」按钮,当你一旦开始跑步,手机基本就不再使用了,直到跑步结束。

△ NRC在运动状态下的界面删除了导航栏

在用户记录跑步这样一个单一事件中,NRC 知道你会专注运动,很少存在关注其他功能、浏览其他页面的可能性。于是 NRC 可以很干脆地删掉导航栏,而返回按钮用了界面中的「结束」按钮代替。

滴滴出行在呼叫快车时也做了删除导航栏的处理。用户一旦发单,开始呼叫司机时,呼叫页面内的所有操作都只聚集在界面下方的一个视觉区域内。

△ 滴滴出行在呼叫过程中删除了导航栏

上面两个删除导航栏的示例有什么共通点呢?

第一,用户在当前页面的事件状态明确,不需要导航标题提醒用户当前在什么位置,用户也极少可能在当前页面发生其他事件操作,于是完全可以去除导航标题与内容控件。

第二,虽然删除了返回按钮,但都采用了很典型的「费茨定律」,就算用户误操作,也能便捷地撤销正在发生的事件。反而这比循规蹈矩地运用导航栏来承载返回按钮合理了许多。

△ 费茨定律简易图解

既然导航栏内所有的规范元素都有可取代方案,为什么不删除它呢?正如 Giles Colborne 在书中告诉我们的:大胆地删除,但也不要极端到盲目删除。

适时隐藏

隐藏和删除看起来十分相似,但其实不然。我们如何区分这两个技巧呢?

隐藏最常见的情况是,当导航栏的出现会成为打扰用户沉浸体验的障碍时,我们会选择隐藏,例如看视频、浏览图片等显示全屏媒体的场景,有导航栏反而会分散用户的注意力。

△ 显示全屏媒体时需要隐藏导航栏

不知道你有没有发现到一个细节,在大多数情况下,需要沉浸体验的页面不但会隐藏导航栏,同时也会隐藏状态栏,导航栏中载有当前页面的标题、导航按钮和内容控件;状态栏中会载有时间、Wi-Fi 等系统设备信息。

iOS 在人机交互指南中提醒我们,显示全屏媒体时,请考虑暂时隐藏状态栏,但请避免永久隐藏。如果没有状态栏,当用户需要查看时间或其他设备信息时必须离开应用。设计师应该让用户可以使用简单的手势重新显示隐藏的状态栏。

△ 用户可以方便地查看时间或其他设备信息

另一种情况是当前页面非常注重一屏内容展现时,我们会隐藏导航栏。

京东在用户搜索了商品之后,头部有三个信息栏,非常冗长。分别是:

  • 导航栏:放置搜索框和页面内容控件;
  • 全局筛选栏:针对全局的筛选组件,主要用于商品排序筛选;
  • 垂直内容筛选栏:当前所搜索的商品品类的垂直筛选标签。

△ 京东搜索商品后屏幕头部的信息栏

用户在搜索了商品之后,向上滑动页面,京东会隐藏导航栏和全局筛选栏。

一是因为用户搜索关键词后,滑动页面大概率表示已经开始在挑选商品,这时候可以大胆地猜测用户行为,认为搜索与排序的重要级下降了,搜索结果垂直内容筛选的重要级上升了,便可以只保留下重要的操作。

二是可以让内容区域高度增加,隐藏顶部两个栏目区域可以大致增加一个商品位的提前露出,增大了商品触达用户的可能性。这不就是 UI 设计为商业目标赋能的一个案例吗?

△ 隐藏导航栏,增加了屏幕利用率

巧妙转移

基于导航栏层级始终高于页面内容的特性,随着用户划出第一屏,许多 APP 做了重要内容或重要控件转移到导航栏的设计。

豆瓣在影评讨论区,用户上滑页面时,会将当前影片的信息转移到导航栏。其实这种转移很常见,许多内容社区 APP 都有这样的交互设计,比如浏览的公众号文章,再回到顶部试试。方便用户时刻知道自己当前所浏览的内容是关于哪一个主题的。这一类转移是单纯站在用户体验角度的考量。

△ 豆瓣在屏幕滚动后转移影片信息到导航栏

但如果你仔细观察,有一类转移却是综合了用户体验与产品目标的共同抉择。如果你再稍微了解一点该产品背后的故事,甚至可以让你洞悉到,为了巩固产品的调性和目标,PM 和 UI 们在页面设计时做了多少细枝末节的引导。

知乎在用户浏览当前问题时向上滑动页面,也会像豆瓣一样,将当前问题标题转移到导航栏上,但与此同时会将「写回答」的操作也转移到导航栏。标题转移是出于用户体验,和大多数内容社区的做法大同小异;而「写回答」的按钮转移,正符合知乎想要打造一个内容交流社区的产品调性,他们希望刺激用户进行问答互动,多输出 UGC 内容,希望用「写回答」的按钮转移进一步激发用户创作内容的可能性。

△ 知乎转移「写回答」让用户更方便地进行问答互动

京东在店铺首页上滑页面时,会将「关注」按钮转移到导航栏,方便用户在浏览的过程中可以随时收藏店铺,增加了用户对品牌店铺的关注度和复购的可能性。京东靠自营模式发家,近几年来开始慢慢重视 B2C 市场,在这个小小的关注按钮上,是不是可以算略显端倪呢?虽然我不能非常肯定,可能提高用户收藏操作只是为了辅助京东更好地进行营销权重划分,不过「关注」按钮的转移,确实能为 B2C 业务的渗透提供一份助力。

△ 京东转移「关注」让用户更方便地收藏店铺

所以我这里说到的「转移」的目的,其实和 Giles Colborne 在书中讲到的并不十分一致,Giles Colborne 是希望设计师将当前页面低频、冗杂的操作转移到另一个页面中去,而我提到的「转移」反而是产品越注重什么功能,越可以利用导航栏层级的先天优势来实现转移。

总结

合理删除、分层组织、适时隐藏和巧妙转移已经是我做设计和分析界面常用的一个手法,它并不一定是万能的,但是它多多少少可以辅助我们做出更合理的设计。

这篇文章想要告诉大家的是,在平台规范里的导航栏是死板又相对静态的,但在四个策略的辅助下,结合用户的操作手势,也可以将它变得十分灵活,帮助页面实现更好的用户体验。不要被规范限制的太死,转换设计师的角色变成用户,你可以研究出更多好玩的操作。随便打开一个应用,去研究研究,你可能会乐在其中的。

文章来源:优设    作者:UCD耍家

疫情专用素材包!Iconfinder 推出新冠病毒防疫免费图标素材包

雪涛

知名的免费图标网站 Iconfinder 要和大家一起对抗新冠病毒,和图标设计师联手推出一系列「防疫免费图标集」(Coronavirus awareness icons),超过 200 个与公共卫生、病毒传播相关图标,这些图案包括常见的 PNG 和 SVG 格式,可以将它们加入标志、海报、传单或类似的内容使用。

如果你想要制作广告牌,提醒在这个区域要洗手或戴口罩,这里有免费图标可让信息更容易被阅读。

依照 Iconfinder 网站说明,这些图标可用于洗手说明、卫生建议或是其他预防病毒传染散播的提醒信息,所有图标采用 Creative Commons BY-SA 3.0 授权释出,使用时需要标示出处,并以相同方式分享。

Coronavirus awareness icons

网站链接:https://www.iconfinder.com/p/coronavirus-awareness-icons

值得一试的三个理由:

  • Iconfinder 和设计师合作推出「防疫免费图标集」下载;
  • 提供超过 200 个公共卫生、病毒传播相关图案;
  • 可使用于标志、海报、传单或类似的内容。

前往 Iconfider 的「Coronavirus awareness icons」网站,就能看到这套专为对抗新冠病毒提供的免费图标集,点选 Download all icons 下载打包好的完整图标。

在网站中展示一些收录在这套图标集的防疫相关图案,每套图案都有不同风格,例如以单纯线条为主的设计,或是采用平面化设计的彩色图标,可以依照自己的需求选择。当然你也可以按下右上角的按钮前往 Iconfinder 找到这套图标的完整版本。

下载后就能取得完整的图标集,依照不同名称分类,有些是 SVG 格式,有些则包括 SVG 和不同大小的 PNG 文件,其中有个 iconfider_freebies.zip 在解压缩后还能取得一些和防疫相关的图标。

值得一试的三个理由:

  • Iconfinder 和设计师合作推出「防疫免费图标集」下载;
  • 提供超过 200 个公共卫生、病毒传播相关图案;

  • 可使用于标志、海报、传单或类似的内容。

文章来源:优设    作者:Pseric

日历

链接

个人资料

蓝蓝 http://www.lanlanwork.com

存档