首页

为什么2020年初爆火的新拟物化设计,完全无法落地使用?

涛涛

新拟态设计(Neumorphism UI)是 2020 年 UI 设计的主要趋势之一,你可以在 dribbble 上看到很多作品,新拟态是基于New+Skeuomorphism  英文单词的拼写。它是一种使用对象阴影的模糊、角度和强度来突显出对象的样式。由于其柔和的阴影和整体的外观,使该设计看起来更加的逼真、未来、现代、真实、有吸引力。

但是老实说,这不是最实用的设计。尝试设计和上线以「新拟态」为整体调性的产品,很有可能让所有人失望,包括你们的同事、用户和可访问性用户(目前有 5700 万美国人患有某种程度的残疾。在上网的用户中,有 54% 的成年人是残障人士,来源于:W3.org)。

根据 W3 的说法,web 和移动端的可访问性包括影响访问的所有障碍,包含:

  • 听觉的
  • 认知的
  • 神经学
  • 物理的
  • 语言/说话能力
  • 视觉的

仅新拟态而言并不支持:视觉、认知、物理方面设计。

让我们深入地讨论为什么新拟态 UI 和 可访问性是无法共存的。

免责声明:我不是可访问性和新拟态方面的设计专家,本文旨在分享一些有关新拟态的一些想法。下面使用的 dribbble 作品仅供参考,以突出我在此问题上的观点。没有一丝评价、嘲笑、不尊重以下设计师的意思,如果你的设计在下面展示了,并且你希望我尽快删除,请及时联系我。

视觉

新拟态对视力低下、失明、色盲的用户来说,可辨识性较差。

△ https://dribbble.com/shots/10006635-Neumorphic-Rebound-of-Nomad-iOS-UI-Kit

当设计中带有重要 CTA 按钮时,你经常考虑并注意使它重点突出,并且在页面上容易被识别阅读。但是,当使用新拟态的设计风格时,没有诸如对比度之类的东西,因为按钮的材质与背景是相同的,唯一将它们分开的是角度和各种柔和的阴影。

△ https://dribbble.com/shots/9393020-Mi-Remote-Control-Mobile-app

根据 W3.org 关于移动端可访问性的描述:

与台式机/笔记本电脑设备相比,移动设备更可能用于各种环境中,包括户外。在户外,阳光或其他强光源下更可能产生眩光,这种情况提高了对所有用户使用良好对比度的重要性,并可能加剧视力低下的用户在移动设备上访问对比度差的内容的挑战性。

