性能优化(网络方向)
web应用无非是两台主机之间互相传输数据包的一个过程; 如何减少传输过程的耗时就是网络方向优化的重点, 优化出发点从第一篇文章中说起
DNS解析过程的优化
当浏览器从第三方服务跨域请求资源的时候,在浏览器发起请求之前,这个第三方的跨域域名需要被解析为一个IP地址,这个过程就是DNS解析;
DNS缓存可以用来减少这个过程的耗时,DNS解析可能会增加请求的延迟,对于那些需要请求许多第三方的资源的网站而言,DNS解析的耗时延迟可能会大大降低网页加载性能。
dns-prefetch
当站点引用跨域域上的资源时,都应在<head>元素中放置dns-prefetch提示,但是要记住一些注意事项。首先,dns-prefetch仅对跨域域上的DNS查找有效,因此请避免将其用于您当前访问的站点
<link rel="dns-prefetch" href="https://fonts.googleapis.com/">
preconnect
由于dns-prefetch仅执行DNS查找,但preconnect会建立与服务器的连接。如果站点是通过HTTPS服务的,则此过程包括DNS解析,建立TCP连接以及执行TLS握手。将两者结合起来可提供机会,进一步减少跨源请求的感知延迟
<!-- 注意顺序, precontent和dns-prefetch的兼容性 -->
<link rel="preconnect" href="https://fonts.googleapis.com/" crossorigin>
<link rel="dns-prefetch" href="https://fonts.googleapis.com/">
TCP传输阶段优化
这个前端方面好像能做的有限, 我们都知道 http协议 是基于 tcp的;
升级http协议版本可以考虑下, 比如把 http/1.0 -> http/1.1 -> http/2;
这个需要我们在应用服务器上配置(nginx, Apache等), 不做概述了, 另外还需要客户端和服务器都支持哦, 目前还没开发出稳定版本,好多只支持https,不过也不远了...
http2 的优势
# 1.多路复用: 同一个tcp连接传输多个资源
这样可以突破统一域名下只允许有限个tcp同时连接,
这样http1.1所做的减少请求数优化就没有太大必要了
如多张小图合成一张大图(雪碧图),合并js和css文件
# 2.报文头压缩和二进制编码: 减少传输体积
http1 中第一次请求有完整的http报文头部,第二次请求的也是;
http2 中第一次请求有完整的http报文头部,第二次请求只会携带 path 字段;
这样就大大减少了发送的量。这个的实现要求客户端和服务同时维护一个报文头表。
# 3.Server Push
http2可以让服务先把其它很可能客户端会请求的资源(比如图片)先push发给你,
不用等到请求的时候再发送,这样可以提高页面整体的加载速度
但目前支持性不太好...emm...
总的来说, 在 c 端业务下不会太普及, 毕竟需要软件支持才行...
http 请求响应阶段优化
为了让数据包传输的更快, 我们可以从两个方面入手: 请求的数据包大小(服务器), 请求数据包的频率(客户端)
减少请求文件的大小
请求文件对应的是我们项目完成后,打包所指的静态资源文件(会被部署到服务器), 文件越小, 传输的数据包也会相对较小, 讲道理也会更快到达客户端
how to reduce a package size?
目前我们都会使用打包工具了(比如webpack, rollup, glup 等), 如何使用工具来减小包的体积呢? 这边建议您去官网文档呢...当然这里列举一下常用的手段(webpack 的), 但是注意要插件版本更新哦
JS文件压缩
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
plugins: [
new UglifyJsPlugin({
// 允许并发
parallel: true,
// 开启缓存
cache: true,
compress: {
// 删除所有的console语句
drop_console: true,
// 把使用多次的静态值自动定义为变量
reduce_vars: true,
},
output: {
// 不保留注释
comment: false,
// 使输出的代码尽可能紧凑
beautify: false
}
})
]
}
CSS 文件压缩
// optimize-css-assets-webpack-plugin
plugins: [
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano'),
}),
];
html 文件压缩
// html-webpack-plugin
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html'),
filename: 'index.html',
chunks: ['index'],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false,
},
}),
];
source map 文件关闭
tree shaking
1.代码不会被执行,不可到达,比如 if(false){// 这里边的代码}
2.代码执行的结果不会被用到
3.代码只会影响死变量(只写不读)
4.方法不能有副作用
// 原理相关: 以后在研究
利用 ES6 模块的特点:
只能作为模块顶层的语句出现
import 的模块名只能是字符串常量
import binding 是 immutable 的
代码擦除: uglify 阶段删除无用代码
scope hoisting(作用域提升)
分析出模块之间的依赖关系,尽可能的把打散的模块合并到一个函数中去,但前提是不能造成代码冗余
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
module.exports = {
resolve: {
// 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件
mainFields: ['jsnext:main', 'browser', 'main']
},
plugins: [
// 开启 Scope Hoisting
new ModuleConcatenationPlugin(),
],
};
项目中使用按需加载,懒加载(路由,组件级)
const router = new VueRouter({
routes: [
{ path: '/foo', component: () => import(/* webpackChunkName: "foo" */ './Foo.vue') }
{ path: '/bar', component: () => import(/* webpackChunkName: "bar" */ './Bar.vue') }
]
})
开启 gizp 压缩
有时候启用也会消耗服务器性能, 看情况使用吧
暂时先提这么些吧...后续想到了再加
减少请求频率
因为同一域名下 tcp 连接数的限制导致过多的请求会排队阻塞, 所以我们需要尽量控制请求的数量和频率
常见措施
将静态资源的内联到HTML中
这样这些资源无需从服务器获取, 但可能影响到渲染进程...
<!-- 1.小图片内联 base64 (url-loader) -->
<!-- 2.css内联 -->
<!-- 3.js内联 -->
<script>
${require('raw-loader!babel-loader!./node_modules/lib-flexible/flexible.js')}
</script>
利用各级缓存(下一篇存储方面介绍)
通常都是在服务端做相关配置, 但你要知道
我们可以利用http缓存(浏览器端)来减少和拦截二次请求, 当然一般都是在服务端设置的;
服务器端也可以设置缓存(redis等), 减少数据查询的时间同样可以缩短整个请求时间
利用本地存储
我们可以将常用不变的信息存在本地(cookie,storage API 等);
判断存在就不去请求相关的接口, 或者定期去请求也是可以的
花钱买 CDN 加速
CDN 又叫内容分发网络,通过把资源部署到世界各地,用户在访问时按照就近原则从离用户最近的服务器获取资源,从而加速资源的获取速度。 CDN 其实是通过优化物理链路层传输过程中的网速有限、丢包等问题来提升网速的...
购买 cdn 服务器;
然后把网页的静态资源上传到 CDN 服务上去,
在请求这些静态资源的时候需要通过 CDN 服务提供的 URL 地址去访问;
# 注意, cdn 缓存导致的新版本发布后不生效的问题
所以打包的时候常在文件后面加上 hash 值
然后在 HTML 文件中的资源引入地址也需要换成 CDN 服务提供的地址
/alicdn/xx12dsa311.js
# 利用不同域名的 cdn 去存放资源, (tcp连接限制)
webpack 构建时添加 cdn
// 静态资源的导入 URL 需要变成指向 CDN 服务的绝对路径的 URL 而不是相对于 HTML 文件的 URL。
// 静态资源的文件名称需要带上有文件内容算出来的 Hash 值,以防止被缓存。
// 不同类型的资源放到不同域名的 CDN 服务上去,以防止资源的并行加载被阻塞。
module.exports = {
// 省略 entry 配置...
output: {
// 给输出的 JavaScript 文件名称加上 Hash 值
filename: '[name]_[chunkhash:8].js',
path: path.resolve(__dirname, './dist'),
// 指定存放 JavaScript 文件的 CDN 目录 URL
publicPath: '//js.cdn.com/id/',
},
module: {
rules: [
{
// 增加对 CSS 文件的支持
test: /\.css$/,
// 提取出 Chunk 中的 CSS 代码到单独的文件中
use: ExtractTextPlugin.extract({
// 压缩 CSS 代码
use: ['css-loader?minimize'],
// 指定存放 CSS 中导入的资源(例如图片)的 CDN 目录 URL
publicPath: '//img.cdn.com/id/'
}),
},
{
// 增加对 PNG 文件的支持
test: /\.png$/,
// 给输出的 PNG 文件名称加上 Hash 值
use: ['file-loader?name=[name]_[hash:8].[ext]'],
},
// 省略其它 Loader 配置...
]
},
plugins: [
// 使用 WebPlugin 自动生成 HTML
new WebPlugin({
// HTML 模版文件所在的文件路径
template: './template.html',
// 输出的 HTML 的文件名称
filename: 'index.html',
// 指定存放 CSS 文件的 CDN 目录 URL
stylePublicPath: '//css.cdn.com/id/',
}),
new ExtractTextPlugin({
// 给输出的 CSS 文件名称加上 Hash 值
filename: `[name]_[contenthash:8].css`,
}),
// 省略代码压缩插件配置...
],
};
/*
以上代码中最核心的部分是通过 publicPath 参数设置存放静态资源的 CDN 目录 URL,
为了让不同类型的资源输出到不同的 CDN,需要分别在:
output.publicPath 中设置 JavaScript 的地址。
css-loader.publicPath 中设置被 CSS 导入的资源的的地址。
WebPlugin.stylePublicPath 中设置 CSS 文件的地址。
设置好 publicPath 后,WebPlugin 在生成 HTML 文件和 css-loader 转换 CSS 代码时,会考虑到配置中的 publicPath,用对应的线上地址替换原来的相对地址。
*/
参考
DNS MDN]
webpack 文档
深入浅出 Webpack
Scope Hoisting
IOS下的webview页面,内嵌iframe元素,将其样式指定为宽高100%:
.iframe { width: 100%; height: 100%;
}
在安卓下运行均无问题,但是在IOS下会出现异常。
具体表现为iframe页面内的子元素一旦超出原先的边界,只要能影响到html元素的宽高,就会自动撑开iframe,即使html元素设置了overflow:hidden
也没用。
比如一个body元素下的弹层需要从下往上滑动进场,这个弹层的位置就会导致html高度的变化,因此页面底部的tabbar就会在弹层运动期间先消失再出现。
解决方法就是使用具体的宽高数值锁定iframe元素:
function onLoadIFrame (index) { // 修复IOS下轮播图初始化瞬间会让iframe宽度自行扩大问题 if (this.ENV.isIOS) { const iframe = this.$el.querySelector('#iframe' + index)
iframe.style.width = iframe.clientWidth + 'px' iframe.style.height = iframe.clientHeight + 'px' }
}
在了解了javascript的语言基础和特性后
javascript真正大放光彩的地方来了——这就是javascript DOM
Javascript DOM
DOM(Document Object Model),文档对象模型。
是W3C组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口;W3C已经定义了一系列DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式。
简单的说就是一套操作文档内容的方法。
需要注意的是,我们需要把DOM当作一个整体,不能分割看待,即DOM(文档对象模型)是一套操作文档内容的方法。
DOM把以上内容看作都是对象
<!DOCTYPE html> <html> <head> <title>Shopping list</title> <meta charset="utf-8"> </head> <body> <h1>What to buy</h1> <p id="buy" title="a gentle reminder">Don't forget to buy this stuff</p> <ul id="purchases"> <li>A tin od beans</li> <li>Cheese</li> <li>Milk</li> </ul> </body> </html>
1、获取DOM四种基本方法
1、getElementById()
2、getElementsByTagname()
3、getAttribute()
4、setAttribute()
常用的两种解析:
1. getElementById():
参数:元素的ID值。 (元素节点简称元素)
返回值:一个有指定ID的元素对象(元素是对象)
注:这个方法是与document对象相关联,只能由document对象调用。
用法:document.getElementById(Id)
例:
<!DOCTYPE html> <html lang="zh"> <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> </head> <body> <div id="time">2020-04-16</div> <script> // 1. 因为我们文档页面从上往下加载,所以先得有标签 所以我们script写到标签的下面 // 2. get 获得 element 元素 by 通过 驼峰命名法 // 3. 参数 id是大小写敏感的字符串 // 4. 返回的是一个元素对象 var timer = document.getElementById('time'); console.log(timer); console.log(typeof timer); // 5. console.dir 打印我们返回的元素对象 更好的查看里面的属性和方法 console.dir(timer); </script> </body> </html>
看一下控制台打印的是什么
可以看到 console.log(timer)打印出来的是整个div标签
timer类型是个对象
2. getElementsByTagName():
参数:元素名
返回值:一个对象数组。这个数组里每个元素都是对象,每个对象分别对应着文档里给定标签的一个元素。
注:这个方法可和一般元素关联。这个方法允许我们把通配符当作它的参数,返回在某份html文档里总共有多少个元素节点。
用法:element.getElementsByTagName(TagName)
例:
var items=document.getElementsByTagName("li");
items.length;//3
document.getElementsByTagName(“*”);//12
2、事件基础
3.1 事件概述
JavaScript使我们有能力创建动态页面,而事件是可以被JavaScript侦测到的行为。
简单理解:触发——>响应机制
网页中每个元素都可以产生某些可以触发JavaScript的事件,例如,我们可以在用户点击某按钮产生一个事件,然后去执行某些操作
3.2 事件三要素
事件源 、事件类型、事件处理程序,我们也称为事件三要素
(1) 事件源 事件被触发的对象 谁
(2) 事件类型 如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下
(3) 事件处理程序 通过一个函数赋值的方式 完成
代码实例
<!DOCTYPE html> <html lang="zh"> <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> </head> <body> <button id="btn">唐伯虎</button> <script> // 点击一个按钮,弹出对话框 // 1. 事件是有三部分组成 事件源 事件类型 事件处理程序 我们也称为事件三要素 //(1) 事件源 事件被触发的对象 谁 按钮 var btn = document.getElementById('btn'); //(2) 事件类型 如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下 //(3) 事件处理程序 通过一个函数赋值的方式 完成 btn.onclick = function() { alert('点秋香'); } </script> </body> </html>
运行结果
1、获取事件源
2、注册事件(绑定事件)
3、添加事件处理程序(采取函数赋值形式)
代码实战
-
<!DOCTYPE html> <html lang="zh"> <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> </head> <body> <div>123</div> <script> // 执行事件步骤 // 点击div 控制台输出 我被选中了 // 1. 获取事件源 var div = document.querySelector('div'); // 2.绑定事件 注册事件 // div.onclick // 3.添加事件处理程序 div.onclick = function() { console.log('我被选中了'); } </script> </body> </html>
常用的DOM事件
onclick事件---当用户点击时执行
onload事件---当用户进入时执行
onunload事件---用用户离开时执行
onmouseover事件---当用户鼠标指针移入时执行
onmouseout事件---当用户鼠标指针移出时执行
onmousedown事件---当用户鼠标摁下时执行
onmouseup事件---当用户鼠标松开时执行
————————————————
版权声明:本文为CSDN博主「那是我呐」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42402867/article/details/105567787
文章目录
继承性的描述:
继承性是指被包在内部的标签将拥有外部标签的样式性,即子元素可以继承父类的属性。
例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div{ color: blue; } </style> </head> <body> <div>父元素 <div>子元素 <p>我依旧是子元素</p> </div> </div> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> p{ font-size: 32px; } </style> </head> <body> <p style="color: blue;">我这里体现了层叠性呀</p> </body> </html>
使用结论
由于内容有限,但是结论是一定的,所以我直接给出结论:
若多个选择器定义的样式不冲突,则元素应用所有选择器定义的样式。
若多个选择器定义的样式发生冲突(比如:同时定义了字体颜色属性),则CSS按照选择器的优先级,让元素应用优先级搞得选择器样式。
CSS定义的选择器优先级从高到低为:行内样式–>ID样式–>类样式–>标记样式。
如若想直接定义使用哪个样式,不考虑优先级的话,则使用!important,把这个加在样式后面就行了。
优先级
定义CSS样式时,经常出现两个或更多规则应用在同一个元素上,这时就会出现优先级的问题。层叠性和选择器的圈中有很大的关系。
优先级的使用说明
权重分析:
内联样式:如:style="",权重为1000。
ID选择器,如:#content,权重为100。
类,伪类和属性选择器,如.content,权重为10。
标签选择器和伪元素选择器,如div p,权重为1。
继承样式,权重为0。
将基本选择器的权重相加之和,就是权重大小,值越大,权重越高。
计算权重方法
数标签:先数权重最高的标签,然后数第二高权重的标签,以此类推,就会生成一个数组,里面包含四个数字。
比如(0,0,0,0)分别对应(行内式个数,id选择器个数,类选择器个数,标签选择器个数)
然后两个选择器通过对别四个数字的大小,确定权重关系。
例:
#box ul li a.cur有1个id标签,1个类,3个标签,那么4个0就是(0,1,1,3)
.nav ul .active .cur有0个id,3个类,1个标签,那么4个0就是(0,0,3,1)
例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .p1{ color: blue; } #p1{ color: red; } </style> </head> <body> <p id="p1" class="p1">我们来试一下优先级</p> </body> </html>
先推测一波,因为前面讲到了ID选择器的权重是大于类选择器的,所以这里颜色应该为red。
效果如下:
推测正确!优先级GET!
今天讲一下使用vant Swipe 轮播控件过程中遇到的问题
主要是使用swiper自定义的大小的时候,宽度适应不同分辨率的移动设备
适应宽度的同时还需控件的正常使用
先看一下需要实现的功能,
一个简单的轮播图,但是每个轮播的宽度需要低于100%,使第二个轮播的van-swipe-item可以展示到第一个位置一部分
这时我们再去vant的文档查看一下控件
刚好有一个自定义控件大小的可以使用,完美解决了我们的问题
当我们使用控件之后
<van-swipe :loop="false" @change="onChange" :width="350"> <van-swipe-item v-bind:id="item0"><div class="swipe0"> <div class="contion"> <p class="title">家中有事,申请请假一天</p> <p class="title1"><span class="rice"></span>部门经理核审中</p> <p class="time">03.8 14.25</p> <p class="type">放假申请</p> </div> <img src="../../assets/images/index/xx/fangjia.png"> </div></van-swipe-item> <van-swipe-item ><div class="swipe1"></div></van-swipe-item> <van-swipe-item ><div class="swipe2"></div></van-swipe-item> <template #indicator> <div class="custom-indicator"> {{ current + 1 }}/3 </div> </template> </van-swipe>
发现功能可以使用,但是再 iPhone8/7 plus 以及iPhone5/se 等分辨率下出现了宽度固定而不适应的情况,
简单来说,我们把van-swipe-item宽度控制在了80% 第二个van-swipe-item自然可以展示出来一部分
但是当滑到第二页的时候 由于第一页的宽度还是80% 所以就出现了这样的情况,所以我打算采用
动态的改变 滑动到第几页的时候 把当页的宽度变为80% 其他页保持不变,
于是
<van-swipe :loop="false" @change="onChange" > <van-swipe-item v-bind:id="item0"><div class="swipe0"> <div class="contion"> <p class="title">家中有事,申请请假一天</p> <p class="title1"><span class="rice"></span>部门经理核审中</p> <p class="time">03.8 14.25</p> <p class="type">放假申请</p> </div> <img src="../../assets/images/index/xx/fangjia.png"> </div></van-swipe-item> <van-swipe-item v-bind:id="item1"><div class="swipe1"></div></van-swipe-item> <van-swipe-item v-bind:id="item2"><div class="swipe2"></div></van-swipe-item> <template #indicator> <div class="custom-indicator"> {{ current + 1 }}/3 </div> </template> </van-swipe>
首先 我们为每个swipe-item添加id
data(){ return { android: true, ios: true, iphoneX: true, current: 0, item0:'item0', item1:'item1', item2:'item2', } }, mounted(){ }, methods: { onChange(index){ console.log('当前 Swipe 索引:' + index); if(index==1){ var div =document.getElementById("item0").style.setProperty('width', '10rem', 'important'); var div1 =document.getElementById("item1").style.setProperty('width', '9.3333333rem', 'important'); var div2 =document.getElementById("item2").style.setProperty('width', '9.3333333rem', 'important'); } else if(index==2){ var div1 =document.getElementById("item1").style.setProperty('width', '10rem', 'important'); var div0 =document.getElementById("item0").style.setProperty('width', '10rem', 'important'); var div2 =document.getElementById("item2").style.setProperty('width', '9.3333333rem', 'important'); } else if(index==0){ var div =document.getElementById("item2"); var div0 =document.getElementById("item0").style.setProperty('width', '9.3333333rem', 'important'); var div1 =document.getElementById("item1").style.setProperty('width', '9.3333333rem', 'important'); } },
此外,监听滑动事件,根据滑动到第几页 更改当前页面的宽度,
这样就解决了
兰兰设计:前端达人
用户体验是用户在使用产品或者服务中的所有的主观感受。因此我们设计的过程中要以用户为中心进行设计,不能单单为了设计一个产品而设计,只关注产品设计本身的功能性。
在生活中好的用户体验设计的产品让人使用舒适,而用户体验不好的设计往往让人很糟糕。
用户体验比较好的:比如我们坐地铁的过程中很准时,这就是好的用户体验;在吃海底捞时,看到好吃的西瓜,他们会给你打包,这就是好的用户体验。
用户体验比较不好的设计:比如在生活中有些插座设计,一个两孔一个三孔,只能一次插一个,很气人有没有,难道上下错位和间距拉大有这么难吗?再比如蚊香的设计,很容易断,每到夏天不断几个,都不好意思!
在产品设计中是否满足用户需求我们可以分为 3 个点来进行分析,主要是有用性;易用性;满意度。
有用性就是产品有用的设计功能,也是产品基础的设计原则。
对于有用性而言,我们在这个过程可以主要在三个方向进行把控,就是:基本需求;期望需求;兴奋需求。
基本型需求
基本型需求是用户必需需求,用户在产品中认为这是必需的功能,(这些基本需求是用户认为必备的,有了用户觉得是应该的,如果没有这些需求,那么用户在使用产品过程中间大部分会直接放弃,选择其他家产品)。
比如淘宝产品中的订单和商品功能就是基本型需求;微信中的聊天和通讯录就是基本型需求;QQ 音乐中的播放页、播放菜单就是基本需求。
期望型需求
基本型需求是用户意愿型需求,用户自己也不知道,但是期望获得的功能。(这类需求就没有基本需求那样必备,是产品中期望需求体验越多越好,用户越满意,反之用户满意度也会下降)。
这类需求是期望型需求,也是我们产品竞争力所在,因此往往人们在谈论哪个产品好不好,通常是期望需求和兴奋型需求。比如淘宝产品中能买到便宜产品,而且符合详情页中描述;比如微信产品中聊天语音/微信/视频,聊天更加方便;比如 qq 音乐中的曲目和歌单数量增加,用户就会很满意,这也是期望需求。
兴奋型需求
兴奋型需求是用户非常期望的需求。(这类需求满意度高,有这些兴奋型需求时即使不太完善,用户也会满意,做得非常好就会让用户兴奋;没有这些需求用户也不会表现得不满意)。
比如淘宝产品能够更多满足用户多样化的生活,各种生活服务提供给用户;商品评价页用户互动,方便用户可以熟悉产品好坏;比如微信产品中暗黑模式,满意希望黑暗模式体验的用户需求;比如 qq 音乐中单曲热评,让我们对歌曲背后的故事,歌友的心路有了了解互动。
此外兴奋性需求在产品中还有一些重要的点,比如微动效、情感化设计等等这些都可以让产品提升很大的用户体验,和宣传力度,因为用户在谈论产品好坏时候比较多的是说产品的兴奋型需求。
需求分析模型
需求分析工具 KANO 模型,主要是帮助我们直观的了解产品不用类型需求实现程度和用户满意度的对比,我们了解这些需求的时候,可以让我们更好的看到这些功能点有哪些影响力。
易用性就是产品好不好用,容易使用吗。同时我觉得在有用性上产品经理需要考虑得比较多一点,而易用性上就是我们 UI、UE 需要重点负责和掌握的东西。
对于易用性而言,我们可以主要在三个方向进行把控,就是:上手快 ;操作快;负担少。
上手快
上手快就是用户使用产品容易上手,没有啥学习成本。简单的意思就是让用户不怎么动脑去想就知道下一步我要做什么,用户操作满足自己的心智模型。
心智模式是指深植我们心中关于我们自己、别人、组织及周围世界每个层面的假设、形象和故事。并深受习惯思维、定势思维、已有知识的局限。简单理解就是在使用产品中满足我们对产品的认知思维。当然文中介绍的只是心智模型的很一小部分,主要是想让大家多去了解心智模型,更好地在以后的产品设计中运用它们。
比如淘宝的下单弹窗、微信的红包、QQ 音乐的音乐播放,都是用户容易上手,即使小白用户在使用时,根据它们简单的提示就可以操作,没有太多复杂选项,一目了然。
操作便捷
操作便捷就是用户在使用产品中操作效率高,没有太多干扰项目。(这类设计一般就是操作方便,尽可能地减少干扰项目,增加快捷入口等)。
比如淘宝产品中的物流信息,没有太多干扰直接出现在订单的头部位置,提高用户查看商品物流信息的操作效率,提升了用户体验。比如微信聊天中的发送图片功能,直接显示最近图片,快捷发送,提高用户发送图片的操作效率。比如 QQ 音乐的播放直接在首页出现,方便用户选歌切换,操作效率高。
负担少
负担少通常是减少记忆负担,不让用户累着,为用户分忧。
比如淘宝红包展示就是在我的页面里面直接显示;比如微信钱包余额直接在钱包按钮下方显示,不用进入三级页面;比如 qq 音乐自建歌单显示歌单数量,减少用户记忆负担。
满意度简单理解就是用户需求被满足后的愉悦感。它是相对的概念,就是用户需求和产品完成度之间的衡量。
对于满意度而言,在产品设计上有很多方面,今天我们简单讲一下两个方向的把控:视觉感官的刺激;奖励。
视觉感官刺激
视觉感官刺激主要是超乎用户想象的好看的视觉。而在 UI 设计中主要体现在动效设计、插画等等。
比如淘宝产品中的图标动效,趣味设计,提升用户对产品的情感交流。比如微信聊天中的表情包功能,简单的动作表达用户的心理,好看又好玩。比如 QQ 音乐的加载像音符一样有韵律地跳动着,给用户带来不一样的审美体验。
奖励
奖励是指用户在完成一些操作时给予奖励的设计。超出用户预期,带来愉悦。
比如淘宝用户每次下单/参加活动获得淘气值,满 1000 可以购买 88 会员,原件 888。比如 QQ 音乐的活动中心,用户每日签到累计可以获得会员体验奖励,更优质内容的声音享受激励。
用户体验设计最根本的就是以用户为中心进行设计,本文主要从有用性、易用性、满意度三个维度来把控用户体验设计,但是在日常工作中,因为产品业务的复杂程度,我们要因地制宜地进行设计,深入挖掘我们产品自己的体验设计特色,增加自己的设计市场竞争力。
文章来源:优设 作者:阿韩设计
在这篇文章中,我们将讨论原型以及如何在 JS 中使用它们进行继承。我们还将会看到原型方法与基于类的继承有何不同。
继承
继承是编程语言的一个显著特征,随着面向对象编程语言的引入而出现。这些语言大多是基于类的语言。在这里,类就像一个蓝图,对象是它的展现形式。就是说,要创建一个对象,首先我们必须创建一个类,然后我们可以从一个类创建任意数量的对象。
想象一下,我们有一个表示智能手机的类。这个类具有像其他智能手机一样的可以拍照、有GPS定位等功能。下面是使用 c++ 来描述这样的一个类:
class SmartPhone {
public:
void captureImages() {}
}
SmartPhone x;
x.captureImages()
我们创建了一个名为SmartPhone的类,它有一个名为capturePictures的方法用来拍照。
如果我们需要一个iPhone类,它可以捕捉图像和一些特殊的功能,比如面部ID扫描。下面是两种可能的解决方案:
1.将捕获图像功能与其他常见的智能手机功能,以及iPhone的特定功能一起重写到一个新类中。但是这种方法需要更多的时间和精力,并且会引入更多的bug。
重用SmartPhone类中的功能,这就是继承的作用,继承也是重用其他类/对象中功能的一种方式。
这里是我们如何从SmartPhone类中继承capturePictures方法,使用 c++ 实现如下:
class Iphone: public SmartPhone {
public:
void faceIDScan() {}
}
Iphone x
x.faceIDScan()
x.captureImages()
上面是一个简单的继承示例。 但是,它表明继承可以使我们以某种方式重用代码,从而使所生成的程序更不易出错,并且花费更少的时间进行开发。
以下是关于类的一些重要信息:
继承该功能的类称为子类
被继承的类称为父类
一个类可以同时从多个类中继承
我们可以具有多个继承级别。 例如,类C继承自类B,而类B继承自类A
值得注意的是,类本身并没有做任何事情。在从类创建对象之前,实际上没有完成任何工作。我们将看到它为什么不同于JavaScript。
大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】。
原型是什么?
在 JS 中,所有对象都有一个特殊的内部属性,该属性基本上是对另一个对象的引用。 此引用取决于对象的创建方式。 在 ECMAScript/JavaScript规范中,它表示为[[Prototype]]。
由于[[Prototype]]链接到一个对象,所以该对象有自己的[[Prototype]]引用。这就是建立原型链的方式。
这个[[Prototype]]链是 JS 中继承的构建块。
__proto__ 对象
为了访问对象的[[Prototype]],大多数浏览器都提供__proto__属性。访问方式如下:
obj.__proto__
需要注意的是,这个属性不是 ECMAScript 标准的一部分,它实际上是由浏览器实现的。
获取和设置原型方法
除了__proto__属性外,还有一种访问[[Prototype]]的标准方法:
Object.getPrototypeOf(obj);
对应的有个类似的方法来设置对象的[[Prototype]]:
Object.setPrototypeOf(obj, prototype);
[[Prototype]]和.prototype属性
[[Prototype]] 只不过是一种用来表示物体原型的标准符号。 许多开发人员将其与.prototype属性混淆,这是完全不同的事情,接着我们来研究一下.prototype属性。
在 JS 中,有许多创建对象的方法。一种方法是使用构造函数,像这样使用new关键字来调用它:
function SmartPhone(os) {
this.os = os
}
let phone = new SmartPhone('Android')
在控制台打印 phone 对象:
{
os: "IPhone"
__proto__{
constructor: ƒ SmartPhone(os)
__proto__: Object
}
}
现在,如果我们希望在phone对象上有一些方法,我们可以在函数上使用.prototype属性,如下所示:
SmartPhone.prototype.isAndroid = function () {
return this.os === 'Android' || 'android'
}
再次创建phone对象时,打印 phone 对象如下:
{
os: "Android"
__proto__{
isAndroid: ƒ()
constructor: ƒ SmartPhone(os)
__proto__: Object
}
}
我们可以在对象的[[Prototype]]中看到isAndroid()方法。
简而言之,.prototype属性基本上就像由给定的构造函数创建的[[Prototype]]对象的蓝图。 在.prototype属性/对象中声明的所有内容都会在对象的[[Prototype]]中弹出。
实上,如果将 SmartPhone.prototype 与phone 的[[Prototype]]进行比较,就会发现它们是相同的:
console.log(Object.getPrototypeOf(phone) === SmartPhone.prototype);
// true
值得注意的是,我们还可以在构造函数中创建方法:
function ObjectA() {
this.methodA = function () {}
}
let firstObj = new ObjectA()
console.log(firstObj)
这种方法的问题是当我们初始化一个新对象时。所有实例都有自己methodA的副本。相反,当我们在函数的原型上创建它时,对象的所有实例只共享方法的一个副本,显然使用原型的方式效率会过高。
大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】。
当我们访问属性时这里发生了什么?
当我们访问一个属性以获取它时,会发生以下情况:
JS 引擎查找对象上的属性,如果找到了该属性,然后返回它。否则,JS 引擎将通过查看[[Prototype]]来检查对象的继承属性,如果找到该属性,则返回它,否则,它会查找 [[Prototype]]的[[Prototype]]。 找到属性或没有[[Prototype]]时,该链结束,这意味着我们已经到达原型链的末端。
当我们设置/创建属性时,JS 总是在对象本身上进行设置。 即使[[Prototype]]链上存在相同的属性,下面是一个例子:
function MyObject() {}
MyObject.prototype.propA = 10; // 在原型上创建属性
let myObject = new MyObject();
console.log(myObject.propA); // [[Prototype]]上的属性
// 10
myObject.propA = 20; // 对象的属性
console.log(myObject.propA);
// 20
在上面的示例中,我们创建了一个构造函数,该函数的[[Prototype]]上具有属性propA。 当我们尝试对其进行读取操作时,会在控制台中看到该值。 但是,当我们尝试在对象本身上设置相同的属性时;JS 使用给定值在对象上创建一个新属性。 现在,如果我们不能直接访问[[Prototype]]上的属性。
值得注意的是,普通对象的[[Prototype]]链的末尾是内置的Object.prototype。 这就是为什么大多数对象共享许多方法(例如toString())的原因。 因为它们实际上是在Object.prototype上定义的。
使用原型继承的各种方法
在 JS 中,无论我们如何创建对象,只有原型继承,但这些方式还有一些区别,来看看:
对象字面量
在JavaScript中创建对象的最简单方法是使用对象字面量:
let obj = {}
如果在浏览器的控制台中打印obj,我们将看到以下内容:
clipboard.png
基本上,所有用文字面量创建的对象都继承了Object.prototype的属性。
需要注意的是__proto__对象引用了创建它的构造函数。 在这种情况下,constructor属性指向Object构造函数。
使用对象构造函数
另一种不太常见的创建对象的方法是使用对象构造函数。JS 提供了一个名为Object的内置构造函数方法来创建对象。
let obj = new Object();
这种方法的结果与对象字面量的方式相同。它从Object.prototype继承属性。因为我们使用Object作为构造函数。
Object.create 方法
使用此辅助方法,我们可以创建一个带有[[Prototype]]的对象,如下所示:
let SmartPhone = {
captureImages: function() {}
}
let Iphone = Object.create(SmartPhone)
Iphone.captureImages()
这是在 JS 中使用继承的最简单方法之一。猜猜我们如何在没有任何[[Prototype]]引用的情况下创建对象?
构造方法
与 JS 运行时提供的对象构造函数相似。 我们还可以创建自己的构造函数,以创建适合我们需求的对象,如下所示:
function SmartPhone(os) {
this.os = os;
}
SmartPhone.prototype.isAndroid = function() {
return this.os === 'Android';
};
SmartPhone.prototype.isIOS = function() {
return this.os === 'iOS';
};
现在,我们想创建一个iPhone类,它应该有'iOS'作为它 os 属性的值。它还应该有faceIDScan方法。
首先,我们必须创建一个Iphone构造函数,在其中,我们应该调用SmartPhone构造函数,如下所示:
function Iphone() {
SmartPhone.call(this, 'iOS');
}
这会将Iphone构造函数中的this.os属性设置为’iOS‘。
之所以调用SmartPhone.call方法,是因为我们需要更改 this 值以引用Iphone。 这类似于在面向对象的世界中调用父级的构造函数。
接下来的事情是,我们必须从SmartPhone构造函数继承方法。 我们可以在此处使用Object.create朋友,如下所示:
Iphone.prototype = Object.create(SmartPhone.prototype);
现在,我们可以使用.prototype为Iphone添加方法,如下所示:
Iphone.prototype.faceIDScan = function() {};
最后,我们可以使用Iphone创建一个对象,如下所示:
let x = new Iphone();
// calling inherited method
console.log(x.isIOS()):
// true
ES6 class
使用ES6,整个过程非常简单。 我们可以创建类(它们与C ++或其他任何基于类的语言中的类不同,只是在原型继承之上的语法糖),然后从其他类派生新的类。
下面是我们如何在ES6中创建类:
class SmartPhone {
constructor(os) {
this.os = os;
}
isAndroid() {
return this.os === 'Android';
}
isIos() {
return this.os === 'iOS';
}
};
现在,我们可以创建一个派生自SmartPhone的新类,如下所示:
class Iphone extends SmartPhone {
constructor() {
super.call('iOS');
}
faceIDScan() {}
}
我们不是调用SmartPhone.call,而是调用super.call。 在内部,JavaScript引擎会自动为我们执行此操作。
最后,我们可以使用Iphone创建一个对象,如下所示
let x = new Iphone();
x.faceIDScan();
// calling inherited method
console.log(x.isIos()):
// true
该ES6示例与先前的构造方法示例相同。 但是阅读和理解起来要干净得多。
原文:https://javascript.info/proto...
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
自己写了段jquery的ajax请求,并输出到页面的表格中
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>jQuery实现JSONP</title> </head> <body> <div id="mydiv"> <button id="btn">点击</button> <div id="container"> <!--每个条目--> <div class="item"> <div class="item-title">作业名字</div> <div> <span class="item-content">创建时间</span> <span class="item-content">发布老师</span> </div> </div> </div> </div> </body> <script type="text/javascript" src="https://code.jquery.com/jquery-3.1.0.min.js"></script> <script type="text/javascript"> $(function(){ $("#btn").click(function(){ $.ajax({ async : true, url : "xxxxxxxxxxx", type : "GET", dataType : "json", // 返回的数据类型,设置为JSONP方式 jsonp : 'callback', //指定一个查询参数名称来覆盖默认的 jsonp 回调参数名 callback jsonpCallback: 'handleResponse', //设置回调函数名 data : { q : "javascript", count : 1, city:'北京' }, success: function(response, status, xhr){ // console.log('状态为:' + status + ',状态是:' + xhr.statusText); // console.log(response); var group = response.hourly_forecast; console.log(group,111111111) console.log(group.length,222222222222) //拼接字符串 var str = ''; //对数据做遍历,拼接到页面显示 for(var i=0;i<group.length;i++){ str += '<div class="item">'+ '<div class="item-title">'+ group[i].date +'</div>'+ '<div>'+ '<span class="item-content">'+ group[i].hum +'</span>'+ '<span class="item-content">'+ group[i].pop +'</span>'+ '</div>'+ '</div>'; } //放入页面的容器显示 $('#container').html(str); } }); }); }); function handleResponse(response){ // 对response数据进行操作代码 alert("jsonp success!"); } </script> </html>
一、处理跨域的方式:
1.代理
2.XHR2
HTML5中提供的XMLHTTPREQUEST Level2(及XHR2)已经实现了跨域访问。但ie10以下不支持
只需要在服务端填上响应头:
header("Access-Control-Allow-Origin:*"); /*星号表示所有的域都可以接受,*/ header("Access-Control-Allow-Methods:GET,POST");
3.jsonP
原理:
ajax本身是不可以跨域的, 通过产生一个script标签来实现跨域。因为script标签的src属性是没有跨域的限制的。
其实设置了dataType: 'jsonp'后,$.ajax方法就和ajax XmlHttpRequest没什么关系了,取而代之的则是JSONP协议。JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问。
ajax的跨域写法:
(其余写法和不跨域的一样):
比如
在很多设计作品中,我们不难发现对于材质的运用是十分广泛的,合理地运用材质可以很大程度地提升作品的质感、细节感!但是相反,如果使用不得当它也可以毁掉一个原本不错的作品,很多人对于材质的理解存在着一定局限性,那么本期内容:设计中材质有哪些运用形式?应该如何合理地运用材质?
很多人对于材质并不陌生,但是每次使用后最终结果总是差强人意,这里首先要说的就是材质运用的几个常见误区:
那么应该如何合理地运用材质呢?
在日常工作中,背景添加材质、肌理的手法是很常用的,但是表现手法上也是有所不同的,表现形式一:将材质、肌理作为背景形象的一部分,也就是将材质做得足够明显,这么做的目的是丰富画面视觉层次变化,增强画面整体对比,比如我们常见的:
通过对比不难发现有无材质对于整体的影响,同样的构图,没有材质变化的画面给人一种很单薄、视觉形象不够鲜明的感觉,但是通过添加材质、肌理,画面整体的丰富度大大提升,背景画面的变化增强,通过材质的变化,也使得主体的视觉形象也更加鲜明;将材质作为背景的组成部分,一定要切记时刻围绕主体展开,主体的位置是不可撼动的。
表现形式二:将材质、肌理作为画面视觉中相对较弱的表现形式,也就是做得不明显,缩小看几乎没有,正常看的情况下又有一定的变化,这种表现形式目的在于增加画面细节感,使得画面不会因为缺少变化而略显单调,比如:
这种表现手法放小了看对于画面的影响并不大,但是如果 1:1 正常比例看,有材质的画面会给人一种细节感丰富、画面充满不同层次的变化感受,这样带给作品更多的可塑性,使得画面给人的视觉感受更深刻,同时也起到了一定的丰富画面的作用。
对于在文字中叠加材质在一些作品中是很常见的,同样的文字,给予不同的材质也会呈现出不同的视觉感受,更多的目的是提升文字与整体形象的契合度,增强整体视觉冲击力,比如:
材质在很大程度上可以提升文字的立体形象,使得文字在整体的视觉形象更加鲜明,但是对于材质的运用也要做到有所选择,每种材质所传递的视觉信息都有所不同,要让材质与文案、主题相契合才能将材质的效果发挥得淋淋尽致,这一点很重要,比如:
这里只考虑材质对文字的影响,首先我们解读文字「第一战场」,让我们首先联想到的就是破损、狼藉、金属等等,那么在给这一文字添加材质时我们就要结合主题;上面两种的材质分别是木纹和大理石,给人的感觉是太过干净、简约,与战场主题不相符,所以说材质使用不得当,而后面两个的材质分别是破损的石灰墙以及金属,就能在很大程度上加强「战场」这一主题的视觉形象,在视觉上属于强调的作用。
材质的选择和使用也是有一定技巧可言的,这里首先要说下:当我们想要使用材质时,应该如何选择呢?
结合整体风格选择,比如画面整体偏简约、干净的感觉,我们就可以尝试:大理石、木纹、石灰墙、花纹、木纹等等;再比如想要炫酷效果,那么我们就可以尝试:金属、破损墙壁、石头等等,也就是说尽可能让材质本身的风格偏向画面整体风格,这样可以让材质更加融合画面,不会给人一种很突兀、刻意的感觉。
结合产品选择,一切的手法、技巧都是要服务于产品、主体的,结合产品选择材质也是很常用的;比如一些化妆品海报,我们可能用到的材质会有:水、植物、大理石、木纹或者产品本身所固有的材质等等,目的是凸显产品的美观、功效,让用户能够在背景及产品之间产生共鸣、联想,这样也能起到对产品的强调辅助作用。
关于使用:通常找到合适的材质后,会锐化一下,目的是增强材质的质感,然后会用不同的图层模式去试,(一般情况下会用「正片叠底、滤色、叠加、柔光的模式」)以便找到最佳的使用形式;当然如果只用材质的纹理感觉,不用材质本身颜色的话,也可以去色后再去选择图层模式。
结合本期内容,做了一个简单的化妆品的海报,充分利用材质的不同表现形式,用分析的角度去观察,第一步,通过运用 C4D 软件,做一个简易场景:
简易场景搭建完成,因为只是黑白稿的场景,那么接下来就要通过分析产品确定材质的选择:
产品的感觉是干净、简约的,那么就围绕这个整体感觉,展开材质的贴合及制作,这里我选择纹理相对不复杂的大理石为主要材质,结合用到木纹、金属作为丰富画面的材质:
这样一个画面给人的感觉是轻飘飘的,因为没有影子,没有将画面做出光感的效果,而且整体缺少色感,这里我选择把原本无色的材质换成有色材质,目的是增加画面整体色感,其次将投影、倒影做好,光源定在左侧,最终呈现的效果:
最终的呈现几乎是用不同材质做出来的一个场景,虽然这里用到了很多不同颜色的材质,但是最终用到的材质属性只有三种:大理石、木纹 、金属,而且依旧贯彻干净、简约的视觉感受,将同种材质的不同形态运用在一起会给人视觉联系的作用,不会给人一种杂乱的感觉!
材质对画面是辅助、丰富、增加细节感的作用,合理地运用材质可以提升设计作品的视觉层次、增强画面质感!但是不管是哪种形式的材质,都要做到切合主题,要让设计的每个元素做到有理有据,切记不要因为材质的过于凸显而抢了主体。
文章来源:优设 作者:
大家平常都习惯去哪些免费图库网站找图呢?虽然有一些老牌、图片数量充足的图库,像是 Unsplash、Pixabay、Pexels,但后来经过人工智能和大数据学习的搜寻工具更深得我心,也能通过算法将质量较低、不适合使用的图库图片先排除掉,大幅节省搜寻时间。如果在寻找图片素材时想尽量避免使用和其他人重复的内容,试试看由摄影师亲自拍摄的小型图库或许是个不错的方法。
往期回顾:
本文要介绍的「DesignersPics」是一个持续更新、每个月都会加入新相片的图库,由摄影师 Jeshu John 亲自拍摄修图,收录各种类型的相片,包括建筑、商业活动、概念、美食和饮料、大自然、人物、科技等等,照片数量不多,但有一定的独特性。
DesignersPics 的相片都具有非常高的分辨率和画质,可自由下载用于个人或商业用途,例如网站、投影片、包装、标签、HTML/PSD 模版、T-Shirts、广告横幅、商店或办公室装饰等等,无需标示出处来源。
网站链接:http://www.designerspics.com/
使用教学
开启 DesignersPics 从右上角的「Categories」选择要浏览的相片分类,或是直接从首页以日期方式浏览,网站亦提供搜寻功能,不过图库本身相片量不多,浏览上不会耗费太多时间。
每张相片会有预览图、标题和免费下载的按钮。
进入图片页面,还能看到图片尺寸、大小等等信息,点选「Download」就能下载取得 .jpg 格式的图片文件。虽然 DesignersPics 没有硬性规定必须标示作者来源,但如果你喜欢可以协助推广。
值得一试的三个理由:
文章来源:优设 作者:Pseric
蓝蓝设计的小编 http://www.lanlanwork.com