首页

后台返回json数据给前台和前台解析json数据(总结)

seo达人

后台返回json数据给前台和前台解析json数据(总结)

一般来说web开发中,前台采用json数据提交给后台,后台处理数据以后返回json数据给前台,前台解析json,显示数据。

总而言之,前后台直接交换的数据格式最常用的非json数据无疑了。

这里就总结一些json数据的前后台处理方式。



1.JSON数据

JSON(JavaScript Object Notation, JS 对象简谱)



是一种轻量级的数据交换格式,比xml更轻巧(由于 JSON 所使用的字符要比 XML 少得多,可以大大得节约传输数据所占用的带宽)。



json是javascript原生格式,就是说在javascript中处理json数据,需要引用其他API或工具包。



简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。



只需要记住!

Json是一种文本字符串!被存储在responseText属性中,而读取json数据可以使用javascript的eval函数来解析json。



2.json规则:

在 JS 语言中,一切都是对象,对象是一个无序的 “键/值” 对集合。

因此,任何支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。但是对象和数组是比较特殊且常用的两种类型:

对象表示为键值对.

数据由逗号分隔.

花括号{}保存对象.

方括号[]保存数组.



键/值对组合中的键名写在前面并用双引号 “” 包裹,使用冒号 : 分隔,然后紧接着值:



{"firstName": "Json"}

1

这很容易理解,等价于这条 JavaScript 语句:



{firstName : "Json"}

1

对象在 JS 中是使用花括号包裹 {} 起来的内容,数据结构为 {key1:value1, key2:value2, …} 的键值对结构。



在面向对象的语言中,key 为对象的属性,value 为对应的值。



键名可以使用整数和字符串来表示,值的类型可以是任意类型。



数组在 JS 中是方括号 [] 包裹起来的内容,数据结构为 [“java”, “javascript”, “vb”, …] 的索引结构。



在 JS 中,数组是一种比较特殊的数据类型,它也可以像对象那样使用键值对,但还是索引使用得多。同样,键名可以使用整数和字符串来表示,值的类型可以是任意类型。



3.JSON 与 JS 对象的关系:

很多人搞不清楚 JSON 和 Js 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:

JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。

如:



var obj = {a: 'Hello', b: 'World'};    //这是一个对象,注意键名也是可以使用引号包裹的

var json = '{"a": "Hello", "b": "World"}';  //这是一个 JSON 字符串,本质是一个字符串

1

2

4.后台返回json数据

一般来说,使用JsonObject来将Java类型数据转换成Json类型,首先要下载该库相关的jar包,下载地址如下:



json-jar包下载



JsonObject的使用:

后台controller部分代码:



JSONObject object = new JSONObject();  //创建Json对象

object.put("username", "张三");         //设置Json对象的属性

object.put("password", "123456");

System.out.println(object.toString());  //调用toString方法将json对象转换成json字符串



//把json数据返回给浏览器:

PrintWriter out = cu.getWriterOut(response);

out.print(object.toString());

//或者

response.getWriter().write(jsonObject.toString());



1

2

3

4

5

6

7

8

9

10

11

5.在JavaScript代码中接收Json数据:

假设result为浏览器得到的json数据,可以使用以下js代码可以将json对象转换为字符串。



比如:



通过$.get从后台获取了一段json串{“id”:“1”,“name”:“ww”},然后要拿到这里面的id和name值:



注意!注意!注意!

如果你直接这么写!



$.get(url,

     function(data) {

       alert("ID:" + data.id + "\nName:" + data.name);

     });

1

2

3

4

直接这样写的话,界面会alert提示undefined,因为没能正确解析返回的字符串。



图示:





解决方案:



1、 需要用eval()函数



将返回的串转化成可用的strig串,eval(data),但是因为原串里面是以{}开始和结束的,会被认为是可执行方法,因此需要加上()包围起来,最终形成:



var jsonobj= eval('(' + data + ')');  // 把JSON字符串解析为javascript对象

1

然后再



alert("ID:" + jsonobj.id + "\nName:" + jsonobj.name);

1

各种正常的按key取值,就能正常显示了。



2、获取的时候就直接表示返回的是json格式,用.getJSON代替 .getJSON代替.getJSON代替.get,其他代码不变,也能正常获取。



也可以直接获取json对象的属性,如下:console.log(result.username);



前端js代码:



$.ajax({

url: url,

type: "POST",

data: parameters,

dataType:"json",

async: false,

success: function(result){

var newData = JSON.stringify(result);    //将json对象转换为字符串

newData = eval("("+newData+")");   /解析json



var annualDays = newData.annualDays;

var entryDate = newData.entryDate;



$("input[name='extendDataFormInfo.value(fd_shengyu_nianjia)']").val(annualDays);

$("input[name='extendDataFormInfo.value(fd_ruzhi_date)']").val(entryDate);



}});



1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

ps: 注意注释中的代码,如果少了这一句,那么直接alert(result);得到的结果会是







所以在这里stringfy()的作用是用于从一个对象解析出字符串

加上了var newData = JSON.stringify(result);这句,然后你再alert(newData);

得到的就会是你想要的结果,如下:





另外:

如果返回的json数据格式不是很规范的解决办法:



判断后台返回的数据格式是否字符串,是则转,不是则不转?



  var $obj = (typeof data.content == 'string') ? JSON.parse(data.content):data.content

1

总结:



前台发送请求,并且设置数据为json格式‘

    $.ajax({

    url:"selectByid.",

    datatype:'json',

    data:{id:id}, // 发送数据 

1

2

3

4

数据回调函数

success:function(data){

alert(data);

var json = eval("("+data+")");//将json类型字符串转换为json对象

alert("hjf"+json.name);

1

2

3

4

给对应的input赋值:

$("#id").val(json.id),

$("#name").val(json.name),

$("#age").val(json.age);

1

2

3

后台代码:返回json数据

response.getWriter().print(str);    //将数据返回前台ajax

1

6.前端ajax接不到json解决?

在前台:



async:false,                //加上这个属性就好了

1

7.返回的json字符串中有转义符解决?

比如:



"result":"{\"id\":\"60\",\"qid\":\"1\",\"bazi\":\"baiz\",\"shenxiao\":\"\",\"xingzuo\":\"\",\"wuge\":\"\",\"jianyi\":\"\",}"

1

这样我们我们使用JSON.parse(result) ,直接转化为json的话是会报错的。



解决方法:

我们先把转义符用正则表达式去掉,



   var string = result.replace("/\","");

   var getDataArray = JSON.parse(string)

1

2

这样就OK了,不过要注意有时候也是需要指定返回数据类型的

dataType:“json”



8.使用其他的json依赖包方式:

引入阿里巴巴的json依赖包:



    <dependency>

     <groupId>com.alibaba</groupId>

     <artifactId>fastjson</artifactId>

     <version>1.2.9</version>

    </dependency>

1

2

3

4

5

模拟后台:



    String params="{\"channelCode\":\"bbb\",\"accountNo\":\"121300000932\",\"message\":\"字符信息解密成功\",\"status\":\"1\"}";

    JSONObject pa=JSONObject.parseObject(params);

    System.out.println(pa.getString("message"));

1

2

3

结果:





或者:

引入net.sf.json-lib依赖包:



    <dependency>

      <groupId>net.sf.json-lib</groupId>

      <artifactId>json-lib</artifactId>

      <version>2.4</version>  

      <classifier>jdk15</classifier>

    </dependency>

1

2

3

4

5

6

后台:



String params="{\"channelCode\":\"ccy\",\"accountNo\":\"121300000932\",\"message\":\"字符信息解密成功\",\"status\":\"1\"}";

JSONObject pa=JSONObject.fromObject(params);

String accountNo=pa.getString("accountNo");

System.out.println(accountNo);

1

2

3

4

结果:





9.后台对象转换json数据返回给前台

List集合转换成json代码:



List list = new ArrayList();

list.add( "first" );

list.add( "second" );

JSONArray jsonArray2 = JSONArray.fromObject( list );

1

2

3

4

Map集合转换成json代码:



  Map map = new HashMap();

map.put("name", "json");

map.put("bool", Boolean.TRUE);

map.put("int", new Integer(1));

map.put("arr", new String[] { "a", "b" });

map.put("func", "function(i){ return this.arr[i]; }");

JSONObject json = JSONObject.fromObject(map);

1

2

3

4

5

6

7

或者在项目中加入引入JSON-lib包,JSON-lib包同时依赖于以下的JAR包:

下载地址。



  1.commons-lang.jar

  2.commons-beanutils.jar

  3.commons-collections.jar

  4.commons-logging.jar 

  5.ezmorph.jar

  6.json-lib-2.2.2-jdk15.jar

1

2

3

4

5

6

用法同上



JSONObject jsonObject = JSONObject.fromObject(message);

getResponse().getWriter().write(jsonObject.toString());

1

2

当把数据转为json后,用如上的方法发送到客户端。前端就可以取得json数据了。(可以参考最下面的实例)



10.后台返回数据给前台,json中文乱码解决方法

在实际运用场景中,当前台发起请求后,我们需要从后台返回数据给前台,这时,如果返回的数据中包含中文,则经常会出现在后台查询出来都是好好,但是传输回去就莫名的乱码了,而且即使在 web.xml 中进行编码过滤了,但还是乱码。



解决办法:

只需要在 spring-mvc.xml 配置文件中配置一次就好,省去了我们重复写的麻烦,配置内容如下:



<!--自定义消息转换器的编码,解决后台传输json回前台时,中文乱码问题-->

    <mvc:annotation-driven >

        <mvc:message-converters register-defaults="true">

            <bean class="org.springframework.http.converter.StringHttpMessageConverter" >

                <property name = "supportedMediaTypes">

                    <list>

                        <value>application/json;charset=utf-8</value>

                        <value>text/html;charset=utf-8</value>

                        <!-- application 可以在任意 form 表单里面 enctype 属性默认找到 -->

                        <value>application/x-www-form-urlencoded</value>

                    </list>

                </property>

            </bean>

            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" ></bean>

        </mvc:message-converters>

    </mvc:annotation-driven>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

加上这段配置,保存重新运行,再次访问,会发现,原先的中文乱码都已经正常显示了。



方法二:在后台的方法映射添加:



@RequestMapping(value="/getphone",produces = “text/plain;charset=utf-8”)



11.Spring MVC返回json数据的方式

  1. 采用@ResponseBody注解

    @ResponseBody 注解的作用是:



    将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据,需要注意的呢,在使用此注解之后不会再走试图处理器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。



    使用举例:





    使用@ResponseBody 注解返回响应体 直接将返回值序列化json

    优点:不需要自己再处理



    再举例:



    RequestMapping("/login")

    @ResponseBody

    public User login(User user){

    return user;

    }

    1

    2

    3

    4

    5

    使用@ResponseBody 注解返回响应体 直接将返回值序列化json。



    User字段:userName pwd,那么在前台接收到的数据为:’{“userName”:“xxx”,“pwd”:“xxx”}’,效果等同于如下代码:



    @RequestMapping("/login")

    public void login(User user, HttpServletResponse response){

    response.getWriter.write(JSONObject.fromObject(user).toString());

    }



    1

    2

    3

    4

    5

    需要在springmvc的配置文件xml中添加:



    <mvc:annotation-driven/>  

    1
  2. 采用工具类,进行json格式转换带回

    JSON-lib包是一个beans,collections,maps,java arrays 和XML和JSON互相转换的包。在本例中,我们将使用JSONObject类创建JSONObject对象,然后我们打印这些对象的值。为了使用JSONObject对象,我们要引入"net.sf.json"包。为了给对象添加元素,我们要使用put()方法。



    要使程序可以运行必须引入JSON-lib包,JSON-lib包同时依赖于以下的JAR包:



    commons-lang.jar

    commons-beanutils.jar

    commons-collections.jar

    commons-logging.jar 

    ezmorph.jar

    json-lib-2.2.2-jdk15.jar

    1

    2

    3

    4

    5

    6

    效果:



    工具类:

    ResponseUtil.java



    package com.zout.utils;

    import java.io.PrintWriter;

    import javax.servlet.http.HttpServletResponse;

    import net.sf.json.JSONArray;

    import net.sf.json.JSONObject;



    /*

     
    @class_name:ResponseUtil  

     @param: EasyUi-响应工具类

     
    @return: 返回字符串格式数据、result是JSONObject对象(json对象)

     @author:Zoutao

     
    @createtime:2018年3月8日

     /

    public class ResponseUtil {

    public static void write(HttpServletResponse response, Object result)

    throws Exception {

    response.setContentType("text/html;charset=utf-8");

    response.addHeader("Access-Control-Allow-Origin", "
    ");

    PrintWriter out = response.getWriter();

    out.println(result.toString());

    System.out.println("带回的json字符串为:"+result.toString()+"类型为:"+result.getClass().getName());

    out.flush();

    out.close();

    }



    public static void main(String[] args) throws Exception {

    /在web运用控制层中调用如下:/

    JSONObject result = new JSONObject(); //创建json对象

    JSONArray jsonArray = JSONArray.fromObject("name:zhangsan"); //字符串转为json数组

    result.put("rows", jsonArray);  //放入json数组中,并起个名字

    HttpServletResponse response = null; //jsp的response对象

    ResponseUtil.write(response, result); //result写入response带回前台,jsp按名字拿取。

    }

    }



    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    后台具体调用:



    JSONObject result = new JSONObject();

    if (resultTotal > 0) { //处理结果

    System.out.println("操作成功。");

    result.put("success",true)

    result.put("message","操作成功"); //消息语句

    } else {

    System.out.println("操作失败。");

    result.put("success", false);

    result.put("message","操作失败");

    }

    ResponseUtil.write(response,result); //带回字符串+状态码

    return null;

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    图:





    后台已经通过工具类封装为json字符串了,使用response带回需要的数据,使用result带回状态字符串或状态码。



    前台:

    这是当成返回一个json字符串,然后直接采取字符串截取的方式,取出消息语句message等消息。





    这是另外一种写法:就是解析传回来的json字符串我js的对象,然后按照key/value的取值。



      function (data) {

              var data=eval("("+data+")");  //解析json

             //alert(data.message)

                $.messager.show({

                  title:'消息',

                  msg:data.message,  //按key取值

                  timeout:1000,

                  showType:'slide',

                  height:120,

                 width:200

         });

     });

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    推荐这种方式。

    效果图:





    以上都是后台返回json数据给前台和前台解析json数据的一些总结,还有json数据的封装,工具类的使用等等,东西有点复杂有点多,挑选自己需要的地方即可。

    另外的一些常用的web开发json:



    Json–Java数据类型对照表(映射)表


javascript基础———原型、原型对象和原型链

seo达人

原型:函数中的属性prototype,她的名字就叫原型。可以通过也只能通过prototype添加可继承的属性和方法

原型对象:函数中prototype中的proto 和对象中的proto

先记住原型(prototype)和原型对象(proto)

下面用代码解释原型、原型对象、 原型链

<!DOCTYPE html>

<html>

   <head>

    <meta charset="utf-8">

    <title>对象</title>

   </head>

   <body>

    <script type="text/javascript">

       //创建一个对象和一个函数

       var obj = {}

       console.log(obj.proto)//obj有原型对象

       function objFun (){}

       console.log(objFun.prototype) //objFun 原型

       console.log(objFun.prototype.proto) //原型中有原型对象

       console.log('*华丽的分割线***')

       // 以objFun为构造函数 (为了把构造函数和普通函数做区分,通常把构造函数名首字母大写)

       // 添加属性和方法

       objFun.prototype.name='saozhu'

       objFun.prototype.say = function(){

        console.log(this.name+'-骚猪')

       }

       // 创建实例对象1

       var obj1=new objFun()

       console.log(obj1)//打印对象 空对象

       console.log(obj1.name) //骚猪 证明obj1继承了objFun函数的属性

       console.log('*华丽的分割线***')

       // 此时此刻 可以理解原型链了: 

       console.log(obj1.proto=== objFun.prototype)

       //true 

       // 原型链是有实例对象的proto(原型对象)指向构造函数函数的原型(prototype)

       console.log(objFun.prototype.proto==window.Object.prototype)

       // true

       // 然后构造函数的原型的原型对象(prototype.proto)指向window.Object.protype(对象的原型)

       console.log(window.Object.prototype.proto===null)

       // 这样的指向关系形成的链式关系就是原型链

       //链式查询,查询对象中的属性和方法,会根据这样的原型链查找,直到找到响应的属性和方法.找到window.Object.prototype.proto还没有值,就返回undeifne

       

    </script>

   </body>

</html>


产品思维·用户体验中的五个层次(下)

分享达人

昨天我们讲了用户体验分为五个层次,从内而外分别是:

①战略存在层 > ②能力圈范围层 > ③资源结构层 > ④角色框架层 > ⑤感知层


以下案例来自于 梁宁老师的《产品思维30讲》

苦思冥想,还是只有梁宁老师这个案例最为合适;


说到“搜索”,你会想到哪些呢


如果我没猜错,你想到的第一个词是:“百度”

研发行业的话,可能我们用的浏览器应该是:“google”居多

但你是否用过古老的“yahoo”呢?



今天,我们就来说说搜索业三大巨头的战争,

他们之间的战争,有助于我们去理解用户体验的五个层次


首先


Google与百度


说到百度与谷歌的竞争前,梁宁老师说了下雅虎:


我们做设计的最知道,色彩是非常重要的元素,如果以科技为关键词,

我们想到的第一个词,一定是蓝色,蓝色一来不会太刺眼,

又相对普遍,所以不会出现审美疲劳,

而yahoo用的是什么为主色呢,是一个我们最不会用的颜色——紫色

 


那么,假如有个用户指着那个“紫色”的“音噗忒(input)”说:“不好用”,

他指的是什么呢?


1.是感知层,不喜欢蓝色?

2.按钮的形状太突兀?尺寸太大?位置不合适?

3.还是说是框架层,内容的排列方式没有令他满意呢?


说点令人兴奋的,我们在百度搜索“大乐透”,

度娘显示的结果第一条,就是本期开奖的结果,

然后是百度百科对“大乐透”这个词条的解释,

其次的就是关于大乐透的各类新闻和各种“行业大师”对下期开奖结果的分析;


百度的框架的意义就是,能一步走完,绝对不让用户走一步半,

为什么百度能给出这么符合用户的搜索结果呢?


虽然这个结果离不开的肯定得是百度的爬虫技术是数以毫秒为单位的,

但百度爬虫技术肯Google当然还是没法比的,

最重要的什么呢,是百度不单只是去爬数据,而且他还建立数据,


当整个互联网的数据都不多的时候,

百度做了一件Google没有做的事,

就是我们刚才说到的“建立数据”

百度做了两个平台:1.百度贴吧     2.百度知道


展示下各自的装备


一个在升级技术去爬,一个在建立数据

你觉得,谁会赢到最后呢,


你说,Google为什么不跟着做呢,

Google 的性格是绝对不会的,用梁宁老师的话来说:

“以Google的清高和耿直,不会做这样的事,甚至当用户有需求时,Google还会为百度导流量,给对手送弹药”


但至此,搜索业都还是处于资源层的比拼

这一仗,百度带着它的百度贴吧和百度知道,拿到了胜利!


但三十年河东,三十年河西

百度在移动场景下输给微信,也是因为微信以百度战胜Google同样的方式,以公众号的形式建设资源;



Yahoo与Google


2004年,一批华尔街精英做了搜索引擎的比评,评测结果呢,Yahoo优于Google,Yahoo胜利,

但奇怪的是评测完之后,大家打开了Google工作,


为什么会出现这个情况呢,


他们的评测方式非常的简单,对,就是简单,


第一步:选几个关键词

第二步:在各个搜索引擎中搜索

第三步:将结果打印

第四步:比对结果,认为哪个好,就投一枚硬币


最后雅虎获得的硬币最多

简单吧,你闲的蛋疼也可以去试试,


那为什么雅虎会胜出呢,因为雅虎用的后台搜索引擎也是Google的,

雅虎只是对热门的关键词做了人工优化,

所以结果不是跟Google一样,就是比Google好,

。。扯吧,但就是这样。


那为什么这批精英日常还是会用Google呢,

竟然是因为框架层,因为Yahoo的设计比较喜欢高大尚,所以界面相对宽松,易看,

但缺点就是一屏只能显示一两条,



而谷歌的搜索结果一屏展示好几十条,

所以对于搜索引擎这个东西来说,

我们更在乎内容,

而形式恐怕稍微次要,


在感知层差别不大的情况下,Yahoo竟然在框架层就输了一局,恐怕很难想到吧



设计师,要有产品思维!

但在互联网设计的今天,可能这五个层级有了一些整合,

但是,在用户抱怨体验不好时,你能分辨,会去分辨用户是说哪个层级吗?

还是说你会跟用户讲道理,说服他们呢?


销售天然的本领就是说服,掌握各种说服的技巧:

摆事实,讲道理,打比方,举例子,要同情,装可怜,将心比心,软磨硬泡;

如果是现实中,或许你能说服用户,


但作为一个互联网产品,别说说服,你连站在旁边说句话的资格都没有,

何况,比起用自己的道理说服用户,我们更应该做的,不应该是挖掘用户真正的需求吗?


从今天起,

不再做销售:按我的来

而要做产品:顺你的意


用户没有我们这么专业,他的表达方式就是:情绪;

如果我们不能接受这个表达方式,就不可能挖掘到用户的真正需求,


总结一下:

  1. 接受用户的表达方式,通过五个层面,挖掘到用户真正的需求;

  2. 销售是按我的来,而产品是顺你的意

取消与关闭:请在设计上区分差异

分享达人

3个方法,区分取消与关闭,避免丢失用户正在操作的内容。

概要:区分这两种操作,可以很大程度上能避免丢失用户已操作的内容。在关闭视图之前保存用户的更改,使用文本标签而不是“X”图标,并在破坏性操作之前提供确认对话框。



一、让人迷惑的“X”图标


很久以前,“X”这个符号是用在地图上,标记“宝藏的藏身地”。但在今天的数字化界面中,“X”符号不再用来标记位置,而是被用来取消进程,或者关闭某个临时页面/弹框。但是如何确定“X”代表的是“取消” or “关闭”?有的时候可以确定,有时却模糊不清难以界定。

  

其实,主要的问题在于“X”图标缺少了文本标签。当同一个图标在不同的界面,却代表不同的含义,该图标的可用性就会受到影响,因为用户判断不了到底是什么含义。



二、为什么要区分“取消”与“关闭”


当用户单击/点击“X”按钮来关闭模态弹框或视图时,系统会完全取消该过程并清空之前所有操作,这让人沮丧,甚至抓狂。因为用户通常认为“X”图标表示取消或者关闭,所以区分这两种可能性对于交互的成功至关重要。


在某些情况下,区分取消 or 关闭并不重要。当一个弹窗占据你的大部分屏幕时,点击“X”按钮(尽可能快地),既可以关闭该模态,也可以取消它可能触发的任何进程。


但是,如果页面中包含正在运行的计时器,正在播放的音频,正在选择多个选项标签,或其他类型未保存的内容,那就很有必要说明“X”图标所代表的意义。因为用户可能打算让计时器或音频继续运行,或者希望立刻应用这些选好的选项标签,或保存正在进行的工作,同时希望关闭该视图继续其他操作。

 

例如:丝芙兰在结账过程中,使用模态窗口来展示用户可以添加到购物车的免费商品。在以下示例中,单击“ ADD(添加)”按钮选择商品后, 该按钮直接被变成了“ Remove(移除)”,看起来似乎商品已经被添加到购物车中了。但是,实际上当用户单击右上角的“X”图标后,该商品并不在购物车中。他需要再重复这个步骤,最后点击“Done(完成)”按钮,商品才会被加入购物车。

Sephora:单击右上角的"X"会取消选择这些试用商品整个过程。用户必须先单击“ADD”,再单击“Done”才能将商品添加到购物车。



三、如何避免丢失用户正在操作的内容


要避免丢失用户正在操作的内容,首先需要确定用户的意图 - 取消 or 关闭 - 并提供明确的选项。有以下几种方法:


  · 主动要求用户确认他们的意图

  · 使用明确的文本标签而不是模糊图标

  · 显示两个不同的按钮:“X”图标表示关闭视图(可以自动保存页面内容/操作),而“取消”则代表放弃该过程


1、要求确认


如果用户在已经执行操作的模态弹框或页面视图中,点击“X”图标,UI则可以在关闭视图之前,直接询问用户是否应用该操作,来确认其意图。此解决方案非常适合会破坏用户工作的破坏性取消操作例如,过滤器视图可能会被意外关闭,并且关闭会导致用户丢失其选定的选项。


这个问题在移动端界面上很常见,因为过滤器视图占用了很大的屏幕空间,这使用户很难或不能判断是否已经应用了那些选择。为了防止这种潜在的错误,在关闭过滤器视图之前,跟用户确认是否要应用这些选择并关闭视图,抑或是清除这些选择。例如:下图中,当用户选择后,点击“X”图标时,Lowes 会出现如下确认弹框。

左 :点击"X"图标或返回箭头,所有的选项都会被取消,并将用户带回上一个页面。右:点击“X”后,出现一个确认对话框,确认用户是应用还是取消筛选,然后再返回结果列表页。

 

同样,当用户关闭正在进行的课程时,语言学习应用- Duolingo 会显示一个确认对话框-课程进行中不能中途离开,除非确认“退出”。至少,该APP向用户传达了这一限制,同时他们也可以选择“取消”来继续课程。点击“X”按钮将结束当前课程。为了防止出错,结束前会出现一个确认对话框。

 

缺点:

a. 虽然确认对话框在避免“X”图标有歧义方面很有效,但它却添加了额外的步骤;

b 用户在按下“X”图标之前还是不知道它到底做了什么,代表什么意思,因此他们可能会对这个操作感到疑惑。



2、使用文本标签


不要完全依赖对话框来让用户确认模糊的“X”图标,而是使用明确的文本标签。文本可以消除歧义,并清楚地传达将发生的操作:取消与关闭。

 

Yelp的筛选页面在屏幕顶部提供了标有”Cancel(取消)“和”Reset(重制)“的按钮,在底部提供了一个大大的”Apply(应用)“按钮。类似地,Etsy中的 Filters视图提供了“Clear(清除)”和“Done(完成)”两个按钮。


注意:Etsy使用“Done”而不是“Apply”,因为过滤器一经选择就可以被应用,而这里是关于开关切换与否的建议。

(左)Yelp:Cancel、Reset 和 Apply 这三个文本标签既直接又清晰,这样用户就不太可能不小心关闭视图而丢失他们过滤器中的选择。(右)Etsy:Clear 为用户取消提供了一种清晰的方式。而点击 Done 则返回到“产品列表”页,其中的选择已经应用。




3、关闭并保存


果必须使用“X”图标而不是文本标签(比如为了以节省空间,或者因为正在遵循团队的设计语言),请谨慎使用,并在用户完成前保存操作/内容。另外,可以提供一个单独的“取消”按钮,让用户在进程之外有一个紧急出口,并消除“X”(关闭 or 取消)在两种含义之间的歧义。

 

例如: Gmail会自动保存在非模态窗口中填写的邮件信息到草稿(Drafts)。这样的好处是,用户在需要折叠或关闭该窗口时,仍然保存原来的内容以便于下次继续编辑。将鼠标悬停在消息窗口右上角的“X”图标上时,会显示一段提示:Save & Close(保存到草稿并关闭)。此外,点击窗口右下角的“垃圾桶”图标可以删除该邮件 - 这个图标离顶部的“保存和关闭”选项很远,可以防止用户误点。

Gmail:Hover 透露, “X”图标是用于关闭窗口而不是删除草稿,它允许用户保存并关闭消息窗口而不会丢失刚刚正在编辑的邮件。

 

对于长进程或倾向于在后台运行的进程(如计时器),默认自动保存也是一种很好的解决方案。

 

例如,Glow Baby中,后台运行喂食或睡眠计时器时,用户还可以浏览APP的其他区域。因为这些计时器一般会运行很长一段时间。此功能还能让用户在APP中做其他的任务操作,例如记录之前换尿布的时间、浏览文章、逛论坛等。点击计时器视图中的“X”图标也只是关闭窗口并不会取消正在运行的计时器。

Glow Baby:(左)点击运行计时器视图中的“X”图标,在不停止计时器的情况下取消视图,从而允许用户继续使用APP记录其他类型的事件、参与社区讨论、阅读文章等。(中)运行计时器的状态显示在屏幕顶部的状态栏中。(右)在计时器暂停时点击“X”图标,弹出“放弃”或“取消”按钮以确认用户的真正意图。


 请注意:在关闭前保存中间工作或维护正在进行的过程是主动的,但有时可能会与用户的意图相反:如果用户打算通过单击“X”按钮取消其选择,那自动应用这些选择可能会令人困惑和沮丧。


这就是为什么还必须有一个单独的“取消”按钮,给用户一个出口,而不是强迫他们必须关闭时自动保存。



四、结论


虽然“X”图标会造成模棱两可,而且经常导致可用性问题,但它不太可能马上从所有接口中消失。设计人员应该注意“X”图标的多重含义,消除“关闭”和“取消”之间的歧义,并提供确认对话框或自动保存等保护性措施,避免丢失任何用户正在操作的内容。


若存在疑问,请记住:先保存,再退出。



原文作者 | Aurora Harley

编辑作者 | WanSU

原文地址 | https://www.nngroup.com/articles/cancel-vs-close/

本文版权归原作者所有;仅供学习使用,转载请注明出处。



五、小思考


读上面这篇文章的一个小启发:


为什么手机验证码登录微信/淘宝时,验证码输入错误,二者都是用的模态对话框提示用户,而不是用Toast呢?

a. 微信和淘宝的用户群体都很庞大,几乎横跨所有年龄层。Toast出现又自动消失的交互体验,用户会感到不可控,尤其是对大龄、老龄的用户不够友好。

b. 也有悖于iOS人机交互指南中提到的“用户控制”这一原则,我想这也是iOS设计语言没有Toast这种控件的原因之一吧。

c. 而模态对话框虽然干扰性较强,但用户可以随时控制,在使用过程中是用户掌握主导权。


补充:Toast这一控件,原是Android系统的控件。但自Android 5.0 推出原质化设计后,Toast就被弱化,而是将 Snackbar 作为官方推荐的控件。如今在 Material Design中更是找不到 Toast的踪影。主要原因还是 Snackbar 在交互友好性方面比 Toast 要好,例如:支持手势交互、支持与CoordinatorLayout联动等。所以说 Toast都过时了呢,应该讲 Snackbar。

找到本质需求:聊聊内容分类

分享达人

资讯产品为例,一段寻找本质需求的旅程。


上篇文章,聊了信息架构。


信息架构有了,得往里面放内容。具体怎么放?特别是当内容非常海量的时候,比如资讯类、购物类产品。这个时候,就离不开内容的分类了。


我们平常看微信公众号(资讯类),会发现,公众号并没有以“科技”、“影视”等维度进行分类,但感觉还好,也没有太多不便。


这种做法,如果放到天猫(购物类)身上,会有点无法想象——硕大一个购物商城,如果不能按照商品的性质进行分类查找,逛起来必然非常不便。


由此可见,关于内容的分类,也是不能一概而论。


那么,内容分类,到底该咋分?个人觉得,笼统的讲,内容分类就是化繁为简,从而更好的满足用户需求。



本文将以综合性资讯产品(手机端、文章类)为例,探讨一下如何给海量的内容进行分类。



01 寻找本质需求


内容分类,既然是为了更好的满足用户需求,那么,我们就从需求出发,从最本质的需求出发。


所谓大道至简,本质的需求一般都不复杂。资讯产品,解决的本质需求是什么?以下是我个人用到的方法,仅供参考。


1 厘清来龙去脉,并注意前后区别


太阳底下无新事。某种程度上,资讯类和购物类产品用到的内容分类,都有借鉴历史。


前面提到,微信公众号没有科技、影视等内容频道。不过网易新闻客户端是有的,类似的内容频道有几十个。


21 世纪最初的十年,逐渐崛起的四大门户(新浪、网易、搜狐、腾讯),也存在几十个这样的内容频道,并沿用至今。


90 年代和 21 世纪初盛行的报纸,比如《参考消息》,也存在类似的内容频道(版面),通常有 10 个左右,同样也是沿用至今。



内容频道这种分类方式,看起来是一脉相承了。但其实这里面有三个很大的变化。


第一,载体由报纸变成电脑、手机(手机还很特殊、被称之为人体的器官)。


第二,报纸代表的是一个信息稀缺的时代,如今是一个信息爆炸、甚至信息泛滥的时代。


第三,报纸和四大门户,基本上都是由专业的记者、编辑来生产内容,质量有一定保障;如今是全民创作时代,各种质量都有。


那么,内容频道这种形式,如今还是最好的内容分类方式吗?


这个问题,是要存疑的。


2 为用户的考虑,尽量周全


由于文章太多,所以有必要按性质对文章进行分类,前台方便展示,后台方便管理,用户查找起来也比较方便。站在企业的角度,这样想,除了可能不够深入,其他也没啥问题。


站在用户的角度,假设有一个从来不买彩票、也没动过相关念头的用户,通常是不会去看彩票相关的内容。对用户而言,一款资讯产品,几十个频道,无数篇文章,往往充斥着大量“彩票内容”。


用户关心什么呢?个人觉得,通常而言,用户只关心“彩票内容”以外、自己兴趣以内的内容,同时还关心怎样快速看到这些内容。


至此,我们可以尝试总结出内容分类需要解决的本质需求了,那就是:兴趣和效率



3 把简单牢记在心


通过前两步,我们已经把本质需求捋出来了。这时候,保险起见,拿本质需求和本条核对一下,看看是否简单。如果本质需求有 10 来条、甚至几十条,通常就是不够简单。


为什么要强调简单,因为诚如张小龙在《微信背后的产品观》中所言,“越简单的分类越易于被接受”。




02 分析本质需求


接下来,我们先剖析一下这俩本质需求,加深一下对它们的理解。


1 本质需求之一:兴趣


相信大部分用户都有这样的感觉:感觉 A 产品的文章,比 B 产品的质量要高;同一类型的公众号,感觉 C 号比 D 号的质量高。


关于文章的质量,个人是这么理解的:

第一,主观上,千人千面,对于质量,每个人都有自己的标准;

第二,客观上,也存在一些比较权威的标准来评价质量,比如豆瓣的影评书评。


不过,常常发生的情况是,即便一部电影的豆瓣评分只有 5、6 分,还是会有很多人去电影院看。


再换一个角度来看:

如果是内容自营,比如心理学科普领域的 KnowYourself(以下简称 KY),就能持续产出较高品质的文章;

如果是平台型产品,像微信公众号,准入门槛又比较低,必然是各种质量的内容都有。


而综合性的资讯产品,普遍都是平台型。


所以,我更愿意这样来理解资讯文章的质量:有些用户是“北方人”,喜欢“面食”;有些用户是“南方人”,喜欢“米饭”。


现在回到“兴趣”这个本质需求上来。


这里的兴趣,是一个广义的概念,既包含了大的方向(比如你是喜欢股票还是彩票),也包含了口味偏好(“面食”还是“米饭”)。


2 本质需求之二:效率


借效率这个话题,简单聊一下手机的特殊性。因为,现在绝大部分用户是通过手机来看综合性资讯的。


情侣之间、夫妻之间、两代人之间,有时候会听到一个词儿,叫“玩手机”。连幼儿园的小朋友都会对自己的父母这样说:爸/妈,你又在玩手机了,到底谁是你的孩子?


不像电脑,手机的办公学习属性很弱,休闲娱乐功能又很强。所以,捧着手机,尤其是在家里,就给人留下了不干正事的刻板印象。


所以,个人猜测,大家在用手机看资讯的时候,潜意识里也会有一点休闲娱乐的感觉,即便是通过公众号在看一些干货文章。


所以实际上,大家也基本上是在用碎片化时间来看资讯:通勤路上;在单位、学校和家里放空的间隙;以及一些无聊的时刻。


在大家的观念里,手机上刷朋友圈和刷资讯一样,都不太属于干正事。


2019 年的微信公开课,张小龙分享的一个数据很有意思。


大概是说,这么多年下来,大家微信好友的数量在增加,朋友圈的内容数量也在增加,但是大家每天花在朋友圈的时间基本是固定的,就是 30 分钟左右。


这说明我们人类是有自我调节机制的。人类的这种自我调节机制,决定了大家每天只会花碎片时间的其中一部分,用来在手机上看资讯


这一特性,无疑也会对“效率”提出更高的要求



03 从本质需求出发,先谈功能特性,再谈内容分类


那就需要聚焦在兴趣和效率上。以下是经过实践检验,比较有效的几点。


1 关注机制


90 年代和 21 世纪初,如果家里订了全年的参考消息,邮递员每天都会把这份报纸投递到你家门口。


2010 年及以后,如果在微博上关注了参考消息。那么,参考消息的每条更新,都会出现在你的信息流里。



关注机制,是一种创新,也是一种“昨日重现”。


用户所关注的账号,通常都是自己感兴趣的;在一个单一维度的关注列表里浏览资讯,效率也得到了很大提升


2 品牌机制


有时候在家看电视,如果没有特别想看的节目,很多人可能就会看湖南卫视。这就是品牌的力量了。


当然,电视台的品牌不止湖南卫视一家。央视和很多地方卫视都是很不错的品牌。


报纸盛行的 90 年代和 21 世纪初,《参考消息》、《大河报》等国家和地方的报纸,都是品牌。百花齐放,百家争鸣。


四大门户盛行的时代,新浪、网易、搜狐、腾讯分别都是品牌,但同时也是一个寡头垄断的时代。


直到博客盛行,品牌的百花齐放才开始复苏,很多人记住了韩寒、徐静蕾、李银河、郑渊洁、王石、潘石屹等各界名人。


微博的问世,品牌再次开始全面开花。


现如今,把综合性品牌经营的最好的,当属微信公众号了。《人民日报》、《三联生活周刊》等老品牌纷纷扎根公众号,公众号也培育了一大批诸如 KY、乌鸦电影的新品牌。这是一个千花齐放、千家争鸣的时代。


通过品牌,用户可以省心而的看到自己感兴趣的资讯内容


3 品牌和频道合二为一


在家里,我外甥喜欢看金鹰卡通频道和卡酷少儿频道。这俩电视台,既是品牌,也代表了“少儿、卡通”这一类频道。


我对心理学比较感兴趣,所以我看 KY 这个公众号比较多。KY 既是一个品牌,也代表了心理学科普领域。


金鹰卡通频道、卡酷少儿频道、KY,他们有个共同点:既是品牌,也是频道。即所谓的品牌即频道、频道即品牌


有了品牌和频道的合二为一,我就不需要再去几十个频道里点“心理学”这个频道、然后再去找文章看。我可以直接找 KY 的文章来看,既符合我的兴趣,又很。


4 推荐机制


人是社会性动物,社交推荐,一直存在。互联网的蓬勃发展,也带来了机器推荐。


前文提到到《参考消息》,中学时代,我买的也不多,很多时候是从同学那儿看到的。


微博鼎盛的时代,大家开始学会一键转发。


如今微信流行,大家开始在微信里分享和推荐文章。


社交推荐的,有时候你未必感兴趣。这里面还有很多其他因素,不在本文论述范围,就不赘述了。


不过,大家是可以在朋友圈、看一看里挑选感兴趣的文章来看,有时候也会从好友的推荐里发现自己感兴趣的内容。


然后再看机器推荐。就在前几年,今日头条凭借比较精准且快速的算法推荐,向用户输送热点和他们感兴趣的新闻,从而在资讯产品里占据一席之地。


总结一下,整体而言,关注机制、品牌机制、品牌和频道合二为一、推荐机制,这四个功能特性,可以更好的满足“兴趣和效率”这个本质需求。



同时做到这四个方面、并且都做的不错的综合性资讯产品,可能就只有微信公众号了。实际上,这篇文章,很大程度上也是以公众号为蓝本进行分析的。


这四个是功能特性。先有功能特性,再做内容分类。


微信公众号是怎么对内容进行分类的呢?抛开推荐机制,只有一个维度,那就是订阅号消息列表。从几十个列表到只有一个列表,更简单,更。


如果跳出来看,也可以理解成有 3 个维度:订阅、朋友在看、精选。这样就把推荐机制也包含在内了。从几十个到 3 个,依然简单,依然。



结语


内容频道/版面,这一特性,被资讯产品一直保留了下来。从这一点也能看出,我们在做内容分类的时候,很多时候都会借鉴生活、借鉴历史。


这其实是非常好的习惯,因为“艺术”来自生活。生活里流传下来的事物,很多都经历了岁月的洗礼。洗礼过后,大浪淘沙始见金。


然而世事纷扰,一不小心,我们可能只是借鉴了形式,而没有借鉴到精髓。


找到那些简单的本质需求,我们就有可能在纷纷扰扰的生活中,借鉴到最精髓的部分。然后相应的设计出比较简单的功能特性和内容分类。


有了能更好满足本质需求的内容分类,这款产品的发展也会更加持久。


行文至此,又到了要说再见的时候。就让我们用下面这句话来结束本文。


太阳底下无新事,惟有经典永流传。

别让我思考

分享达人

《点石成金:访客至上的网页设计秘笈》在用户体验领域,可以说是一部很经典的书籍,该书于2000年出版第一版,现在已经更新到第三版,自从问世以来可以说已经将近20年了,但一直是备受推崇。这本书主要为我们介绍了产品可用性原则,并用大量的案例来阐述及运用。几年前我读过一次,最近再次重温,准备做一个整理,当做自己的学习记录。


作者史蒂夫·克鲁克(简称Krug先生)是一名备受尊敬的可用性咨询师,他把多年的从业经验,以通俗易懂的方式凝结成此书,并且篇幅简短,虽然作者说两个小时就可以读完,但如果边读边思考的话,两个小时还是不够的,毕竟这是一本工具类书籍,不是小说。本篇文章只是我的一个学习记录,还是非常希望大家能够读一读原著的。



别让我思考,作为Krug可用性第一定律,意味着,设计者应该尽量做到,当看到一个页面时,应该是不言而喻,一目了然。我能明白它是什么,怎样使用它,而不需要花费很多精力进行思考。


举个例子,假如一个你不认识的人,就比如是你隔壁的邻居,对你的网站毫无兴趣,也几乎不知道如何使用,但是他仍然看一眼你的主页,就知道这是干什么的,该怎么用。


比如以下这个网站,这是我从网上随便找的一个网站,之前从来没有听说过,点击链接进入后的第一眼,就是很多关于车的元素,猜测一定是关于车的网站;右下角两个大大的按钮“找新车”“品牌找车”,那这个应该是卖车网站,八九不离十了。先不说下面是多么杂乱不堪,起码第一眼我就可以看出,这个网站是干什么的,该怎么用,这是最基本的。



有可能我们之前访问过一些网站,打开后茫然不知所措,几乎把首页的每个地方都浏览过了,才知道是该怎么操作,或者某些元素看起来像按钮,但是却不能点击,也没有点击失败的提示...总之体验很差。所以当我们创建网站时,就需要去掉这些问号。作为一个用户,永远不能让我花几秒思考,能不能点击的问题。


当我们访问WEB的时候,每个问号都会加重我们的认知负担,把我们的注意力从要完成的任务上拉开。这种干扰也许很轻微,但他们会累积起来,有时候这样的干扰不用太多,就足以让我们抓狂。这样会让我们对网站失去信心。


那么哪些事情是访问者在访问网站时不应该花时间思考的事呢?


例如:

1、我在什么位置?

2、我该从哪里开始?

3、他们把某某放在什么地方了?

4、这个页面上最重要的是什么?

5、为什么他们给他取这个名字?

...

我们在设计网站的前和后,可以把这些作为走查对象审视一下,慢慢的这些习惯就会变成你的潜意识,再次设计网站的时候就会自然而然的把这些因素考虑在内。


不过,有时候,特别是在进行一项崭新的,开拓性的或者非常复杂的页面设计时,也许只能做到自我解释。在一个自我解释的页面中,用户只需要花一点点时间去理解页面的外观,精心选择的名称,页面布局以及少量仔细斟酌过的文字。所以,如果不能做到让一个页面不言而喻,那么至少应该让它自我解释,这个非常重要。



我们常常认为用户会盯着每个网页,仔细阅读我们精心制作的文字,领会我们组织页面的方式,然后,在点击某个链接之前权衡他们的可选目标。


但是大部分情况却是,用户只会在每个页面上瞥一眼,扫过一些文字,点击第一个令他们感兴趣或者大概符合他们目标的链接。通常,页面上的很多部分他们都不看(想一想,你是不是这样浏览网页的呢)。


本想举快手WEB端的例子,没想到再次打开后发现已经改版了,而且应该是近两个月左右的事情,可惜已经不能截图,不过这次的改版比之前好多了。

上一版本中,几乎有几段整段整段的文字,虽然文采不错,比较优美吧,但谁有耐心看呢,总之我打开几次,一次也没一字一字的阅读过。这个直接增加了用户的负担,降低了主要元素的层级,画蛇添足。


所以,如果我们想设计有效的网页,必须开始接受关于网络使用的三个事实:


一、我们不是阅读,而是扫描


原因有3:

1、我们总是处于忙碌之中;

2、我们知道自己不必阅读所有内容,只对网页中的一小部分内容感兴趣,剩下的内容我们并不关心,扫描就是我们找到相关内容的方式。

3、我们善于扫描,在日常生活中,我们不管是看报纸,还是杂志,书籍,基本都是用扫描的方式,找到我们感兴趣的部分。


大家想一想,我们在看报纸的时候,是不是先浏览一遍,然后看到哪个标题比较吸引才专心去看那篇文章,而且也不会是一字一句的去读,而是知晓大概内容即可。


再举个贴近的例子,打开站酷的首页,你们会从左到右,从上到右的一字不漏的去看吗,我们是不是用眼睛扫一遍,看到吸引你的内容,然后再点进去看详情,对的,这就是互联网用户的扫描阅读。



二、我们不做最佳选择,而是满意即可


在设计页面时,我们通常假设用户只是扫过整个页面,考虑所有可能的选项,然后选择一个最好的。


事实上,大多数时间里,用户不会选择最佳选项,而是选择一个合理的选项,一旦发现一个链接,看起来似乎能跳转到我们想去的地方,那很大的机会就会去点击它。


原因有以下几个:

1、我们总是处于忙碌之中,寻找最佳策略需要的时间很长。

2、如果猜错了,也不会产生什么严重的后果。就算做了错误选择,我们只要点击几次返回按钮就好,所以,返回按钮,是WEB端用的最多的地方。

3、对选择进行仔细思考还不如很快多尝试几次。

4、猜测更有意思,猜测不会像仔细权衡那么累,而且如果猜对了,速度会更快。


当然,这并不是说用户在点击之前从不进行权衡,这要取决于时间上的紧迫以及其他因素。


大家想一想,现实中是不是这样的呢。也许通往一个入口有好几条路径,但是第一次进入该网站的时候,不会寻找最佳路径,而是试探的摸索,只要找到就可以了,不会刻意的找那条最捷径的。

 

三、我们不是追根究底,而是勉强应付。


生活中,人们在使用任何东西,往往不理解它们的运作原理,甚至对它们的工作原理有完全错误的理解。


无论面对哪种产品,除了刻意钻研的,很少有人会花时间阅读说明书。相反,我们往往是贸然前进,勉强应付。


比如我们买了一台新款电视机,几乎从来不会把电视机的零件一个个都拆下来,完全理解了它们的工作原理后才使用,我们甚至连说明书都不看,而是拿着遥控器自己琢磨,完全没有必要去深究。



为什么会这样?

1、这对我们来说并不重要。对于大多数人来说,是否明白背后的工作机制并不重要,只要正常使用即可,这并不是智力低下的表现,而是我们并不关心。

2、如果发现某个事物能用,我们会一直使用它。我们一旦发现某个事物能用,很少去找更好的替代品。如果偶然发现一种更好的方法,我们会换用这种更好的方法,但很少去主动寻找更好的。


举个我小时候的例子,上学时我用的第一只中性笔是同学给我的,虽然可以用,但我发现比较粗,不太喜欢,但是认为可以用,从来没想过是否有稍微细一点的。当第一只笔芯用完,去文具店购买时,发现竟然还有0.35的笔芯,很意外,当然我就放弃了之前的笔芯,换作成0.35的,这样的例子应该都会发生在每个人的生活中。


那如果人们勉强应付的时候这么多,有没有弄明白真的那么重要吗?答案是很重要,因为有时候可以勉强应付,但通常效率不高,而且容易出错。


如果用户很清楚,不是勉强应付呢?

1、他们会更容易找到自己需要的东西。

2、会更容易理解你的网站提供哪些服务。

3、你更可能引导他们到你的网站上希望他们看到的地方。

4、在你的网站上,会觉得自己更聪明,感觉更好,这样他们就会离开让人勉强应付的网站了。


这也是现在竞品之间抢夺用户的一个重要因素,两个服务内容一样的产品,一个直观明了,一个结构比较混乱,不能很快找到目标,对于这两个产品,那用户该选择哪一个呢,可想而知。



前面已经说到,现在互联网的用户阅读都是扫描式阅读,那么在这种情况下,怎样才能让用户清晰理解你的网站,提高体验。


需要注意5个方面,保证他们会很容易理解你的网站:

1、在每个页面上建立清晰的视觉层次;

2、尽量利用习惯用法;

3、把页面划分成明确定义的区域;

4、明显标识可以点击的地方;

5、最大限度降低干扰;


前面已经说到,现在互联网的用户阅读都是扫描式阅读,那么在这种情况下,怎样才能让用户清晰理解你的网站,提高体验。


一个视觉层次清晰的页面有3个特点:

1、越重要的部分越突出;

2、逻辑上相关的部分,视觉上也相关;

3、逻辑上包含的部分在视觉上游嵌套;

 

也可以这么说,要把版式设计的四个原则,亲密,重复,对齐,对比,把这几点做好。

 

对于习惯用法可以说是人的一种本性习惯了,这也是为什么很多竞品都很相似的原因了。


举个常见的例子,比如聊天的icon,都是一种对话框的设计,因为人们已经习惯了这种图标设计,如果换成其他,用户看到后会不理解这到底是什么东西。



对于设计师,很多人一直想创新,但是一定要秉持两个原则:

1、创新的方法同样也要不言而喻;

2、能够为用户带来很大价值,值得用户付出一点努力来学习新的方法。



Krug可用性第二定律——点击多少次都没关系,只要每次点击都是无须思考的选择。

 

文中说:WEB设计师和可用性专家一直有一个争论,用户在到达目标之前点击多少次不会觉得有挫败感,作者认为,真正的问题不是到达目标之前要点击的次数,而是每次点击有多艰难,需要多少思考,有多大的不确定性来判断自己是否在进行正确的选择。

 

所以当我们在使用目前一些成功的产品时,会感到自然而然的流畅体验,虽然有时候因为产品体量大,没有很快找到目标,但我们也没有过多挫败和烦躁。


Krug可用性第三定律——去掉每个页面上一半的文字,然后把剩下的文字再去掉一半。


好处:

1、可以降低页面的噪声。

2、让有用的内容更加突出。

3、让页面更简短,让用户在每个页面上一眼就能看见更多的内容,而不必滚动屏幕。

 

如果有欢迎词,尽量减少,能不用就不用。

指示性说明尽量不用。

如果指示性说明非常冗长,用户发现所需信息的机会很小。

我们应该通过让每项内容不言而喻来完全消除指示性说明,当指示文字变得完全没有必要,就应把他们全部去掉。


现在比较成功的App的引导页都非常简洁,因为没有人会在进入的时候看你写的一长段文字,等待很长时间,除非视觉性很强,比如今年美团变黄的那段视频,视觉冲击力很强,我看完一次后,在网上又自己找,看了几次。所以要做到尽量减少指示性说明。



作者认为,很多网站,一旦到了第二个层次,导航会变得支离破碎,随意发挥,以至于很难找到良好的三级导航的例子。


原因有3:

1、好的多级导航本来就很难设计,同时有很多元素需要安排到页面中。

2、设计师即使在设计前两个层次也常感到时间不够。

3、第三个原因是它看起来并不重要,不是主导航,也不是二级导航,而且有一种倾向认为,当人们深入到网站的这一个层次后,会自然明白如何进行操作。

 

而且就算设计师提出需求,他们也可能拿不到,因为负责内容的通常不会想的那么深远。


事实上,用户在底层页面上花的时间通常和花在顶层页面的时间相同,除非从一开始就自顶往下进行导航设计,否则以后很难再进行添加,也很难保持一致性。


网站主页是我们打开后第一眼看到的,也是最容易向用户突出网站的价值等内容的,那在主页该放什么哪些内容比较合适呢:

1、站点的标识和使命:告诉我们这是什么网站,做什么的;

2、站点层次:提供服务概貌,包括内容,功能,组织形式;

3、搜索;

4、导读:主页最好有“里面有精彩内容”的暗示提醒;

5、内容经常更新;

6、友情链接;

7、快捷方式:最常访问的内容片断;

8、登录、注册;

...


除了这些主要的,最好还要满足这些:

1、让我看到自己正在寻找的东西;

2、我也许感兴趣的精彩内容;

3、告诉我从哪里开始;

4、建立可信度和信任感。

 

比如打开淘宝首页,你不仅可以看到以上罗列的内容,淘宝通过算法,会自动推荐你曾经搜索过得商品,最上角的非常醒目的位置,logo动效还会告诉你最近的活动。



对于一个控件的选择或者其他设计,很多团队经常在无休止的讨论,始终没有决定,这样的讨论除了浪费时间,也很容易造成紧张气氛,破坏团队成员之间的关系,常常让团队无法做出关键的决定.


我们每个人都是用户,和所有的用户一样,对网站上喜欢什么,不喜欢什么有着强烈的感觉。

 

我们往往认为我们自己喜欢的,绝大多数用户也都喜欢。这应该是人的一种天性。

 

同时,在团队中,由于职位不同,不同岗位的人对网站设计也有不同的看法。


比如设计师喜欢视觉上比较好看的网站,而开发却喜欢构建新颖,有趣,功能出色的网站。所以不同的角色,不同的视角,常常造成不同的看法,继而不停的讨论,让会议陷入僵局,当然每个人的想法并不是一层不变的,只要有足够的证据能打动他,他的想法完全可以反过来。


一旦因个人和职位不同而造成的冲突不分胜负时,讨论常常会转化为寻找某种方式(专家的意见、焦点小组或者用户测试)来决定绝大部分用户喜欢或不喜欢什么,但是,找出所谓的普通用户,就是错误的想法,因为,本来就没有什么普通用户,所有的web用户都是的。

 

越是仔细观察用户,认真倾听他们表达自己的想法,越能意识到他们对网页的个人反应和很多不同的变量有关系。所以,试图用一些简单的喜好来形容用户,既琐碎又没有什么作用,另一方面,好的设计会把这种复杂性考虑进去。


关于普通用户的这个说法,最糟糕的是加强了这种看法,认为好的web设计主要是找出人们的喜好,这种想法看上去不错。比如面包屑导航好,要么不好,弹出框好,要么不好,非黑即白。


问题是,对于大部分web设计问题来说,没有简单的“正确”答案,好的设计能满足需要,也就是说,经过仔细考虑,实现和测试的设计就是好的。


例如,对于Flash的使用,如果询问用户,有些用户会说他们很喜欢Flash,而另外差不多同样数量的用户会说他们讨厌Flash。实际上,他们不喜欢的是使用不当的Flash,大而复杂的动画,需要很长时间下载,没有带来任何价值。如果仔细观察他们,很可能发现同样是这些人,喜欢那些使用精心设计,适当并小规模使用Flash的网站,增加一些简约的修饰,或者有用的功能,同时又不带来麻烦。


并不是说不存在完全错误的方法,有些设计网页的方法确实是完全错误的,只是他们往往并不是设计团队通常争论的那些方法。


解决这种问题的关键方法就是,不要再问这样的问题“大部分人喜欢这样的导航吗”,正确的问题应该是“在这个页面,这种导航会让可能使用这个网站的大部分人产生一种良好的体验吗?”,然后观察人们对它的看法和使用的方法,再不断调整。


争辩人们喜欢什么既浪费时间又消耗团队的经历,而通过测试将讨论对错转移到什么有效,什么无效上,更容易缓和争论,打破僵局,而且测试会让我们看到用户的动机,理解,反应的不同,从而让我们不再坚持认为用户的想法和我们的想法一样。



在做测试时,往往很多人不清楚什么是焦点小组访谈和可用性测试的的区别,那就先科普一下。


焦点小组访谈,百度百科的解释是这样的:就是采用小型座谈会的形式,由一个经过训练的主持人以一种无结构、自然的形式与一个小组的具有代表性的消费者或客户交谈。从而获得对有关问题的深入了解。


简单来说就是一个小组围坐在桌子周围,主持人抛出问题,针对这一问题,被访谈人说出自己的想法,从而快速得到用户的意见和反应。


焦点小组可以抽象的确定你的目标用户想要什么,需要什么,喜欢什么。也可以测试出网站的理念是否有意义,价值主张是否吸引人等等。


但焦点小组只是适合用于网站设计前就应该进行的,是一个早期阶段方法。


比如电视剧《我的前半生》中,段晓天因得不到主角罗子君而为难她的那个片段,就是一次焦点小组访谈。



可用性测试的百度百科解释是这样的:让一群具有代表性的用户对产品进行典型操作,同时观察员和开发人员在一旁观察,聆听,做记录。


该产品可能是一个网站,软件,或者其他任何产品,它可能尚未成型。测试可以是早期的纸上原型测试,也可以是后期成品的测试。


简单说就是向用户展示一些内容,不管是网站还是原型,或是草图,并且要求用户说出这是什么,并用他们来完成一项特定的任务。


如果想建立一个优秀的网站,一定要测试。为一个网站工作几个星期会让你失去新鲜感,因为你对网站了解的太多,很多细节都知道,所以清楚网站是否正常运作的唯一方法就是测试。


测试会提醒你,不是每个人的想法都和你一样,会和你用同样的方法使用网站。


要记住,测试一个用户比不做测试好一百倍。测试总是会有效果,哪怕对错误的用户做一次糟糕的测试,也会让你看到改善网站的一些方面。


在项目中,早做测试,哪怕一位用户也好过最后测试50位用户。


一旦一个网站投入使用,要改变就不是很容易了,有些用户拒绝做出任何变化,所以在开始的时候,有助于防止你犯错误的方法都很划算。


测试的关键不是证明什么或者反驳什么,而是了解你的判断力。对于用户的招募也不要太严格,如果能够让用户是更接近使用网站的用户就更好了,但更重要的是,要尽早和经常进行测试,这是一个开发,测试,修复,再度测试的过程,没有什么比现场用户的反应更重要了。

 

其实做可用性测试没有想象的那么复杂,一个简单的可用性测试完全可以把问题解决。

 

那么应该测试多少用户呢:

很多情况下,每轮测试用户数量应该是三个,最多四个。前三个用户很可能会遇到几乎所有最明显的问题,更重要的是多做几轮测试,只测试三名用户有助于很快进行下一轮测试。由于你会修正在第一轮测试提出的问题,因此在第二轮测试中,就会发现新的问题。这样的话,能够很快的对测试进行总结,并能很快利用测试结果进行修正。

 

很多人不知道该招募怎样的测试人员,总是很纠结,其实没那么难。


实际上,我们都是初学者。就算找一位专家,你也有可能发现他也在勉强应付。


设计出的网站如果只有你的目标用户能使用,这通常不是一个好的方法,应该既要满足专家的要求也要满足新手的要求。


例外:

如果你的网站几乎由某一类用户使用,那就只招募这一类用户。


如果你的目标用户群体可以分成几个明显的阵营,而且这些阵营有着完全不同的兴趣和需要,那么至少要从每个阵营里选择用户进行一次测试。


同时避免对网站或网站背后的组织架构进行预先讨论。


可以找任何人来引导测试,真正需要的工作只是鼓励测试用户去尝试。同时还需要一个观察人,对于观察人选,建议如果能让管理层参与就好了,他们的参加能极大鼓舞团队的士气,这是他们第一次看到自己的网站被人使用,而且很多地方和他们想象的画面并不一样,这样的话,团队也更容易向管理层拿到对测试的投资,可谓是一举两得。



测试什么,什么时候测试?


测试:顾名思义,就是让测试用户看到网站,然后看他们能否理解这个网站,包括目标,价值主张,组织方法和运行方式等。

可以对用户进行关键任务测试,让用户完成一些任务,然后观察他们是怎么做的。

 

立刻回顾测试结果


在测试后的讨论会议上,主要做以下两件事:


给问题分类:

回顾大家看到的问题,决定哪些问题需要修正。


解决问题:

找出修正这些问题的方法。


这样,从其他人的角度看你的作品,常常能为问题提供全新的解决方案,或者让你用一种新的眼光看待原有的问题。


要记住,这是一个循环的过程,不能只做一两次就停止了。

  

测试常见问题:


1、用户不清楚概念:用户看着网站,要么不清楚他们说的是什么,要么他们以为自己知道,但是理解有误。

2、他们找不到自己要找的字眼:这通常意味着你组织的内容分类不符合用户的习惯或者分类符合他们的习惯,但没有使用他们期望的名字。

3、内容太多了:有时候,他们要找的内容就在页面上,但就是看不到,在这种情况下,你需要减少页面上的整体干扰或者把他们需要看到的内容设置的更加醒目,让它们从可视层次结构中更加突出。

 

在任何测试中,你都可能会遇到这样的情况,用户暂时出现错误,然后在不需要任何帮助的情况下回到原来的轨道。


只要出现问题的人马上发现自己偏离了原来的主体,尽量不需要帮助就能回到原来的方向,这种情况看起来没有扰乱他们的活动,就可以忽略这些。总的来说,如果用户关于在哪里找到他们需要的内容的第二次猜测总是对的,就可以了。


这样的问题总会存在的,因为有些含混之处,总是没有简单的解决方法,不管怎么做,都会有一半用户在第一次猜测的时候出错,但每个人都会在第二次猜测之内找到,这样就好。

 

当在测试时清楚看到人们没有理解某些内容时,大部分人的第一反应是增加一些内容,例如一些注释或者指导说明。


这样的方法不对,正确的解决方案往往是去除某个或一些让人混淆的内容,而不是增加另一些干扰。


而且不要太看重人们对新功能的需求,人们常常说“如果它能像某某”就好了,这样的说法常常被看做是在要求新的功能,如果仔细询问,常常会发现,他们已经找到一个很好的网站,能做某某功能,就算你做了这个功能,他们也不会切换到你的网站,他们只是在告诉你他们的喜好而已。

 

当大家看到第一个用户试着勉强应付的时候,问题和解决方法都很明显的那种惊喜,就像是现成的收获,你应该马上修正它们。

 

和任何好的设计一样,成功的网页需要巧妙的平衡,要记住,哪怕一个微小的变化都会带来不小的影响,有时候,真正的挑战不是修正你发现的问题,而是修正这些问题的同时不破坏已经正常运行的部分。


只要进行改变,就要仔细思考它将会影响哪些其他内容。特别是,当你把某些部分调整的更为突出时,想想看是不是把其他内容的重要性降低了。


降低网站好感度有几种方式:

1、隐藏我想要的信息;

2、因为没有按照你们的方式行事而惩罚我;

3、向我询问不必要的信息:大多数用户都很介意个人信息,如果网站要求的信息超出当前任务时,会让用户觉得很麻烦。

4、敷衍我,欺骗我:我们都会讨厌虚伪的真诚,也讨厌假意的关心,想想每次你听到“您的电话对我们来说很重要”的时候是什么感觉吧!

5、给我设置障碍:不得不等待一个长长的flash介绍。

6、你的网站看上去不专业:网站看起来很凌乱,组织很混乱。


就算你有些地方做的不好,也还有可能再度提高我的好感,只要让我相信你的所作所为是在为我着想。


提高好感的几种方式:

1、知道人们在你的网站上想做什么,并让他们容易明白:把用户最想做的几件事放在最明显的地方;

2、告诉我我想知道的。

3、尽量减少步骤,让用户以最快的途径到达他们想去的地方。

4、知道我可能有哪些疑问,并且给予解答:可以做一个经常更新的常见列表。

5、为我提供协助。

6、容易从错误中恢复:当潜在的错误不可避免时,要提供一个快速且清晰的方法快速从错误中恢复。

7、如果不确定,记得道歉:有时候会因为暂时没有能力或资源做到用户想要的,如果你做不到,至少让他们明白你知道你在给他们造成不便。

一个例子让你明白原型对象和原型链

seo达人

开篇

之前对js中的原型链和原型对象有所了解,每当别人问我什么是原型链和原型对象时,我总是用很官方(其实自己不懂)的解释去描述。有一句话说的好:如果你不能把一个很复杂的东西用最简单的话语描述出来,那就说明你没有真正的理解。最近正在读《Javascript高级程序设计》,书中对原型对象和原型链的描述让我受益匪浅,下面仅用一个对比性的例子来说明。



我们经常会这么写

    function Person () {

        this.name = 'John';

    }

    var person = new Person();

    Person.prototype.say = function() {

        console.log('Hello,' + this.name);

    };

    person.say();//Hello,John

1

2

3

4

5

6

7

8

上述代码非常简单,Person原型对象定义了公共的say方法,虽然此举在构造实例之后出现,但因为原型方法在调用之前已经声明,因此之后的每个实例将都拥有该方法。从这个简单的例子里,我们可以得出:



原型对象的用途是为每个实例对象存储共享的方法和属性,它仅仅是一个普通对象而已。并且所有的实例是共享同一个原型对象,因此有别于实例方法或属性,原型对象仅有一份。



所以就会有如下等式成立:



    person.say == new Person().say

1

可能我们也会这么写

    function Person () {

        this.name = 'John';

    }

    var person = new Person();

    Person.prototype = {

        say: function() {

            console.log('Hello,' + this.name);

        }

    };

    person.say();//person.say is not a function

1

2

3

4

5

6

7

8

9

10

很不幸,person.say方法没有找到,所以报错了。其实这样写的初衷是好的:因为如果想在原型对象上添加更多的属性和方法,我们不得不每次都要写一行Person.prototype,还不如提炼成一个Object来的直接。但是此例子巧就巧在构造实例对象操作是在添加原型方法之前,这样就会造成一个问题: 

当var person = new Person()时,Person.prototype为:Person {} (当然了,内部还有constructor属性),即Person.prototype指向一个空的对象{}。而对于实例person而言,其内部有一个原型链指针proto,该指针指向了Person.prototype指向的对象,即{}。接下来重置了Person的原型对象,使其指向了另外一个对象,即



 Object {say: function}

1

这时person.proto的指向还是没有变,它指向的{}对象里面是没有say方法的,因为此报错。



从这个现象我们可以得出:



在js中,对象在调用一个方法时会首先在自身里寻找是否有该方法,若没有,则去原型链上去寻找,依次层层递进,这里的原型链就是实例对象的proto属性。



若想让上述例子成功运行,最简单有效的方法就是交换构造对象和重置原型对象的顺序,即:



    function Person () {

        this.name = 'John';

    }

    Person.prototype = {

        say: function() {

            console.log('Hello,' + this.name);

        }

    };

    var person = new Person();

    person.say();//person.say is not a function

1

2

3

4

5

6

7

8

9

10

一张图让你秒懂原型链

 



其实,只需要明白原型对象的结构即可:



    Function.prototype = {

        constructor : Function,

        proto : parent prototype,

        some prototype properties: ...

    };

1

2

3

4

5

总结:

函数的原型对象constructor默认指向函数本身,原型对象除了有原型属性外,为了实现继承,还有一个原型链指针proto,该指针指向上一层的原型对象,而上一层的原型对象的结构依然类似,这样利用proto一直指向Object的原型对象上,而Object的原型对象用Object.prototype.proto = null表示原型链的最顶端,如此变形成了javascript的原型链继承,同时也解释了为什么所有的javascript对象都具有Object的基本方法。



Blog同步


w3cschool编程实战之JavaScript 队列

seo达人

JavaScript 队列

题目:

在计算机科学中 队列(queue)是一个抽象的数据结构,队列中的数据条目都是有秩序的。新的条目会被加到 队列 的末尾,旧的条目会从 队列 的头部被移出。



写一个函数 queue ,用一个数组arr和一个数字item作为参数。数字item添加到数组的结尾,然后移出数组的第一个元素,最后队列函数应该返回被删除的元素。

queue([], 1) 应该返回 1

queue([2], 1) 应该返回 2

queue([5,6,7,8,9], 1) 应该返回 5

在 queue(testArr, 10) 之后, testArr[4] 的值应该是 10



通关答案:



function queue(arr, item) {

/下面这两句是关键/

    arr.push(item);

    return arr.shift();// Change this line

}



console.log(queue([], 1));

console.log(queue([2], 1));

console.log(queue([5,6,7,8,9], 1));

// Test Setup

var testArr = [1,2,3,4,5];



// Display Code

console.log("Before: " + JSON.stringify(testArr));

console.log(queue(testArr, 10)); // Modify this line to test

console.log("After: " + JSON.stringify(testArr));



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

页面跳转的两种方式(转发和重定向)区别及应用场景分析

seo达人

转发和重定向区别详解

        作为一名程序员,特别是java web开发的程序员,在使用servlet/jsp的时候,我们必须要知道实现页面跳转的两种方式的区别和联系:即转发和重定向的区别。



      1、RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect 方法不仅可以重定向到当前应用程序中的其他资源,还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。如果传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头,它是相对于整个WEB站点的根目录;如果创建RequestDispatcher对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录。、



      2、调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;而调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。



      3、HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的 访问请求,这个过程好比有个绰号叫“浏览器”的人写信找张三借钱,张三回信说没有钱,让“浏览器”去找李四借,并将李四现在的通信地址告诉给了“浏览器”。于是,“浏览器”又按张三提供通信地址给李四写信借钱,李四收到信后就把钱汇给了“浏览器”。可见,“浏览器”一共发出了两封信和收到了两次回复, “浏览器”也知道他借到的钱出自李四之手。RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。这个过程好比绰号叫“浏览器”的人写信找张三借钱,张三没有钱,于是张三找李四借了一些钱,甚至还可以加上自己的一些钱,然后再将这些钱汇给了“浏览器”。可见,“浏览器”只发 出了一封信和收到了一次回复,他只知道从张三那里借到了钱,并不知道有一部分钱出自李四之手。



       4、RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程。对于同一个WEB应用程序的内部资源之间的跳转,特别是跳转之前要对请求进行一些前期预处理,并要使用HttpServletRequest.setAttribute方法传递预处理结果,那就应该使用RequestDispatcher.forward方法。不同WEB应用程序之间的重定向,特别是要重定向到另外一个WEB站点上的资源的情况,都应该使用HttpServletResponse.sendRedirect方法。



        5、无论是RequestDispatcher.forward方法,还是HttpServletResponse.sendRedirect方法,在调用它们之前,都不能有内容已经被实际输出到了客户端。如果缓冲区中已经有了一些内容,这些内容将被从缓冲区中。



以上五点的论述来源于:点击查看原文论述



转发和重定向的图解





两种跳转获得对象的方式

//获得转发对象getRequestDispatcher()

HttpServletRequest(httpServletRequest).getRequestDispatcher

ServletContext.getRequestDispatcher();

 

//获得重定向对象sendRedirect()

HttpServletResponse(httpServletResponse).sendRedirect();

转发和跳转的小结

      1、转发使用的是getRequestDispatcher()方法;重定向使用的是sendRedirect();



      2、转发:浏览器URL的地址栏不变。重定向:浏览器URL的地址栏改变;



      3、转发是服务器行为,重定向是客户端行为;



      4、转发是浏览器只做了一次访问请求。重定向是浏览器做了至少两次的访问请求;



      5、转发2次跳转之间传输的信息不会丢失,重定向2次跳转之间传输的信息会丢失(request范围)。



转发和重定向的选择

      1、重定向的速度比转发慢,因为浏览器还得发出一个新的请求,如果在使用转发和重定向都无所谓的时候建议使用转发。



      2、因为转发只能访问当前WEB的应用程序,所以不同WEB应用程序之间的访问,特别是要访问到另外一个WEB站点上的资源的情况,这个时候就只能使用重定向了。



转发和重定向的应用场景

       在上面我已经提到了,转发是要比重定向快,因为重定向需要经过客户端,而转发没有。有时候,采用重定向会更好,若需要重定向到另外一个外部网站,则无法使用转发。另外,重定向还有一个应用场景:避免在用户重新加载页面时两次调用相同的动作。



       例如,当提交产品表单的时候,执行保存的方法将会被调用,并执行相应的动作;这在一个真实的应用程序中,很有可能将表单中的所有产品信息加入到数据库中。但是如果在提交表单后,重新加载页面,执行保存的方法就很有可能再次被调用。同样的产品信息就将可能再次被添加,为了避免这种情况,提交表单后,你可以将用户重定向到一个不同的页面,这样的话,这个网页任意重新加载都没有副作用;



       但是,使用重定向不太方便的地方是,使用它无法将值轻松地传递给目标页面。而采用转发,则可以简单地将属性添加到Model,使得目标视图可以轻松访问。由于重定向经过客户端,所以Model中的一切都会在重定向时丢失。但幸运的是,在Spring3.1版本以后,我们可以通过Flash属性,解决重定向时传值丢失的问题。



       要使用Flash属性,必须在Spring MVC的配置文件中添加一个<annotation-driven/>。然后,还必须再方法上添加一个新的参数类型:org.springframework.web.servlet.mvc.support.RedirectAttributes。



       如下所示:



@RequestMapping(value="saveProduct",method=RequestMethod.POST)

public String saveProduct(ProductForm productForm,RedirectAttributes redirectAttributes){

 

     //执行产品保存的业务逻辑等

  

     //传递参数

       redirectAttributes.addFlashAttribute("message","The product is saved successfully");

   

     //执行重定向

      return "redirect:/……";



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

日历

链接

blogger

蓝蓝 http://www.lanlanwork.com

存档