与对比度问题相关的 WCAG 2.0 成功标准是(原文地址:https://w3c.github.io/WCAG21-zh/#contrast-minimum):

  • 1.4.3条:对比度(最小值)(AA级),要求对比度至少为 4.5:1(大号文本以及大文本图像至少保持 3:1)。
  • 1.4.6条:对比度(增强)(AAA级),要求对比度至少为 7:1(大号文本以及大文本图像至少保持 4.5:1)。

认知

新拟态让用户思考。

△ https://dribbble.com/shots/9592062-Neumorphism-Smart-Home

一般来说,带有阴影的元素通常比没有阴影的视觉上更加突出。但是,使用新拟态设计时,大多数元素都会漂浮并脱颖而出,在一个屏幕上互相竞争,用户很难轻易理解页面中的视觉层次和信息层级关系,这会导致界面缺少适当的焦点,从而在眼动追踪中造成混乱。

界面上缺少信息层级关系的结果,会对用户的决策过程以及他们的思考过程产生重大的影响。因此,如存在多个可操作的内容,但是信息层级,重点不突出,这会让用户在当前的流程或页面上产生困惑,很难理解正在发生的事情。从而可能导致错误的判断和误操作,好的 UI/UX 不需要让用户思考。

认知和学习障碍影响人们处理信息的方式。例如,它们可以影响人们的感知、记忆、语言、注意力、解决问题和理解力。类别和条件的术语各不相同,包括智力残疾、发育障碍、注意缺陷多动障碍(ADHD)、自闭症、痴呆症、诵读障碍等。

△ https://dribbble.com/shots/9916835-Neumorphism-Smart-Home-app

物理

新拟态会造成混乱:

  • 我可以点击吗?
  • 选择了什么?
  • 不是什么?
  • 这是可点击的吗?
  • 还是不是?

对象的阶段由内部/外部阴影决定和标识。由于新拟态围绕着各种阴影色调和角度变化,因此用户不禁要问,可点击与不可点击之间的界限在哪里。

△ https://dribbble.com/shots/9938821-Smart-home-app

每个使用新拟态的产品都可以根据其功能和要求有自己的 UI 设计规范,但是由于阴影、角度和浮动水平的不同,由于缺乏一致性,迷失了方向的可操作项,「新拟态」可能会给用户带来麻烦,最终为残疾用户造成身体障碍。

触发可操作性的元素应该足够清晰,以便与不可操作的元素(内容、状态信息等)明确区分。提供元素可操作的明确指示与具有可操作元素(如按钮或链接)的 web 和本机移动应用程序相关,尤其是在交互模式中,可操作元素通常以视觉方式检测(触摸和鼠标使用)。交互元素还必须由依赖于编程确定的可访问名称的用户(例如屏幕阅读器用户)检测到。

△ https://dribbble.com/shots/9838619-Music-Player-Neumorphism-Rebound-shot

从 dribbble 开始的新拟态的设计趋势,应该要在追随前认真地思考,是否适用?这是一个问题。

设计师可以自由地实践和探索他们倾向于哪种趋势或风格……我只是在这里展示和解释为什么「新拟态」和「可访问性」不能并存。我也不是来阻止你练习你的设计技巧(如果有的话,我鼓励每个人练习他们的技巧和探索他们的想法,但希望,考虑它可能对残疾用户的影响以及特殊场景下的实用性的思考)。

不过,我之前在另一篇文章中说过,我会再说一次:现在是 2020 年,作为一个设计师,我认为我们必须重新评估我们在设计实际产品时的设计方式。我们不能为所有人设计,但要排除残疾用户。在可访问性和使所有数字产品都可访问方面,我们还有很长的路要走,但是它必须要在某一个地方开始。例如,它可以从我们把新拟态抛在脑后开始,而从那时起专注于开发一种在美学上令人愉悦但又实用、现实的设计。谢谢。

文字来源:优设    作者:UX Talk

「设计系统」 构建指南

涛涛

这篇文章来自于 Invision 出品的书籍,围绕规划、设计、构建和实现设计系统的实践经历来指导读者,其中包含了经验丰富专家的真知灼见和一手经验。我很喜欢,也分享给大家,推荐阅读。这是一个系列,一共有 7 章,感兴趣的话,持续关注吧。

20 世纪 60 年代,计算机硬件技术的升级开始超越软件发展的速度。计算机的处理速度变得越来越快,价格也越来越便宜,但计算机软件开发仍然处于缓慢、难以维护的境地,并且还很容易出错。两者之间的差距以及解决这个问题的困境被称之为「软件危机」。

在 1968 年的北约软件工程会议上,道格拉斯·麦克罗伊(Douglas McIlroy)提出了基于组件开发有可能是解决「软件危机」的方法之一。基于组件开发是一种通过复用代码来提高编程潜力的方法,该方法能帮助编程工作更、更易于扩展。这样做既能减少编程工作量又能提升软件开发的速度,让软件更好地运用现代计算机的力量。

在 50 年后的今天,我们又面临着类似的挑战,只不过这一次是在设计领域。在 UI 设计中,设计的角色是在为特定需求量身定做解决方案,所以很难去基于整个应用进行扩展。

你有没有走查过你输出的界面,发现自己使用了几十种类似的蓝色,或者同一个按钮不同的用法,将这些样式组合对应到你设计的每一个 UI 界面,就会意识到一套不成体系的设计是多么的难以维护。

△ 一份 UI 样式走查收集的成果,里面罗列的十几种类似的按钮样式说明之前团队挖的坑有多深。

在这种状态下,设计要跟上开发的速度,公司可以选择做以下三件事:

  • 雇更多的人
  • 提高设计速度
  • 找到一个适用于多个问题的解决方案

通过复用设计,设计系统能够帮助团队更好、更快地构建产品——复用性使规范成为可能。这是设计系统的核心和价值。一个设计系统是一个可复用组件的合集,由清晰的规范作为指导,组合在一起构建成各种的应用程序。

50 多年来,工程师们一直在遵循着这个理念执行工作。现在是时候让设计充分发挥其潜力加入他们了。

用系统思维扩展设计

你可能已经清楚地意识到,设计系统已经成为当今软件行业的一个热门话题,并且理由也很充分。很多企业投资设计系统,因为他们认识到产品体验能够带来竞争优势,不仅能吸引和留住客户,更降低产品学习成本。

在重视设计系统的公司内部,通常能看见这种情况:

  • 设计团队不断壮大。
  • 设计师分布在整个公司的团队中,可能在多个部门。
  • 设计在整个公司平台上的各个产品中都起着关键作用。

如果你是设计师,那么前面所说对设计的投资听起来可能会令你很兴奋,但其实也带来很多挑战。当一个应用由不同的团队负责迭代各自模块的时候,你将如何跨平台设计一致的 UI?又如何使所有团队能够进行快速迭代?当团队的设计师设计出新的独立样式时,你又将如何处理这种不可避免的设计需求?

要了解如何应对上述的挑战,我们要先了解什么是设计系统。设计系统将个体和整体两个概念各自的优点结合在一起。

1. 标准

拥有 MAC 用户界面的技术知识是产品设计的关键因素,但了解用户界面背后的理论,才能够帮助你创造出色的产品。——苹果人机交互指南

为了设计卓越的用户体验,不仅要了解设计系统背后的内容,还要了解其设计的原因。我们一般会通过建立和遵守标准来达成共识,这样做能消除主观性和歧义性,保证产品团队内部不会出现摩擦和混乱。

这套标准的内容涵盖了设计和开发。例如对命名约定、无障碍标准和文件结构等等,帮助团队达成共识,减少出错。

视觉语言是设计标准的核心部分。定义颜色、形状、类型、图标、布局和动效的样式和用法对于创建品牌一致的用户体验至关重要。系统中的每个组件都包含这些元素,它们在表达品牌特性中扮演着不可或缺的角色。

没有标准,决策时就会无据可依。这不仅不能扩展设计,还会造成复杂、差劲的用户体验。

超越平台

视觉语言可以不局限于单一平台,可以在 Web,iOS,Android 和其他平台上延续。将规范文档展示在设计系统网站的醒目位置,能够帮助系统开发者了解组件的样式和交互模式。例如,Google 的 Material Design 就深入到其产品视觉语言的各个层面。

2. 组件

组件是系统中复用代码的一部分,它们充当应用程序界面的基础。组件的复杂性各不相同。将组件简化为单个功能(如按钮或下拉菜单)可以增加其灵活性,使其更易于复用。复杂的组件,如特定类型数据的图表,可以很好地满足其应用场景,但是这种复杂性限制它的使用场景数量。组件的复用性越高,需要维护的次数就越少,规模也就越简单。

基于组件的开发通过复用代码来减少技术开销。建立标准规范了这些组件的用途、样式和用法。两者结合在一起,就相当于为你的产品团队配备了一个清晰的系统,让他们了解到为什么和怎么做。

设计系统的价值

让我们详细看看设计系统如何帮助你解决一直以来的痛苦。

1. 扩展式设计

随着团队的成长,设计师通常会将注意力集中在应用程序的独立功能区域,如搜索和发现、帐户管理等。这就会导致设计碎片化,就像是一座设计的巴别塔,每个设计师都将他们的设计语言往上添。当设计师单独而不是系统地去解决问题时,就会发生这种情况。

没有通用设计语言统一产品和设计,用户体验就会开始崩溃。当缺乏设计规范时,设计讨论就变得毫无用处。为了使团队内部保持一致,必须要有一个共享的来源——可供参考的官方样式库。

大多数情况下的样式库都是静态的内容,例如设计模版。但是静态的参考几乎立刻就会过时。这就是为什么有的团队会建造像 Shopify’s Polaris 站点这样的网站——一个设计系统站点,用该设计系统构建而成,记录系统的所有方面,包括组件、指南和交互最佳使用场景。因为它是与系统一起构建的,所以它能够保持其永远是的。

对于产品团队而言,内部设计系统站点是最佳、最易访问的共享来源。它提供了一个引力,使团队成员保持一致和同步。

2. 管理你的债务

随着应用程序和团队的时间积累,会慢慢形成债务。这种债务不是金融债务,而是技术和设计债务。这些债务是因为解决独立问题获得的。设计债务由大量不可复用和不一致的样式和惯例组成,而维护它们是不可能完成的任务。随着时间的推移,这些债务的累积会成为减缓增长的巨大负担。

创造行为本身并不会产生债务——就像花钱本身并不会产生金融债务一样。但使用设计系统将使你的设计和代码保持足够简洁,同时仍然允许你进行升级和迭代。

3. 一致的设计

一致且重复使用的标准化组件,使你应用程序的易用性大大提升。标准化的组件还能让设计师花更少的时间关注样式,花更多的时间专注于提升用户体验。

4. 更快的原型

在设计系统下工作,你可以像玩乐高一样快速拼凑流程和交互,构建无数的原型和方案进行快速验证,从而帮助团队快速获得数据和结论。

5. 提高可用性

页面样式的不一致会影响产品的可用性,当 CSS 因为数不清的不一致样式元素和交互增加时,页面加载时间也会加长,这会导致很糟糕的用户体验。它还可能产生冲突的 CSS 和 JavaScript,从而可能破坏你的应用程序。通过使用设计程序,通过构建一个整体的组件库(而不是每页)来避免这些冲突,从而花费更少的时间来保证产品质量。

6. 建立可访问性程序

可访问性在组件级别就可以实现,针对残疾人士、网速较慢和老旧的计算机上进行优化。这是一个建立易用性程序很好的方法, 在第 3 章「构建设计系统」中,Katie Sylor-Miller 解释了设计系统如何帮助你改善产品的可用性,并保证遵守你所在国家/地区的法律。

(译者注:美国残疾人法案于 1990 年 7 月通过并签署,其中有规定网站的可用性必须遵守《美国残疾人法》(ADA)的相关内容。)

设计系统的误区

即使有上述说的这些好处,在团队内部推行一个设计系统的时候,仍然很难说服团队成员。设计师可能会感到局限或束缚,但通常这些被感知到的弱点正是设计系统的最大优势。

让我们来揭穿那些你在推行设计系统时经常会遇到的误区吧。

误区1:过于局限

误区:负责深入独立业务的设计师看到的设计标准可能会与其他需求的不一样,因此,他们会认为通用的设计系统过于局限,可能无法满足某些特定业务的需求。

现实:设计师通常会设计出自定义的解决方案以满足应用中的独立的业务,从而增加了设计和技术的负担。而使用设计系统,这些被设计的新解决方案可以被反馈到设计系统里面,使每个人都可以使用这些改进方案。

误区2:缺乏创造力

误区:如果设计师被限制在一个设计系统下做设计,那么他将不能去自由地探索设计风格。前端的工作通常包含着各种样式风格的更新。对应用程序的风格进行改版通常不是一个小任务。这也可能是一个很大的风险,因为从事这项工作会移除一部分的旧资源,可能会对可用性产生负面影响。

现实:设计系统的组成部分是相互关联的,这意味着当一个位置进行更改时,这项更改会在整个系统中同步,这使得系统内的样式更新工作变得轻而易举,但影响却大得多。以前是几周甚至几月的工作量,现在可以在一个下午就能完成。

误区3:一劳永逸

误区:设计和构建完设计系统后,工作就完成了。

现实:设计系统是有生命的,这意味着需要不断对其进行维护和改进。但是由于应用是由设计系统的复用性组件提供支持的,因此该应用会自动同步设计系统的改进内容,从而减少维护应用程序的工作量。这就是设计系统提供的扩展能力。

总结

设计系统不是一时流行的方法,也不是未经检验的假设。为了让设计找到与技术的快速发展相匹配的同等方案,基于组件的设计和开发是一种行之有效的可靠解决方案。

现在你已经了解了创建设计系统的真正价值,让我们在下一章中深入探讨实际的设计过程吧。

文章来源:优设    作者:彩云译设计

Vue.js 常用系统指令

seo达人

1.v-on :可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码



(1)v-on:click绑定点击事件



<!DOCTYPE html>

<html>

   <head>

      <meta charset="utf-8" />

      <title>v-on:click</title>

      <script src="js/vuejs-2.5.16.js"></script>

   </head>

   <body>

      <div id="app">

         {{message}}  

         <button v-on:click="fun1('test')">vue的onclick</button>

      </div>

   </body>

   <script>

      //view model

      new Vue({

         el:'#app',

         data:{

             message:'hello vue'

         },

         methods:{

             fun1:function (msg) {

               this.message=msg;

                }

         }

      });

      

   </script>

</html> 









(2)v-on:keydown事件会在用户按下一个键盘按键时发生



<!DOCTYPE html>

<html>

 

   <head>

      <meta charset="utf-8" />

      <title>v-on:keydown</title>

      <script src="js/vuejs-2.5.16.js"></script>

   </head>

 

   <body>

      <div id="app">

         Vue:<input type="text" v-on:keydown="fun($event)">

         <hr/>

         传统JS:<input type="text"  οnkeydοwn="showKeyCode()"/>

      </div>

   </body>

   <script>

      //view model

      new Vue({

         el:"#app",

         methods:{

             / $event 它是vue中的事件对象  和我们传统js的event对象是一样的  /

             fun:function(event){

                    var keyCode = event.keyCode;

                    if(keyCode < 48  || keyCode > 57){

                        //不让键盘的按键起作用

                        event.preventDefault();

                    }

            }

         }

      });

 

 

      //传统js的键盘按下事件

      function showKeyCode(){

         //event对象和我们的document对象以及window对象是一样的,可以不用定义直接使用

         var keyCode = event.keyCode;

         if(keyCode < 48  || keyCode > 57){

            //不让键盘的按键起作用

            event.preventDefault();

         }

         // alert(keyCode);

         // if(event.keyCode == 13){

         //     alert("你按的是回车");

         // }

      }

   </script>

 

</html>





(3)v-on:mouseover  当鼠标指针位于元素上方时,会发生 mouseover 事件



<!DOCTYPE html>

<html>

 

   <head>

      <meta charset="utf-8" />

      <title>v-on:mouseover</title>

      <style>

         #div {

            background-color: red;

            width:300px;

            height:300px;

         }

      </style>

      <script src="js/vuejs-2.5.16.js"></script>

   </head>

 

   <body>

      <div id="app">

         <div @mouseover="fun1" id="div">

            <textarea @mouseover="fun2($event)">这是一个文件域</textarea>

         </div>

 

         <!--<div οnmοuseοver="divmouseover()" id="div">

            <textarea οnmοuseοver="textareamouseover()">这是一个文件域</textarea>

         </div>-->

      </div>

   </body>

   <script>

      //view model

        /*

       
@事件名称  就是  v-on:事件名称的简写方式

        @mouseover它就等同于v-on:mouseover

         
/

      new Vue({

         el:"#app",

         methods:{

            fun1:function(){

                alert("鼠标悬停在div上了");

            },

            fun2:function(event){

                alert("鼠标悬停在textarea上了");

                    event.stopPropagation();

            }

         }

      });

 

 

      //传统的js方式

      function divmouseover(){

          alert("鼠标移动到了div上了");

      }

 

      function textareamouseover(){

          alert("鼠标移动到了textarea上了");

          event.stopPropagation();

      }

   </script>

 

</html>





(4).Vue.js 为 v-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault() 或 event.stopPropagation()。注意:该方法将通知 Web 浏览器不要执行与事件关联的默认动作(如果存在这样的动作)



Vue.js通过由点(.)表示的指令后缀来调用修饰符。

.stop

.prevent

.capture

.self

.once

<!DOCTYPE html>

<html>

 

   <head>

      <meta charset="utf-8" />

      <title>v-on:事件修饰符</title>

      <style>

         #div {

            background-color: red;

            width:300px;

            height:300px;

         }

      </style>

      <script src="js/vuejs-2.5.16.js"></script>

   </head>

 

   <body>

      <div id="app">

         <form @submit.prevent action="http://www.itheima.com" method="post" >

            <input type="submit" value="提交">

         </form>

         <!--<form action="http://www.itheima.com" method="post" οnsubmit="return checkForm()">

            <input type="submit" value="提交">

         </form>-->

         <hr/>

         <div @mouseover="fun1" id="div">

            <textarea @mouseover.stop="fun2($event)">这是一个文件域</textarea>

         </div>

      </div>

   </body>

   <script>

      //view model

      new Vue({

         el:"#app",

         methods:{

                fun1:function(){

                    alert("鼠标悬停在div上了");

                },

                fun2:function(event){

                    alert("鼠标悬停在textarea上了");

                }

         }

      });

      

      

      //传统js方式

      function checkForm(){

          alert(1);

          //表单验证必须有一个明确的boolean类型返回值

         //在应用验证方法时必须加上 return  方法名称

         return false;

      }

   </script>

 

</html>

 







 



2.v-text与v-html



<!DOCTYPE html>

<html>

   <head>

      <meta charset="utf-8" />

      <title>v-text与v-html</title>

      <script src="js/vuejs-2.5.16.js"></script>

   </head>

   <body>

      <div id="app">

         <div v-text="message"></div>

         <div v-html="message"></div>

         <!--<div id="div1"></div>

         <div id="div2"></div>-->

      </div>

   </body>

   <script>

      //view model

      new Vue({

         el:"#app",

         data:{

             message:"<h1>Hello Vue</h1>"

         }

      });



      //传统js的innerText和innerHTML

      window.onload = function(){

          document.getElementById("div1").innerHTML="<h1>Hello</h1>";

            document.getElementById("div2").innerText="<h1>Hello</h1>";

      }

   </script>

</html>





 



(2)v-bind 插值语法不能作用在 HTML 特性上,遇到这种情况应该使用 v-bind指令



<!DOCTYPE html>

<html>



   <head>

      <meta charset="utf-8" />

      <title>v-bind的使用</title>

      <script src="js/vuejs-2.5.16.js"></script>

   </head>



   <body>

      <div id="app">

         <font size="5" v-bind:color="ys1">传智播客</font>

         <font size="5" :color="ys2">黑马程序员</font>

      </div>

   </body>

   <script>

      //view model

      //插值表达式不能用于html标签的属性取值

      //要想给html标签的属性设置变量的值,需要使用v-bind

      //v-bind也可以简化写法   直接使用:

      new Vue({

         el:"#app",

         data:{

             ys1:"red",

            ys2:"green"

         }

      })

   </script>



</html>





(3)v-model



<!DOCTYPE html>

<html>

   <head>

      <meta charset="utf-8" />

      <title>v-model</title>

      <script src="js/vuejs-2.5.16.js"></script>

   </head>

   <body>

      <div id="app">

         <form action="" method="post">

            用户名:<input type="text" name="username" v-model="user.username"><br/>

            密码:<input type="text" name="password" v-model="user.password"><br/>

            <!-- v-model替换原来的value属性的值,用value获取不到-->

         </form>

      </div>

   </body>

   <script>

      //view model

      new Vue({

         el:"#app",

         data:{

            user:{

                username:"test",

               password:"1234"

            }

         }

      })

   </script>

</html>





(4)v-for



 



<!DOCTYPE html>

<html>

   <head>

      <meta charset="utf-8" />

      <title>v-for遍历数组</title>

      <script src="js/vuejs-2.5.16.js"></script>

   </head>

   <body>

      <div id="app">

         <ul>

            <li v-for="(item,index) in arr ">{{item}}={{index}} </li>

            <!--index是索引的意思,用插值表达式输出 -->

         </ul>

      </div>

   </body>

   <script>

      //view model

      new Vue({

         el:"#app",

         data:{

             arr:[1,2,3,4,5]

         }

      })

   </script>

</html>





 



<!DOCTYPE html>

<html>

   <head>

      <meta charset="utf-8" />

      <title>v-for遍历对象</title>

      <script src="js/vuejs-2.5.16.js"></script>

   </head>

   <body>

      <div id="app">

         <ul>

            <li v-for="(key,value) in product ">{{value}}===={{key}} </li>

         </ul>

      </div>

   </body>

   <script>

      //view model

        new Vue({

            el:"#app",

            data:{

               product:{

                   id:1,

               name:"笔记本电脑",

               price:5000

            }

            }

        })

   </script>

</html>





<!DOCTYPE html>

<html>



   <head>

      <meta charset="utf-8" />

      <title>v-for遍历对象</title>

      <script src="js/vuejs-2.5.16.js"></script>

   </head>



   <body>

      <div id="app">

         <table border="1">

            <tr>

               <td>序号</td>

               <td>编号</td>

               <td>名称</td>

               <td>价格</td>

            </tr>

            <tr v-for="(product,index) in products ">

               <td>{{index}}</td>

               <td>{{product.id}}</td>

               <td>{{product.name}}</td>

               <td>{{product.price}}</td>

            </tr>

         </table>

      </div>

   </body>

   <script>

      //view model

        new Vue({

            el:"#app",

            data:{

                products:[

                   { id:1,name:"笔记本电脑",price:5000 },

                    { id:2,name:"手机",price:3000 },

                    { id:3,name:"电视",price:4000 }

                ]

            }

        })

   </script>



</html>





3.v-if与v-show



v-if是根据表达式的值来决定是否渲染元素

v-show是根据表达式的值来切换元素的display css属性

 

<!DOCTYPE html>

<html>

   <head>

      <meta charset="utf-8" />

      <title>v-if与v-show</title>

      <script src="js/vuejs-2.5.16.js"></script>

   </head>

   <body>

      <div id="app">

         <span v-if="flag">传智播客</span>

         <span v-show="flag">itcast</span>

         <button @click="toggle">切换</button>

      </div>

   </body>

   <script>

      //view model

      new Vue({

         el:"#app",

         data:{

             flag:false

         },

         methods:{

             toggle:function(){

                 this.flag = !this.flag;

            }

         }

      })

   </script>

</html>


vue框架渐进性的理解和mvvm模式的理解

seo达人

引言

现在市场很多前端开发的招聘岗位都或多或少的要求你要掌握vue,可以说vue在国内是非常的火爆的,下面我给大家介绍一下vue框架吧!

vue是渐进式框架



vue的核心是一个视图模板引擎,但是这并不能说明vue不是一个框架,如上图所示在声明式渲染(视图模板)基础上,vue可以添加组件系统component,vue-router客户端路由,vuex的状态管理,vue-cli构建工具来构建一个完整的框架,更重要的是这些功能相互独立,你可以任意选用你项目需要的部件,不一定非要全部整合在一起(就像是vuex它是一个很好的可以管理组件之间共享状态的部件,但非必须在你的每一个项目中使用它,如果说你的项目相对简单,组件之间的通信相对简单你完全可以不使用它),可以看到渐进式,其实就是vue的使用方式,同时也能看到vue的设计理念

vue是mvvm模式

为什么说vue是mvvm模式呢?这个大家首先要知道mvvm是什么。mvvm是Model-View-ViewModel的简写,即模型视图视图模型。模型是指后端传过来的数据,视图是指我们看到的页面,视图模型是mvvm框架的核心,他是连接view和model的桥梁,它有两个方向,第一将后端传来的数据转换成页面可以看到的视图,第二,将用户在页面上的交互转化成为后端数据,我们称之为双向绑定。

总结mvvm模式的视图和模型是不能直接通信的,它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信

vue框架可以理解为是ViewModel,它可以实现dom监听和数据绑定

vue的数据绑定原理



当你把JavaScript对象传入vue实例作为data选项,vue会遍历此对象的所以属性,并使用Object.defineProperty把这些属性转换为getter和setter,每一个组件都有一个watcher实例,它会在组件渲染过程中,把接触过的数据记录为依赖,当依赖的setter被触发是,他会通知watcher,重而使关联的数据重新渲染,以下是代码展示。



<div id = "box"></div>

var obox = document.getElementById('box')

var obj = {}

object.defineProperty(obj,'myname',{

get () {

// obj设置了一个myname属性,当访问obj.myname属性会执行get方法

},

set (data) {

// 当修改myname属性会执行set方法

// data会得到你修改的值

obox.innerHTML = data

}

})



object.definePeoperty有一下缺点: {

1:无法监听es6的set,map变化

2:无法监听class类型的数据

3:属性的新增和删除也无法监听

4:数组元素的新整和删除也无法监听

}




JS循环结构有哪些?循环结构概述

seo达人

所谓循环,就是重复执行一段代码,计算机的判断能力和人相比差的很远,计算机更擅长一件事情——不停的重复。而我们在JavaScript中把这叫做循环。下面让我们来了解了解JavaScript里的循环。



js循环结构有哪些

js循环结构有三种



for循环 ==> 用来多次遍历代码块

while循环 ==> 当指定条件为true时,循环代码块

do while ==> 当指定条件伪true时,循环代码块

1、for循环

for是由两个部分组成,条件控制和循环体

语法:



for(初始化表达式;循环条件表达式;循环后的操作表达式){

需要重复的代码块;

}



for语句结构如图:



for循环的执行顺序



1.初始化表达式

  1. 循环条件表达式
  2. 需要重复的代码块
  3. 循环后的操作表达式



    简单的for循环,循环执行一次会改变一个变量的值

    举例:输出1到100的值



    for(var i=1; i <= 100; i++){

    //在循环开始时设置一个变量i;//定义运行循环的条件i<=100;//每个循环执行后,变量增加1

    console.log(i);

    }



    2、while循环

    while循环会重复执行一段代码,直到某个条件不再满足。

    语法:



    while(条件表达式语句){

    执行的代码块;

    }



    while循环结构如图:



    while执行顺序

    当我们的使用条件条件返回值是true,就会执行大括号里面的代码块,执行完大括号的语句之后,会重复大括号里的语句,直到判定条件返回值为false,才会结束循环。



    案例:



    var i = 0;

    while (i < 10){

    console.log(i);

    i++;

    }

    //while循环会先判定条件,再根据条件是否成立达成决定是否进入循环

    //如果条件一开始就是false ,则不会进入循环



    缺点:



    使用while语句的时候,一定要写大括号

    如果没有条件的话,会无限的运行下去,造成死循环。

    3、do while循环的结构

    do while 结构的基本原理和while结构是基本相同的,但是它保证循环体至少被执行一次。因为它是先执行代码,后判断条件

    语法:



    do {

    执行语句块;

    }

    while(条件表达式语句);



    do while 执行顺序:

    先执行一次code,再做判断。与while循环不同,do while无论条件如何 都会执行一次代码

    案例:



    var i = 0;

    do{

    console.log(i);

    i++;

    }while(i<10);



    while 和 do while的不同

    while: 先判断 再执行 条件不成立 循环体 一遍都不执行

    do…while: 先执行 再判断 条件不成立 循环体 至少执行一遍


H5之外部浏览器唤起微信分享

seo达人

最近在做一个手机站,要求点击分享可以直接打开微信分享出去。而不是jiathis,share分享这种的点击出来二维码。在网上看了很多,都说APP能唤起微信,手机网页实现不了。也找了很多都不能直接唤起微信。

总结出来一个可以直接唤起微信的。适应手机qq浏览器和uc浏览器。

下面上代码,把这些直接放到要转发的页面里就可以了:

html部分:


  1. <script src="mshare.js"></script>//引进mshare.js
  2. <button data-mshare="0">点击弹出原生分享面板</button>
  3. <button data-mshare="1">点击触发朋友圈分享</button>
  4. <button data-mshare="2">点击触发发送给微信朋友</button>

js部分:


  1. <script>
  2. var mshare = new mShare({
  3. title: 'Lorem ipsum dolor sit.',
  4. url: 'http://m.ly.com',
  5. desc: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quaerat inventore minima voluptates.',
  6. img: 'http://placehold.it/150x150'
  7. });
  8. $('button').click(function () {
  9. // 1 ==> 朋友圈 2 ==> 朋友 0 ==> 直接弹出原生
  10. mshare.init(+$(this).data('mshare'));
  11. });
  12. </script>

下面是mshare.js的代码分享,把这些代码新建一个js文件放进去,然后在页面中引进就ok了。


  1. /**
  2. * 此插件主要作用是在UC和QQ两个主流浏览器
  3. * 上面触发微信分享到朋友圈或发送给朋友的功能
  4. */
  5. 'use strict';
  6. var UA = navigator.appVersion;
  7. /**
  8. * 是否是 UC 浏览器
  9. */
  10. var uc = UA.split('UCBrowser/').length > 1 ? 1 : 0;
  11. /**
  12. * 判断 qq 浏览器
  13. * 然而qq浏览器分高低版本
  14. * 2 代表高版本
  15. * 1 代表低版本
  16. */
  17. var qq = UA.split('MQQBrowser/').length > 1 ? 2 : 0;
  18. /**
  19. * 是否是微信
  20. */
  21. var wx = /micromessenger/i.test(UA);
  22. /**
  23. * 浏览器版本
  24. */
  25. var qqVs = qq ? parseFloat(UA.split('MQQBrowser/')[1]) : 0;
  26. var ucVs = uc ? parseFloat(UA.split('UCBrowser/')[1]) : 0;
  27. /**
  28. * 获取操作系统信息 iPhone(1) Android(2)
  29. */
  30. var os = (function () {
  31. var ua = navigator.userAgent;
  32. if (/iphone|ipod/i.test(ua)) {
  33. return 1;
  34. } else if (/android/i.test(ua)) {
  35. return 2;
  36. } else {
  37. return 0;
  38. }
  39. }());
  40. /**
  41. * qq浏览器下面 是否加载好了相应的api文件
  42. */
  43. var qqBridgeLoaded = false;
  44. // 进一步细化版本和平台判断
  45. if ((qq && qqVs < 5.4 && os == 1) || (qq && qqVs < 5.3 && os == 1)) {
  46. qq = 0;
  47. } else {
  48. if (qq && qqVs < 5.4 && os == 2) {
  49. qq = 1;
  50. } else {
  51. if (uc && ((ucVs < 10.2 && os == 1) || (ucVs < 9.7 && os == 2))) {
  52. uc = 0;
  53. }
  54. }
  55. }
  56. /**
  57. * qq浏览器下面 根据不同版本 加载对应的bridge
  58. * @method loadqqApi
  59. * @param {Function} cb 回调函数
  60. */
  61. function loadqqApi(cb) {
  62. // qq == 0
  63. if (!qq) {
  64. return cb && cb();
  65. }
  66. var script = document.createElement('script');
  67. script.src = (+qq === 1) ? '//3gimg.qq.com/html5/js/qb.js' : '//jsapi.qq.com/get?api=app.share';
  68. /**
  69. * 需要等加载过 qq 的 bridge 脚本之后
  70. * 再去初始化分享组件
  71. */
  72. script.onload = function () {
  73. cb && cb();
  74. };
  75. document.body.appendChild(script);
  76. }
  77. /**
  78. * UC浏览器分享
  79. * @method ucShare
  80. */
  81. function ucShare(config) {
  82. // ['title', 'content', 'url', 'platform', 'disablePlatform', 'source', 'htmlID']
  83. // 关于platform
  84. // ios: kWeixin || kWeixinFriend;
  85. // android: WechatFriends || WechatTimeline
  86. // uc 分享会直接使用截图
  87. var platform = '';
  88. var shareInfo = null;
  89. // 指定了分享类型
  90. if (config.type) {
  91. if (os == 2) {
  92. platform = config.type == 1 ? 'WechatTimeline' : 'WechatFriends';
  93. } else if (os == 1) {
  94. platform = config.type == 1 ? 'kWeixinFriend' : 'kWeixin';
  95. }
  96. }
  97. shareInfo = [config.title, config.desc, config.url, platform, '', '', ''];
  98. // android
  99. if (window.ucweb) {
  100. ucweb.startRequest && ucweb.startRequest('shell.page_share', shareInfo);
  101. return;
  102. }
  103. if (window.ucbrowser) {
  104. ucbrowser.web_share && ucbrowser.web_share.apply(null, shareInfo);
  105. return;
  106. }
  107. }
  108. /**
  109. * qq 浏览器分享函数
  110. * @method qqShare
  111. */
  112. function qqShare(config) {
  113. var type = config.type;
  114. //微信好友 1, 微信朋友圈 8
  115. type = type ? ((type == 1) ? 8 : 1) : '';
  116. var share = function () {
  117. var shareInfo = {
  118. 'url': config.url,
  119. 'title': config.title,
  120. 'description': config.desc,
  121. 'img_url': config.img,
  122. 'img_title': config.title,
  123. 'to_app': type,
  124. 'cus_txt': ''
  125. };
  126. if (window.browser) {
  127. browser.app && browser.app.share(shareInfo);
  128. } else if (window.qb) {
  129. qb.share && qb.share(shareInfo);
  130. }
  131. };
  132. if (qqBridgeLoaded) {
  133. share();
  134. } else {
  135. loadqqApi(share);
  136. }
  137. }
  138. /**
  139. * 对外暴露的接口函数
  140. * @method mShare
  141. * @param {Object} config 配置对象
  142. */
  143. function mShare(config) {
  144. this.config = config;
  145. this.init = function (type) {
  146. if (typeof type != 'undefined') this.config.type = type;
  147. try {
  148. if (uc) {
  149. ucShare(this.config);
  150. } else if (qq && !wx) {
  151. qqShare(this.config);
  152. }
  153. } catch (e) {}
  154. }
  155. }
  156. // 预加载 qq bridge
  157. loadqqApi(function () {
  158. qqBridgeLoaded = true;
  159. });
  160. if (typeof module === 'object' && module.exports) {
  161. module.exports = mShare;
  162. } else {
  163. window.mShare = mShare;
  164. }

