ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值
如果解构不成功,变量的值就等于undefined
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错、
交换变量的值
例如:let x=1,y=2;[x,y] = [y,x]
从函数返回多个值
函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便
函数参数的定义
解构赋值可以方便地将一组参数与变量名对应起来
提取 JSON 数据,很多接口数据只需要其中某部分
例如aa.axios.get(res=>{let {data:result}=res;}),则res.data.result = result了
函数参数的默认值
指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || ‘default foo’;这样的语句
遍历 Map 结构
Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便
输入模块的指定方法
加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。* const { SourceMapConsumer, SourceNode } = require(“source-map”);
左右两侧数据解构须得吻合,或者等号左边的模式,只匹配一部分的等号右边的数组(属于不完全解构)
特殊情况使用…扩展运算符,无值是空数组
左右两边等式的性质要相同,等号的右边不是数组(或者严格地说,不是可遍历的结构),那么将会报错,只要某种数据结构具有 Iterator
接口,都可以采用数组形式的解构赋值,例如Set结构
解构赋值允许指定默认值,当一个数组成员严格等于undefined,默认值才会生效,否则取赋值的值;如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值;默认值可以引用解构赋值的其他变量,但该变量必须已经声明
// 数组的解构赋值 let [a,b] = [1,2]; console.log([a,b],a);//[1, 2] 1 let [aa] = [11,22]; console.log(aa)//11 let [aaa,bbb] = [111]; console.log(aaa,bbb)//111 undefined let [head, ...tail] = [1, 2, 3, 4]; console.log(head,tail)//1,[2,3,4] let [x, y, ...z] = ['a']; console.log(x,y,z)//a undefined [] // 等号右边不是数组会报错 // let [ab] = 121; // conosle.log(ab)//TypeError: 121 is not iterable // let [abc] = {} // conosle.log(abc)//TypeError: {} is not iterable // 默认值赋值 let [zz = 1] = [undefined]; console.log(zz)//1 let [zzz = 1] = [null]; console.log(zzz)//null let [foo = true] = []; console.log(foo)// true let [xxx, yyy = 'b'] = ['a']; console.log(xxx,yyy)//a,b let [xxxx, yyyy = 'b'] = ['a', undefined]; console.log(xxxx,yyyy)//a,b function f() { console.log('aaa'); } let [xx = f()] = [1]; console.log(xx)//1 let [qq=ww,ww=11] = [23,44]; console.log(qq,ww)//23,44,因为ww申明比qq晚所以是undefined;
2、对象的解构赋值
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者
数组是按照位置区分,对象则是按照键名区分的,同样的解构失败则为undefine
可将已有方法对象解构赋值
嵌套赋值,注意是变量是否被赋值是模式还是键值
对象的解构赋值可以取到继承的属性
如果要将一个已经声明的变量用于解构赋值,必须非常小心
let xx; // {xx} = {xx: 1}这样会报错,
解构赋值允许等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式
({} = [true, false]);//可执行
由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构
objFuc(){ // 对象解构赋值 let {b,a} = {a:1} console.log(a,b)//1 undefined // 已有对象解构赋值 let { sin, cos } = Math;//将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上 console.log(sin);//log() { [native code] } const { log } = console; log('hello') // hello // let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; console.log(baz);//aaa // 嵌套赋值 let obj = { p: [ 'Hello', { y: 'World' } ] }; let { p,p:[x, { y }] } = obj; console.log(x,y,p)//Hello World p: ['Hello',{ y: 'World' }] //继承赋值 const obj1 = {}; const obj2 = { foo: 'bar' }; Object.setPrototypeOf(obj1, obj2);//obj1继承obj2 const { foo } = obj1; console.log(foo) // "bar" // 默认值 // 错误的写法 let xx; // {xx} = {xx: 1};// SyntaxError: syntax error,Uncaught SyntaxError: Unexpected token '=' ({xx} = {xx: 1});//正确写法 console.log(xx) // 古怪的,等式左边可为空 // ({} = [true, false]); // 对象可解构数组 let arr = [1, 2, 3]; let {0 : first, [arr.length - 1] : last} = arr; console.log(first,last)//1 3 },
strFuc(){ // str:'yan_yan' let [a,b,c,d,e,f,g] = this.str; console.log(a,b,c,d,e,f,g)//y a n _ y a n // 对数组属性解构赋值 let {length} = this.str; console.log(length)//7 },
4、数值和布尔值的解构赋值
let {toString: s} = 123; console.log(s === Number.prototype.toString,s)//true ƒ toString() { [native code] } let {toString: ss} = true; console.log(ss === Boolean.prototype.toString,ss)// true ƒ toString() { [native code] } // 右侧必须是数组或对象,undefined和null无法转为对象,所以对它们进行解构赋值,都会报错 // let { prop: x } = undefined; // TypeError // let { prop: y } = null; // TypeError
5、函数参数的解构赋值
// 函数的解构赋值可使用默认值,注意默认值是指实参的默认值而不是形参的默认值 function move({x=1, y=1}={}) { return [x, y]; } function move1({x, y} = { x: 0, y: 0 }) { return [x, y]; } function move2({x, y=1} = { x: 0, y: 0 }) { return [x, y]; } console.log(move({x: 3, y: 8})); // [3, 8] console.log(move({x: 3})); // [3, 1] console.log(move({})); // [1, 1] console.log(move()); // [1,1] console.log(move1({x: 3, y: 8})); // [3, 8] console.log(move1({x: 3})); // [3, 1] console.log(move1({})); // [undefined, 1] console.log(move1()); // [0,0] console.log(move2({x: 3, y: 8})); // [3, 8] console.log(move2({x: 3})); // [3, 1] console.log(move2({})); // [undefined, 1] console.log(move2()); // [0,0]
6、圆括号问题 解构赋值虽然很方便,但是解析起来并不容易。对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道。 由此带来的问题是,如果模式中出现圆括号怎么处理。ES6 的规则是,只要有可能导致解构的歧义,就不得使用圆括号。 可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号 总结: 不管是哪一类的解构赋值,等式右边的数据必须是对象形式(数组也是一种对象形式) ———————————————— 版权声明:本文为CSDN博主「Yan_an_n」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_44258964/article/details/105643553
目录
HTTP协议
HTTP请求:
HTTP响应:
会话与会话状态:
Cookie
Session
Cookie和Session的区别
HTTP协议
HTTP请求:
Post /test.php HTTP/1.1 //请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本
Host: www.test.com //请求头
User-agent:mozilla/5.0(windows NT 6.1: rv: 15.0)
Gecko/20100101 firefox15.0
//空白行,代表请求头结束
Username=admin&passwd=admin //请求正文
HTTP请求方法
GET 请求获取Request-URI所标识的资源
POST 在Request-URI所标识的资源后附加新的数据
HEAD 请求获取由Request-URI所标识的资源的响应消息报头
PUT 请求服务器存储一个资源,并用Request-URI作为其标识
常用的为GET和POST;GET和POST的区别:
GET提交的内容会直接显示在URL中,私密性较差,可以用于显示一些公共资源;但是GET效率会比较高。
POST不会将内容显示在URL中,可以用于提交一些敏感数据,例如用户名或密码。
HTTP响应:
HTTP/1.1 200 OK //响应行由协议版本号,响应状态码和文本描述组成
Data:sun,15 nov 2018 11:02:04 GMT //响应头
Server:bfe/1.0.8.9
……
Connection: keep-alive
//空白行,代表响应头结束
<html>
</html><title>index.heml</title> //响应正文
HTTP的状态码:
状态代码由三位数字组成,第一个数字定义了响应的类别,且有五种可能取值。
1xx:指示信息 —— 表示请求已接收,继续处理。
2xx:成功 —— 表示请求已被成功接收、理解、接受。
3xx:重定向 —— 要完成请求必须进行更进一步的操作。
4xx:客户端错误 —— 请求有语法错误或请求无法实现。
5xx:服务器端错误 —— 服务器未能实现合法的请求。
常见状态代码、状态描述的说明如下。
200 OK:客户端请求成功。
400 Bad Request:客户端请求有语法错误,不能被服务器所理解。
401 Unauthorized:请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用。
403 Forbidden:服务器收到请求,但是拒绝提供服务。
404 Not Found:请求资源不存在,举个例子:输入了错误的URL。
500 Internal Server Error:服务器发生不可预期的错误。
503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常。
会话与会话状态:
Web中的会话是指一个客户端浏览器与web服务器之间连续发生一系列请求和响应过程。会话状态是指在会话过程中产生的状态信息;借助会话状态,web服务器能够把属于同一会话中的一系列的请求和响应关联起来。
Cookie
概述
Cookie是一种在客户端保持HTTP状态信息的技术,它好比商场发放的优惠卡。在浏览器访问Web服务器的某个资源时,由Web服务器在在HTTP响应头中附带传送给浏览器一片数据,web服务器传送给各个客户端浏览器的数据是可以各不相同的。
一旦Web浏览器保存了某个Cookie,那么它在以后每次访问该Web服务器是都应在HTTP请求头中将这个Cookie回传个Web服务器。Web服务器通过在HTTP响应消息中增加Set-Cookie响应头字段将CooKie信息发送给浏览器,浏览器则通过在HTTP请求消息中增加Cookie请求头字段将Cookie回传给Web服务器。
一个Cookie只能标识一种信息,它至少含有一个标识该消息的名称(NAME)和和设置值(VALUE)。一个Web浏览器也可以存储多个Web站点提供的Cookie。浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
传送示意图
特点
存储于浏览器头部/传输与HTTP头部,写时带属性,读时无属性。由三元【name,domain,path】唯一确定Cookie。
Set-Cookie2响应头字段
Set-Cookie2头字段用于指定WEB服务器向客户端传送的Cookie内容,但是按照Netscape规范实现Cookie功能的WEB服务器, 使用的是Set-Cookie头字段,两者的语法和作用类似。Set-Cookie2头字段中设置的cookie内容是具有一定格式的字符串,它必须以Cookie的名称和设置值开头,格式为"名称=值”,后面可以加上0个或多个以分号(;) 和空格分隔的其它可选属性,属性格式一般为 "属性名=值”。
除了“名称=值”对必须位于最前面外,其他的可选属性可以任意。Cookie的名称只能由普通的英文ASCII字符组成,浏览器不用关心和理解Cookie的值部分的意义和格式,只要WEB服务器能理解值部分的意义就行。大多数现有的WEB服务器都是采用某种编码方式将值部分的内容编码成可打印的ASCII字符,RFC 2965规范中没有明确限定编码方式。
举例: Set-Cookie2: user-hello; Version=1; Path=/
Cookie请求头字段
Cookie请求头字段中的每个Cookie之间用逗号(,)或分号(;)分隔。在Cookie请求字段中除了必须有“名称=值”的设置外,还可以有Version、path、domain、port等属性;在Version、path、domain、port等属性名之前,都要增加一个“$”字符作为前缀。Version属性只能出现一次,且要位于Cookie请求头字段设置值的最前面,如果需要设置某个Cookie信息的Path、Domain、Port等属性,它们必须位于该Cookie信息的“名称=值”设置之后。
浏览器使用Cookie请求头字段将Cookie信息会送给Web服务器;多个Cookie信息通过一个Cookie请求头字段会送给Web服务器。
浏览器会根据下面几个规则决定是否发送某个Cookie信息:
1、请求主机名是否与某个存储的Cookie的Domain属性匹配
2、请求的端口号是否在该Cookie的Port属性列表中
3、请求的资源路径是否在该Cookie的Path属性指定的目录及子目录中
4、该Cookie的有效期是否已过
Path属性的指向子目录的Cookie排在Path属性指向父目录的Cookie之前
举例: Cookie: $Version=1; Course=Java; $Path=/hello/lesson;Course=vc; $Path=/hello
Cookie的安全属性
secure属性
当设置为true时,表示创建的Cookie会被以安全的形式向服务器传输,也就是只能在HTTPS连接中被浏览器传递到服务器端进行会话验证,如果是HTTP连接则不会传递该信息,所以不会被窃取到Cookie的具体内容。
HttpOnly属性
如果在Cookie中设置了"HttpOnly"属性,那么通过程序(JS脚本、Applet等)将无法读取到Cookie信息,这样能有效的防止XSS攻击。
总结:secure属性 是防止信息在传递的过程中被监听捕获后信息泄漏,HttpOnly属性的目的是防止程序获取cookie后进行攻击这两个属性并不能解决cookie在本机出现的信息泄漏的问题(FireFox的插件FireBug能直接看到cookie的相关信息)。
Session
使用Cookie和附加URL参数都可以将上一-次请求的状态信息传递到下一次请求中,但是如果传递的状态信息较多,将极大降低网络传输效率和增大服务器端程序处理的难度。
概述
Session技术是一种将会话状态保存在服务器端的技术,它可以比喻成是医院发放给病人的病历卡和医院为每个病人保留的病历档案的结合方式。客户端需要接收、记忆和回送Session的会话标识号,Session可以且通常是借助Cookie来传递会话标识号。
Session的跟踪机制
HttpSession对象是保持会话状态信息的存储结构,一个客户端在WEB服务器端对应一个各自的HttpSession对象。WEB服务器并不会在客户端开始访问它时就创建HttpSession对象,只有客户端访问某个能与客户端开启会话的服务端程序时,WEB应用程序才会创建一个与该客户端对应的HttpSession对象。WEB服务器为HttpSession对象分配一个独一无的会话标识号, 然后在响应消息中将这个会话标识号传递给客户端。客户端需要记住会话标识号,并在后续的每次访问请求中都把这个会话标识号传送给WEB服务器,WEB服务器端程序依据回传的会话标识号就知道这次请求是哪个客户端发出的,从而选择与之对应的HttpSession对象。
WEB应用程序创建了与某个客户端对应的HttpSession对象后,只要没有超出一个限定的空闲时间段,HttpSession对象就驻留在WEB服务器内存之中,该客户端此后访问任意的Servlet程序时,它们都使用与客户端对应的那个已存在的HttpSession对象。
Session是实现网上商城的购物车的最佳方案,存储在某个客户Session中的一个集合对象就可充当该客户的一个购物车。
超时管理
WEB服务器无法判断当前的客户端浏览器是否还会继续访问,也无法检测客户端浏览器是否关闭,所以,即使客户已经离开或关闭了浏览器,WEB服务器还要保留与之对应的HttpSession对象。随着时间的推移而不断增加新的访问客户端,WEB服务器内存中将会因此积累起大量的不再被使用的HttpSession对象,并将最终导致服务器内存耗尽。WEB服务器采用“超时限制”的办法来判断客户端是否还在继续访问如果某个客户端在一定的时间之 内没有发出后续请求,WEB服务器则认为客户端已经停止了活动,结束与该客户端的会话并将与之对应的HttpSession对象变成垃圾。
如果客户端浏览器超时后再次发出访问请求,Web服务器则认为这是一个新的会话开始,将为之创建新的Httpsession对象和分配新的会话标识号。
利用Cookie实现Session的跟踪
如果WEB服务器处理某个访问请求时创建了新的HttpSession对象,它将把会话标识号作为一个Cookie项加入到响应消息中,通常情况下,浏览器在随后发出的访问请求中又将会话标识号以Cookie的形式回传给WEB服务器。WEB服务器端程序依据回传的会话标识号就知道以前已经为该客户端创建了HttpSession对象,不必再为该客户端创建新的HttpSession对象,而是直接使用与该会话标识号匹配的HttpSession对象,通过这种方式就实现了对同一个客户端的会话状态的跟踪。
利用URL重写实现Session跟踪
Servlet规范中引入了一种补充的会话管理机制,它允许不支持Cookie的浏览器也可以与WEB服务器保持连续的会话。这种补充机制要求在响应消息的实体内容中必须包含下一 次请求的超链接,并将会话标识号作为超链接的URL地址的一个特殊参数。将会话标识号以参数形式附加在超链接的URL地址后面的技术称为URL重写。 如果在浏览器不支持Cookie或者关闭了Cookie功能的情况下,WEB服务器还要能够与浏览器实现有状态的会话,就必须对所有能被客户端访问的请求路径(包括超链接、form表单的action属性设置和重定向的URL)进行URL重写。
Cookie和Session的区别
session和cookies同样都是针对单独用户的变量(或者说是对象好像更合适点),不同的用户在访问网站的时候都会拥有各自的session或者cookies,不同用户之间互不干扰。
他们的不同点是:
1,存储位置不同
session在服务器端存储,比较安全,但是如果session较多则会影响性能
cookies在客户端存储,存在较大的安全隐患
2,生命周期不同
session生命周期在指定的时间(如20分钟) 到了之后会结束,不到指定的时间,也会随着浏览器进程的结束而结束。
cookies默认情况下也随着浏览器进程结束而结束,但如果手动指定时间,则不受浏览器进程结束的影响。
总结:简而言之,两者都是保存了用户操作的历史信息,但是存在的地方不同;而且session和cookie的目的相同,都是为了克服HTTP协议无状态的缺陷,但是完成方法不同。Session通过cookie在客户端保存session id,将用户的其他会话消息保存在服务端的session对象中;而cookie需要将所有信息都保存在客户端,因此存在着一定的安全隐患,例如本地Cookie中可能保存着用户名和密码,容易泄露。
————————————————
版权声明:本文为CSDN博主「悲观的乐观主义者」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43997530/article/details/105650267
目前众多的网文产品中,设计同质化比较高,无论是产品视觉或是品牌运营视觉大多都缺乏独创性与统一性。番茄小说想要从众多产品中脱颖而出就需要走出一条合而不同的设计道路。因此提升产品的识别度与消费者对品牌的认知势在必行,设计需探索构建一套属于产品的语言体系。
探索番茄小说的设计语言,建立产品认知
传统文学
文学分为两类,严肃文学(看重语言和细节)、通俗文学(注重情节和故事,浅显易懂)。
周宪《文学理论导引》里定义「文学是以精致语言书写的具有艺术价值的以文本为中心的文化系统。」通过定义可以概括出文学的特点就是具有艺术价值,并且能够通过文字内容带人用户反思或者收获。当人们在阅读文学书籍时是冷静的,只有在这样的心境下读者才能更好的独立思考与分析。因此在氛围上需要给用户提供一个相对沉浸的空间、安逸的环境,通过分析可以提炼出的传统文学情绪关键词:沉浸、冷静、舒适、价值
网络文学
不同于传统文学,网络文学是顺应市场价值而诞生,是文学创作的平民化,让大家能够以网络为载体而发表的文字内容。广义来说,网络文学属于通俗文学的一类,注重情节和故事,通过文字传递的内容更加的朴实、接地气,在创作分类上也更加的多样化,作者可以天马行空的表达自己感受,可以说是在传统文学的基础上,给文字增加了几分烟火气息,也多了几分热闹的感受。
因此通过文学关键词可扩展出网络文学情绪关键词:沉浸、愉悦、烟火气
前期通过对小说用户群体与市场的走访调研,并通过数据分析,我们得到了如下结论:
产品用户类型
12-50岁青中年人;后GenX时代;一二三线城市有阅读小说习惯的人群;目前为对生活充满向往的学生与蓝领
产品品牌人格
乐观愉悦(轻松);品质(书好);亲民、丰富(书多)
产品视觉风格
品牌色贯穿产品,但不过分使用;视觉为产品功能服务,不做多余的设计;视觉表现多样化,但需要表达相同的产品气质;适度的留白,增强设计空间感
产品核心词:「沉浸中的愉悦」
正如我们对文学的分析,小说阅读同样是一种独立个体的行为方式,在读书时,我们不希望被人打扰,不希望被琐事细节阻断,我们希望在一个相对安静、舒适的环境下阅读,这是一种沉浸式的感受。
因此这里我们就根据用户的想要的感受,引入「沉浸」的概念——希望能够给读者留下一定的空间,并抛除繁杂打扰,让大家享受阅读与独立思考。其核心是围绕信息内容本身而呈现,设计不再作为独立于内容之外的元素存在,而将着眼于内容本身,为用户打造直观的视觉体验。拉大层级对比,增加适当的留白,在一定程度上增加少许修饰,打破绝对的冷淡。其既能体现出文学的特点,又能够在简约的基础上增加画面的构成感,给用户愉悦的感受。
触感
网络小说与传统文学另外一个最大的区别是触感。
传统文学大多以实体书籍纸张为承载,而网络文学来自于互联网是虚拟的。我们在阅读时,触摸纸张与书本朴实的质感,也能够给读者带来额外的舒适感受,因此如果能以视觉的形式还原用户对书籍的「触感」,不仅能够将网络与实体相链接,也可以帮助用户增加电子阅读的乐趣。
根据归纳出的文学特征,以及调研用户年龄层与喜好,我们可以归纳出番茄小说基础原生关键词。
基础原生关键词
拓展衍生关键词
根据网络文学原生关键词,我们拓展出衍生词
图片搜索、提取情绪版
根据相关的衍生关键词,我们收集大量的视觉图片并将其汇总,借以分析其视觉特征
色彩提取
视觉映射
通过对情绪版的分析,我们可以得出结论并整理出番茄小说设计语言,轻量的色彩、写意式元素、非对称布局、纸纹理噪点
将传统的冷静沉浸与网络文学的热闹向融合是番茄小说设计语言的重要视觉呈现方式风格
多元化的简约设计+情感化修饰
Logo
番茄的品牌名称基于「、优质」的产品理念,服务于产品设计、品牌设计中。番茄相对于红果是一个更加具象的表达,不仅可提高用户对产品的认知,也能传递小说品牌的理念和态度。基于此,这个理念框架是讲述品牌故事的关键载体。
logo动画展示
小说相关产品logo汇总
在logo的设计上我们将番茄的图形概念化,保留番茄籽,局部的留白让标志同样能表达空间与白的概念。我们选择在白色底上用红色非对称性式logo ,既区别了市面上大多产品logo样式,又能够加深用户对产品的印象,突出了「愉悦」的特性。
选定 logo 并设计图形+文字组合:
在文字设计上,相比正常宋体弱化文字衬线,为了突出空间感,我们扩大了字面拉伸了中宫的占比,这样做不仅提高文字识别度,整体气质也也能够与沉浸的定义相耦合。
品牌色
前期通过情绪版的分析,摘取关键词配色,综合归纳出符合番茄小说特性的的色彩搭配
通过对情绪版色彩的归纳,我们抽取具有代表性的颜色,作为番茄小说的品牌色
辅助图形
从logo中番茄图形的概念出发,提取出以圆、番茄籽、番茄轮廓为基本型的品牌图形元素
官方字体
考虑到官方字体在沉浸式页面中的运用,番茄官方字体的选择与品牌属性相契合的苹方体、宋体。
VI 呈现:
品牌视觉感受:
品牌体现—产品场景
番茄小说给人的感觉是安静、平和、友好。因此在颜色使用中以品牌色配合低饱和度背景色做搭配,突出产品的带给用户的沉浸、愉悦感。
运营场景—运营设计对品牌塑造的意义
第一眼的感受,往往决定了用户对产品的整体印象。目前在番茄小说的产品中,最直观的品牌视觉展示主要以书单活动banner为载体,其做为活动入口本身就处在一个前置的位置,占用空间大且更能吸引到用户的注意。因此,需要对运营焦点图设计精细化的打磨,让用户在打开产品的瞬间,快速塑造产品在用户心中的视觉形象。
番茄小说运营设计——和而不同
运营设计的基本原则
因此番茄小说的运营视觉需要紧密围绕在这个大前提下进行设计,快速传达信息=保证信息的简单化、文字有效性,促使用户行动=画面内容的趣味性、吸引性。
视觉呈现形式
遵循番茄体系,体现小说内核的「烟火」气质,视觉呈现多元化。以运营文案为中心,画面设计贴近内容,降低用户信息识别成本。
品牌运营视觉一期构建:手绘元素+非对称构图+质感
设计规范
运营视觉与品牌调性应是统一的,因此在运营设计的色彩选择需要与品牌配色相呼应,保证视觉与整个产品的和谐性。
运营插图案例
在运营活动中,依然要以产品所传递的气质来进行画面设计,即是保留沉浸的前提下,抽取关键词的某个方向来表达品牌运营所传递的理念。在色彩的使用上可以围绕关键词的方向来选择颜色,以表达内容所传递的信息,可适当使用品牌色作为点缀,但依然需要的保持视觉给人带来的平和感。
作为一个从 0 到1的品牌,番茄小说的设计语言依然在不断的打磨、优化。整体清晰的品牌规划能够保证线上、线下、产品与营销的各个视觉设计环节更加统一,同时也为后续的设计指明方向,助力业务持续发展。
文章来源:优设 作者:今日头条UED
his是一个关键字,表示执行当前函数的对象
function fn(){
console.log(this); //window
console.log(typeof this); //object
}
fn();
- 严格模式下,this指向undefiend
"use strict";
function fn(){
console.log(this); //undefined
}
fn();
文章目录
0.官方文档:
1.webpack概述:
2.webpack的基本使用:
3.在项目中安装和配置 webpack:
4.配置自定义打包的自定义入口和出口:
4.配置自动打包功能:
5.配置生成预览页面功能:
6.配置自动打包相关参数:
7.webpack 中的加载器:
8.loader加载器的基本使用:
9.Vue单文件组件:
10.webpack 打包发布:
11.以上所有配置 webpack.config.js 截图
1.webpack概述:
webpack是一个流行的前端项目构建工具(打包工具) ,可以解决当前web开发中所面临的困境
webpack提供了友好的模块化支持,以及代码压缩混淆、处理js兼容问题、性能优化等强大的功能,从而让程序员把工作的重心放到具体的功能实现上,提高了开发效率和项目的可维护性
2.webpack的基本使用:
2.1:打开终端运行命令 npm init -y 初始化包管理配置文件 package.json
2.2:新建 src 源文件目录(里面放程序员自己写的代码比如 html css js images …)
2.3:如果需要引入 jquery 库 终端运行以下命令npm install jquery -S 安装 jquery
自己在src文件夹中创建 index.js 引入下载的jquery包import $ from 'jquery'
3.在项目中安装和配置 webpack:
3.1:终端运行 npm install webpack-cli -D 命令,安装webpack相关的包
这里要注意一个问题 : package.json 和 package-lock.json 文件里的名字默认为 “name”=“webpack”,在配置 webpack-cli 之前要把name 改成 其他名字 比如 “name”=“webpack_” 不然的话为出现无法安装的问题
具体可点击这里 Webpack依赖包安装问题解决方案
3.2:在项目根目录中 ,创建名为 webpack.config.js 的 webpack 配置文件
3.3:在 webpack.config.js 中,初始化一下基本配置
建议选择 development (打包速度快,体积大),项目上线是才改成 production (如果选择production会进行代码的压缩和混淆,打包速度慢,体积小)
3.4:在package.json中的 script节点 新增一个dev脚本 值为 webpack ,就可以实现打包功能
在终端运行命令:npm run dev
就可以打包 默认打包成main.js在 dist文件夹中
在src自己新建的index.html 中引入打包后的 js
属性描述符就是一个属性除了属性名与属性值之外的其他相关信息
通过Object.getOwnPropertyDescriptor(对象, 属性名)
可以得到一个对象的某个属性的属性描述符
let obj = { a: 1 } console.log(Object.getOwnPropertyDescriptor(obj, 'a')); // { // value: 1, // writable: true, // enumerable: true, // configurable: true // }
通过Object.getOwnPropertyDescriptors(对象)
可以得到某个对象的所有属性描述符
let obj = { a: 1, b: 2 } console.log(Object.getOwnPropertyDescriptors(obj)); // { // a: { // value: 1, // writable: true, // enumerable: true, // configurable: true // } // b: { // value: 2, // writable: true, // enumerable: true, // configurable: true // } // }
接下来,说一说每一个属性描述符的作用
不多逼逼
当我们设置configurable为false以后,再去修改属性描述符的话,会报错
let obj = { a: 1, b: 2 } Object.defineProperty(obj, 'a', { value: 'a', configurable: false }) Object.defineProperty(obj, 'a', { value: 'a', configurable: true }) // Uncaught TypeError: Cannot redefine property: a // at Function.defineProperty (<anonymous>)
当设置一个属性的enumerable为false时,该属性不可被forin循环
但是不影响forof循环,因为forof循环看有没有Symbol(Symbol.iterator)
forin循环的是属性名,forof循环的是属性值
不用看时间,你没有穿越,现在是 2020 年,不是 2000 年。这复古的字体设计和这带有年代感的落日背景,以及悠扬壮阔的背景音乐,甚至让我以为是在看二十年前新年晚会的演出视频。
△ 视频链接:https://v.youku.com/v_show/id_XNDYzNTE2MzgxNg==.html
不得了,不得了,恒大足球场的宣传视频甚至登上了央视的广告舞台,展示给了全国观众,壕气十足,花开富贵,这绚烂的烟花背景,让我瞬间梦回三十年前。
建筑不仅外表华丽,其实文化内涵还很深厚,与中老年表情包冥冥之中有了一个巧妙的对应,蕴含着给你带来好运,祝你平安健康。
据网友考据,设计理念可能来自于一盆多肉,为了更加贴近人民群众的生活,让人们时时感受到自然的美妙。
还有网友幻想出最终建设完成时的终极形态,积极对建筑进行了自己的解读和创作,看这广泛的联合角色设计,佛祖、红孩儿;这跨越多个时代的风格杂糅,上个世纪的吉祥如意、这个世纪的游戏建模;涵盖多个领域的莲花主题,植物、彩灯,应有尽有,真是妙啊!
什么?你觉得不好看吗?这可是恒大总裁许家印从 9 种莲花宝座设计方案中精挑细选出来的一个!九种不同的莲花设计方案,深浅不同的粉红色,看不出有多大不同的开合程度,微微不一样的花瓣设计,供你瞪大双眼选择。
你问:可以阻止这个色彩绚丽的建筑修建起来么?来晚了,莲花宝座已经于 4 月 16 日开始修建,届时会成为世界规模最大的顶尖专业足球场。开心一点,说不定以后能在中国看世界杯了呢。
既然是世界规模最大的顶尖足球场!为什么不修好看一点?这什么设计师,这种红配绿,亮瞎人眼的设计是哪个沙雕公司设计的?许老板这么有钱,怎么不请好一点的设计师呢。广州这么时尚的城市配上这样的土味建筑,真是令人头大。其实,你可能骂错人了。背后的设计公司可是 Gensler,现在世界上数一数二的的设计团队。这不是变魔术,设计出上面土味十足的建筑和下面高级感扑面而来的建筑的就是一个团队。
上海中心大厦(右一),凭借其独特的造型和楼高,荣获诸多大奖,成为上海地标性的建筑之一。
还有菲律宾金融中心大厦,与周围的建筑对比起来,科技感和现代感十足,在 CBD 群中独占鳌头。
又或者是在波士顿起到枢纽作用的综合体建筑设计,一眼望去称霸整个地区。
这怎么看,都不像是一个团队设计出来的作品。莲花球场和高级感相关在哪里?这不是随随便便一个设计师都可以设计出来的么?其实,这也不是许老板第一次这么偏爱莲花了,看看海花岛项目就知道了,网友调侃说到,果然设计师还是败给了金钱。
不过同样是以莲花为设计元素,印度的莲花寺怎么看起来就这么高端优雅呢?与莲花球场「土味建筑」不同的是,莲花寺广受好评,被称为新德里的「悉尼歌剧院」。
类似莲花球场这样的案例在中国还有很多。之前被评为 2017 年中国最丑陋的十大建筑之一的广州圆大厦,由意大利米兰设计师 Joseph di Pasquale 设计,他在采访中说到:「中国改变了他,让他知道了文化如何融于建筑,如何更好地满足客户的欲望。」其实建筑的寓意「双环玉璧」是很好的,但是最终的效果不尽人意,建筑类似于黄金的外表颜色,被网友们吐槽,称其为「土豪圆」。
不过设计这个事情,有时候也很难去用单纯的美丑判别。例如设计出台北 101 大厦的李祖原老师,在同年设计出的沈阳方圆大厦,是参考铜钱的形状设计而成。在 2000 年威尼斯世界建筑设计展览会上被称赞为是「世界上最具创意性和革命性的完美建筑」,但在 2012 年却被 CNN 旗下的生活旅游网评选为全球最丑的十大建筑之一。
你以为这就结束了吗?别走,奇葩建筑还有很多,中国各个省都互不相让。首先我们从南看起,海南三亚的「美丽之冠」,就是后面那些像树一样的建筑,一模一样的楼不知道为什么要修建九个。
往北走,我们来到了官方宣传视频里写到的「不来万家丽,枉来中国行」,之中的世界最大建筑「长沙万家丽」。这栋同样金碧辉煌、中西结合的建筑让你深刻体会到一句话「有钱就是可以为所欲为」。不论是美是丑是否合适,只要是自己喜欢的元素,通通都堆砌在一栋建筑里。
接着我们来到了山东的文成城堡,沈腾的《西虹市首富》取景地,看看这个豪华程度,一晃神还以为自己来到了欧洲。
最后我们来到河北,学习魔法不需要出国,直接来河北美术学院,一个被戏称为「霍格沃茨华北分校」的美术帝国,由于其仿照魔法学院进行的设计,在中国众多美院中独树一帜。
以上这些奇葩建筑的盘点,均来自于 B 站 up 主史里芬 Schlieffen,一个被长沙万家丽老板黄总盛情邀请再次体验万家丽的男人。盘点中国奇葩建筑,现代青年当仁不让。想要了解中国建筑底层设计的朋友,可以前去品鉴和观赏,不要怪我用丑陋和土味蒙蔽了你们的双眼。押韵的解说词,第一视角的全方位建筑讲解,你值得拥有。
主页链接:https://space.bilibili.com/323733137/
这样的建筑作品很新鲜但是确实不美观。且不说中国其实有很多好的设计师,为什么和国外知名设计团队合作,做出来的作品依旧差强人意呢?难不成是我们的审美水平真的已经沦落成这个地步了?如果哪天全民都觉得这样的建筑是美的,都欣赏这样的建筑,那我们整个社会才算是陷入了「恶趣味审美」之中,就真正完蛋了。标榜着以「莲花绽放」这一美好寓意为核心的莲花球场设计,何尝不是披着虚伪外衣的土味建筑设计呢?美能够让人感到幸福,反过来,丑则使人感到不适。
对于莲花宝座外形的足球场设计,我想开了,毕竟我不是亚洲第五富,众位设计师,你们是怎样看待的呢?
文章来源:优设
feed 单词释义:v. 喂养;进食;为……提供充足的食物;施肥;为(某人)提供(信息、主意等);
n. 饲料;饲养;(尤指给动物或婴儿)喂食;进食;(计算机的)订阅源
形象来讲,如今新浪微博、微信朋友圈、抖音、今日头条、小红书、Facebook、QQ 空间等等内容平台每时每刻都在不断投喂给我们赖以维系健康生活(废柴生活)的精神食粮——信息内容。而这些信息组合起来的格式便是 feed。
1. Feed
feed 是一种信息格式,平台通过它将资讯传递给用户。feed 是信息聚合的最小单元,每一条状态或者消息都是 Feed,比如朋友圈中的一个动态就是一个Feed,微博中的一条微博就是一个 Feed。
2. Feed流
feed 流即持续更新并呈现给用户内容的信息流。每个人的朋友圈,微博关注页,头条新闻等等都是一个 Feed 流。
Feed 源于早期的 RSS(Really Simple Syndication )
RSS(简易信息聚合):将用户主动订阅的若干消息源组合在一起形成内容(aggregator),帮助用户持续地获取的订阅源内容。对用户而言,聚合器是专门用来订阅网站的软件,一般亦称为 RSS 阅读器、feed 阅读器、新闻阅读器等。用户选择订阅多个订阅源,网站提供 feed 网址 ,用户将 feed 网址登记到聚合器里,在聚合器里形成聚合页,用户便能持续地获取的订阅源内容。
在早期的 Web 时代,订阅源一般是新闻网站以及博客。用户主动订阅感兴趣的多个订阅源,订阅器帮用户及时更新订阅源信息,然后按照 timeline 时间顺序展示出来。这样,用户可以通过订阅器获取即时信息,而不用每天都检查各个订阅源是否有更新。
转折出现在 2006 年,Facebook 宣布了一项新的首页形式「News Feed」,这一形式打破了传统 RSS 的订阅方式。News Feed 可以看做一个新型聚合器,订阅源不仅仅是某个网址、某个新闻网站或者某个内容,而是生产内容的人或者团体,而内容即是好友或关注对象的动态(发布的内容以及其他的社交行为)。News Feed 的出现使得 RSS 被迫淡出历史舞台。News Feed 发展至今已经拓展出多种多样的模式和呈现方式。
推模式:每当用户发帖,对所有粉丝推送一条该用户的动态消息记录。需要考虑的是如果一个粉丝量级非常大的用户(大 V),发布一条动态那么需要在每个粉丝页推送一条动态,多个大 V 级别用户同时发帖对数据的存储负荷是非常大的。
拉模式:每当请求好友动态,拉取用户所有关注者的最近动态,然后汇总排序。如果用户同时关注非常多的用户,那么查询这类型的用户的关注列表也是很大的数据成本。
推拉模式:在线推,离线拉;定时推,离线拉。
除了关注 feed 流的主要模式之外,feed 流的排序方式也值得一提:
Timeline:按发布的时间顺序排序,先发布的先看到,后发布的排列在最顶端,类似于微信朋友圈等。这也是一种最常见的形式。产品如果选择 Timeline 类型,那么就是认为 feed 流中的 feed 不多,但是每个 feed 都很重要,都需要用户看到。
Rank:按某个非时间的因子排序,一般是按照用户的喜好度排序,用户最喜欢的排在最前面,次喜欢的排在后面。这种一般假定用户可能看到的 Feed 非常多,而用户花费在这里的时间有限,那么就为用户选择出用户最想看的 Top N 结果,场景的应用场景有微博、头条新闻推荐类、商品、视频推荐等。
目前 feed 流的主流排序方式不再严格按照 timeline,而是广泛使用智能 feed 排序。
智能排序基于趋势 trending、热门 hot、用户生产 UGC 、编辑推荐 PGC、相似 Similarity 等等因素综合考虑,随着技术的进步,智能算法将会更加懂得用户的喜好。新的 feed 流不再需要用户主动订阅或者搜索,只要监测我们的浏览时长、点赞分享等动作,或者建立用户画像类别,就可以主动推荐我们感兴趣的内容。它对我们了如指掌,给我们想了解的,让我们不停刷新沉溺于其中。就现在 feed 流中的广告,女性用户对化妆品的喜好,男性用户对车的偏爱,临时借钱的窘迫,这些暖广告已经不再像牛皮癣一样惹人讨厌,甚至变成了一颗我们愿意吃下的安利。
可以有以下大致分类:
feed 作为信息聚合的最小单元,每一个 feed 都会具备相应的内容。其中包括发布的时间、发布者、文字内容、图片内容,还包含点赞、转发、评论、关注等操作、根据应用场景、业务目标不同,其表现方式也大有不同,任何表现形式都应该是为了更好地呈现功能及内容。
新闻资讯类产品和社交互动类产品 feed 元素大体相同,区别在于新闻资讯类产品通常着重展现新闻内容,标题,简介,匹配的图片等,而发布时间和发布作者等会在单个 feed 的底部出现。在图文兼备的排版布局中,左文右图适合文字内容类比如文章或者知乎、豆瓣等长答案评论等,图片是辅助信息支撑文字内容。左图右文图片更加吸引人的注意通常出现在商品信息比如什么值得买。
社交互动类产品,其最终目的是发现和拓展社交关系,融入相应的社交圈。而这时候社交拓展的基本单位人或者团体发挥着至关重要的作用。所以我们可以发现,通常的社交互动软件都会将发布者头像放在上部展示的位置,也会在底部突出点赞,评论,分享等互动操作。
视频直播类产品与前两者相异,页面的大部分空间留给视频内容的展示,一般一屏只承载一个 feed 信息单元,内容等提示元素在左侧呈现,除回复评论等操作元素列在右侧。
feed 中各元素的位置关系、所占比例与产品自身定位密切相关。如微博作为泛社交应用产品,社交关系主要建立在内容上,社交关系质量较弱,多为单向传播,注重的是传播的速度和内容公开。所以其 feed 的呈现方式发布者与发布内容不做明显的设计排布区分。以卡片间隔的形式在 feed 与 feed 之间做区隔。评论页面在下一层级。
微信是作为一个社交工具,社交关系质量较强,多为双向关系,注重的是私人内容的交流和互动,信息的传播速度不快,但受众信息消化率很高。所以将发布者头像与发布内容做出较明显区分,feed 与 feed 之间因为已经有了头像元素这一明显区别要素,仅用分割线做区隔。且注重评论区域的互动与展示。
无论怎样的设计布局方式,遵循的核心思想始终是根据场景需求、业务目标去发展深化设计方案。每一个设计点都要有足够的支撑,多问问自己为什么这么设计,解决了用户什么样的问题?还有没有更好的替代方案?而不是这样设计是不是新颖,出奇制胜。
文章来源:优设 作者:Nicole
性能优化(网络方向)
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
蓝蓝设计的小编 http://www.lanlanwork.com