好了,这样就可以直接唤起微信进行分享啦

事件冒泡和冒泡的阻止

seo达人

事件冒泡概念:当元素触发了事件的时候,会依次向上触发所有元素的相同事件。



事件冒泡的行为演示

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <title>Document</title>

    <style>

     #a{

         background: pink;

         width: 400px;

         height: 400px;

     }

     #b{

         background: green;

         width: 300px;

         height: 300px;

     }

     #c{

         background: red;

         width: 200px;

         height: 200px;

     }

    </style>

</head>

<body>

    <div id="a">

        我是a

          <div id="b">

                我是b

             <div id="c">我是c</div>

          </div>

    </div>

    <script>

     var a = document.querySelector('#a')

     var b = document.querySelector('#b')

     var c = document.querySelector('#c')



     a.onclick = fn1;

     b.onclick = fn2;

     c.onclick = fn3;



     function fn1(){

         alert('a来了')

     }



     function fn2(){

         alert('b来了')

     }

     

     function fn3(){

         alert('c来了')

     }

    </script>

</body>

</html>



上面这段代码一共有三个事件,三个div都分别绑定了单击事件。在页面中当单击c会连续弹出3个提示框。这就是事件冒泡引起的现象。事件冒 泡的过程是:c --> b --> a 。c冒泡到b冒泡到a。



冒泡的阻止

方法:

1.event.stopPropagation(); 是事件对象Event的一个方法,作用是阻止目标元素事件冒泡到父级元素 2.event.cancelBubble = true; IE浏览器的方法



<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <title>Document</title>

    <style>

     #a{

         background: pink;

         width: 400px;

         height: 400px;

     }

     #b{

         background: green;

         width: 300px;

         height: 300px;

     }



      #c{

         background: red;

         width: 200px;

         height: 200px;

     }

    </style>

</head>

<body>

    <div id="a">

        我是a

          <div id="b">

                我是b

             <div id="c">我是c</div>

          </div>

    </div>

    <script>

     var a = document.querySelector('#a')

     var b = document.querySelector('#b')

     var c = document.querySelector('#c')



     a.onclick = fn;

     b.onclick = fn;

     c.onclick = fn;



     function fn(event){

         var e = window.event || event;

         // 事件冒泡的阻止

         if(e.stopPropagation){

            e.stopPropagation();  // 通用写法

         }else{

             e.cancelBubble = true; // 阻止IE

         }

         var str = this.innerHTML;

         alert(str)

     }

    </script>

</body>

</html>


网页制作学习用好HTML字体标记及属性

前端达人

我们在这里将要谈的是有关文字的标记,包括字体大小、颜色、字型...等变化,适当的应用可以增加页面的美观!



常用字体标记



<Hn>...</Hn> 标题 ,设定标题字体大小, n = 1 ( 大 ) ~ 6 ( 小 ) 会自动跳下一行。通常用在如章节、段落等标题上。

如 : <H2> 标题 </H2>



标题

如 : <H3 ALIGN = CENTER> 标题 </H3> ( 标题置中 )

标题

<B>...</B> 粗体字 。

如 : <B> 粗体字 </B>



粗体字



<I>...</I> 斜体字 。

如 : <I> 斜体字 </I> 

斜体字



<U>...</U> 加底线 。

如 : <U> 加底线 </U> 

加底线



<DEL>...</DEL> 横线 ( 表示删除 )。

如 : <DEL> 横线 </DEL> 

横线



<TT>...</TT> 打字体 ( 固定宽度文字 )。

如 : <TT> 打字体 </TT> 

打字体



<SUP>...</SUP> 上标字 。

如 : 字体 <SUP> 上标字 </SUP> 

字体 上标字



<SUB>...</SUB> 下标字 。

如 : 字体 <SUB> 下标字 </SUB> 

字体 下标字



<!...> 注解 ( 不会显示在浏览器上 ),可以多行。



如 : <! 更新日期 : 2000/1/1>



设定字体大小、颜色、字型



有关设定文字的方法共有以下几种 :



1.设定HTML文件主体文字颜色。<BODY>...</BODY>标记。 



如 : <BODY TEXT=RED>...</BODY> 或 

<BODY TEXT=#FF0000>...</BODY>



2.设定基本字体大小、颜色、字型。<BASEFONT>...</BASEFONT>标记。



3.设定字体大小、颜色、字型。<FONT>...</FONT>标记。



<BASEFONT>...</BASEFONT> 设定基本字体 ,SIZE = 1 ~ 7,1 ( 最小 ) 7 ( 最大 )。

如 : <BASEFONT SIZE=4> 基本字体大小为 4 </BASEFONT> 

基本字体大小为 4



如 : <BASEFONT COLOR =#FF0000> 设定颜色 </BASEFONT> 

设定颜色



如 : <BASEFONT FACE = 标楷体 , 细明体 > 设定字型 </BASEFONT> 

设定字型



<BIG>...</BIG> 基本字体加大 。

如 : <BASEFONT SIZE=4> 基本字体大小为 4,</BASEFONT> 

<BIG> 加大为 5 </BIG> 

基本字体大小为 4, 加大为 5



<SMALL>...</SMALL> 基本字体减小 。

如 : <BASEFONT SIZE=4> 基本字体大小为 4,</BASEFONT> 

<SMALL> 减小为 3 </SMALL> 

基本字体大小为 4, 减小为 3



<FONT>...</FONT> 设定字体大小、颜色、字型 ,SIZE = 1 ~ 7,1 ( 最小 ) 7 ( 最大 )。

如 : <FONT SIZE=4> 字体大小为 4 </FONT> 

字体大小为 4



如 : <BASEFONT SIZE=4> 基本字体大小为 4 

<FONT SIZE= 1> 1字体大小为 5 </FONT> 

<FONT SIZE=-2> -2字体大小为 2 </FONT>...</BASEFONT> 

基本字体大小为 4 

1字体大小为 5 

-2字体大小为 2 



如 : <FONT COLOR =#FF0000> 设定颜色 </FONT> 

设定颜色



如 : <FONT FACE = 标楷体 , 细明体 > 设定字型 </FONT> 

设定字型



新建一个前端学习qun438905713,在群里大多数都是零基础学习者,大家相互帮助,相互解答,并且还准备很多学习资料,欢迎零基础的小伙伴来一起交流。


  1. 设定字体的大小分 : 绝对SIZE 如 : <FONT SIZE=4> 

    和 相对SIZE 如 : <FONT SIZE= 1> ( 以 BASEFONT 设定的字体大小做加减 )。


  2. 设定字体的颜色可以是颜色名称或#RRGGBB表红绿蓝强度 ( 00 暗 ~ FF 亮 )。 #RRGGBB 所代表的是红、绿、蓝三原色,每一色由两位十六进制的数值表示 ( 即十进制 0 ~ 255 )。 

    十六进制 : 0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F。


  3. 设定字体的字型会按照顺序找出显示的字型,若找不到则以系统预设字型显示。

    ————————————————

    版权声明:本文为CSDN博主「前端学习线路」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

    原文链接:https://blog.csdn.net/webxuexi168/article/details/104411193

Layui中使用ECharts

seo达人

日常”过坑“记录

只记录方法不说原理。。。



步骤:



ECharts下载

引入echarts.js

注意:这里好像只能用echarts.js,其它的不行,英文后面配置的时候要改东西(ps:我也不太不清楚)







修改echarts.js

打开echarts.js,在文件大概开始处添加如下代码



window.layui && layui.define ? layui.define(function(exports){exports('echarts',factory(exports))}) :

如图:







在文件内容末尾添加如下代码:



exports.parseGeoJson = parseGeoJson;

return exports;

如图:







 



layui添加配置并使用





ok了,和网上其它的相比,我这个应该是最简单的配置了。


B端web表格设计总结

涛涛

在B端的UI设计过程中经常要接触到大量的表单设计,且要展示海量数据,因此如何展示更清晰且让用户使用起来更便捷是设计师主要需要考虑的。结合自己在实际工作中遇到的列表类型总结了 web 表格设计的常用基础列表模式,并进行汇总以便后续使用。


一、基础型列表


web列表中的基础表格样式,通常用于横向表格的纵列数据较少时,使页面不需要滑动条也可以展示完全。操作项一般置于页面最右侧,便于用户浏览完全后进行操作。


二、 带有进度条的列表


用于查看数据完成进度,通常与网格型列表搭配使用,方便数据的直观对比,进度条用不同颜色进行区分,降低用户认知负荷。

三、可进行选择、排序、筛选、表头分组且带有冻结列的复合型表格

由于业务场景的复杂性,在B端系统中通常一个表格会涉及到大量复杂的操作,这就需要将多种样式叠加应用提高使用效率,防止用户产生疑惑。此图中用户既会进行单选或者批量选择,也有可能会对数据进行排序、筛选查看,对于专业术语或用户不常见的名词应给予一定的帮助说明。另外由于指标列选项过多,屏幕无法展示完全,还需要将重要列冻结,其他列增加滑动条来展示。


四、用于小计及总计的表格


小计行可能会出现一页多行的情况,用特殊颜色隔开,方便用户快速识别不同部分;总计行一般出现于页面最末端,通常只有一行,文字加粗显示。

五、行冻结、带有角标的可编辑表格


点击带有角标的表格可直接进行编辑更改数值;

整行冻结:当用户向上滚动查看或者翻页时,冻结的行依然悬浮显示于页面顶部。


六、主从型列表-可展开表格


表格默认收起状态,因为 B 端产品的业务数据量通常较大,默认展开多个主从关系表格对服务器的性能损耗较大。因此设定只有当用户点击下转箭头,此表格单独展开。

七、双排文字表格


适用于一屏以内文字内容较多且不需要完全展示时的解决方案。

我们都遇到过这样头痛的问题,当列表字段太多,一屏无法完全展示,这时应该怎么做?当用户需要鼠标频繁去滑动横向滚动条查看一屏以外的信息时,易导致操作成本和对屏幕展示信息的记忆成本提高,而产品的易用性降低。因此提供了除增加滚动条外的另一条解决方案,使用双排文字表格,可节省列表空间,部分内容省略表示,鼠标hover时展示全部内容。



总结:

1.关于对齐方式:随着工作范围的深入展开,发现之前做表格时对对齐方式并未做过多深入研究,导致不同项目的对齐方式并不一致,因此总结出一套方法:文本信息左对齐,因为现代人的阅读方式习惯从左到右,符合正常的心智;数据信息右对齐,更加方便数字大小的直观对比;内容一样居中对齐,视觉上更均衡;表头与信息内容对齐方式一致,给用户视觉上的统一感,降低视觉噪音。

2.当设计师把设计稿交给开发时,虽然已经标好注、切好图同时也包括交互注释,但是不代表开发能把界面表达的跟设计稿完全一样,甚至会有很大偏差。我们在设计的时候会考虑到字体大小、是否加粗、对齐方式等设计层级,但前端在开发时可能并不会注意到这些细节,因此需要保持与前端的良好沟通,包括出具走查文档及当面沟通,更能提高工作的质量和效率。

3.由于B端系统的复杂性,常需要不同的表单样式结合使用,因此还需设计时根据业务场景灵活运用。


文章来源:站酷    作者:小魔女4376 


日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档