不会化妆的写手
不是好程序员


  • Home

  • Categories

  • Archives

  • Tags

  • About

Vue.js keep-alive踩坑

Posted on 2018-03-08 | In 框架/库/工具 , Vue.js

发现面试好像会喜欢问“项目中遇到的难点”这样的问题。但说实话,难点这种东西,难了不会,会了不难,一旦解决了就觉得也还好,过段时间也就忘了,再过段时间,哪怕能想起来,也一定觉得不是什么值得说出来的问题。
总之,确实怎么回想也想不出什么难点,就只好从现在开始记录了。
就从keep-alive踩坑开始吧。
本文主要为了给个人记录一个过程,因此按照踩坑顺序记录,而不是一个知识体系。
btw过程中发现了好多博客的错误……

首先,移动端,一个列表页,一个详情页。从列表页点入详情页,再从详情页回退到列表页,实际上列表页是完全不需要刷新的。在此需求上,能做到类似App那样“前进刷新,后退不刷新”的效果,当然是极好的。

判断前进还是后退

单纯监听前进还是后退,很容易想到监听popstate事件。但是这个事件不管前进还是后退都能触发,且不能和Vue的生命周期结合起来,所以Pass。

其他人的实现提供了两种方法,一种是另辟蹊径:vue单页面,多路由,前进刷新,后退不刷新,严格监听是从哪一个路由跳到哪一个路由,从而监听是前进还是后退。这显然是很死板的,当然,如果需求简单,仅仅需要顾及几个页面,那反而很安全。另一种是vue实现前进刷新,后退不刷新,使用路由的路径层级去判断是前进还是后退,也就是说,前进后退和路由层级严格挂钩,路由和前进后退的方向都变得不自由了。

我开始想的是第三种方法,在路由信息对象上记录数字,用这个数字标识层级。但是很快意识到,这种方法也不直观,最直观的方法莫过于直接压一个栈。当要去的路由等于栈顶的路由的时候,就相当于是后退了。

1
2
3
4
5
6
7
8
9
10
let routerStack = []
router.beforeEach((to, from, next) => {
if (to.name === routerStack[routerStack.length - 1]) {
// 后退
routerStack.pop()
} else {
// 前进
routerStack.push(to.name)
}
})
Read more »

JS获取各种常见位置距离

Posted on 2018-03-02 | In JavaScript , 基础

client/offset/scroll系

width/height

element.clientWidth/Height

按照以下判定规则:

  1. 如果没有CSS布局盒子或者CSS布局盒子为inline,返回0;
  2. 如果是根元素(html元素)或body元素,clientWidth/Height指的是视口的宽高(不含滚动条)
  3. 否则,如上,是不包含border不包含滚动条的元素宽高。

显然,其实就是致力于表示元素能够用于显示内容的那部分区域的宽高,所以才叫做clientWidth/Height吧。

用盒子模型表达,就是content-box去除滚动条占位。

clientWidth/Height

element.offsetWidth/Height

与clientWidth/Height致力于表示元素能显示内容的区域的宽高不同,offsetWidth/Height致力于表示元素本身的宽高。

用盒子模型表达,即border-box的宽高。

offsetWidth/Height

element.scrollWidth/Height

表示元素内容的宽高,即包括了被卷去部分的宽高。

用盒子模型表达,就是……没有专门的框,就是显示在content-box中的内容的宽高(内容仅包含常规流中的元素),包括因设置overflow: auto/hidden藏起的部分

Read more »

关键渲染路径

Posted on 2018-02-05 | In 前端基础

关键渲染路径

从收到HTML、CSS和JavaScript字节到对其进行必需的处理,从而将它们转变成渲染的像素。这一过程中有一些中间步骤,即关键渲染路径。

  1. 处理HTML标记并构建DOM树;
  2. 处理CSS标记并构建CSSOM树;
  3. 将DOM与CSSOM合并成一个渲染树;
  4. 根据渲染树来布局,以计算每个节点的几何信息;
  5. 将各个节点绘制到屏幕上。

阻塞渲染的CSS

关键渲染路径要求我们同时具有DOM和CSSOM才能构建渲染树,因此HTML和CSS都是阻塞渲染的资源。
我们可以通过媒体类型和媒体查询将一些CSS资源标记为不阻塞渲染。
浏览器会下载所有的CSS资源,无论是否阻塞渲染,只是不阻塞渲染的资源优先级比较低。
阻塞渲染指的是浏览器是否要暂停网页的首次渲染,直至该资源准备就绪。

Read more »

Underscore.js实现bind方法

Posted on 2018-01-23 | In 框架/库/工具 , Underscore.js

ES5中的bind

描述

bind()函数会创建一个新函数(称为绑定函数),新函数与被调用函数(绑定函数的目标函数)具有相同的函数体(。当新函数被调用时,this值绑定到bind()的第一个参数,该参数不能被重写。绑定函数被调用时,bind()也接受预设的参数提供给原函数。
一个绑定函数也能够使用new操作符创建对象,这种行为就像是把原函数当做构造器。提供的this值被忽略,同时调用时的参数被提供给模拟函数。

语法

fun.bind(thisArg[, arg1, [, arg2, [, …]]])

  • thisArg:当调用绑定函数时,该参数会作为目标函数运行时的this指向。当使用new操作符调用绑定函数时,该参数无效。
  • arg1, arg2, …:当调用目标函数时,前置于提供给绑定函数的参数的参数
  • 返回值:返回由指定的this值和初始化参数改造的原函数拷贝
Read more »

替换元素和非替换元素

Posted on 2018-01-18 | In CSS

印象很深,一年前觉得这么简单的概念不需要专门记,结果一年后就打脸了,又要重新翻找……好记性不如烂笔头。

替换元素(replaced element)

替换元素是指内容不在CSS格式化模型范围的元素,比如图片、嵌入的文档或者应用程序。举例说,HTML IMG元素的内容常常被它的src属性指定的图片所替换。替换元素常常本身就有尺寸:一个本身的宽、一个本身的高和一个本身的比例。比如说,一个位图图片本身有绝对单位决定的宽和高(其比例显然也被确定)。另一方面,其他文档也有可能没有任何本身的尺寸(如果一个空白的HTML文档)。

计算width和margin

计算值(computed value):给CSS属性设置的值。比如,如果是width属性,其计算值可以是百分比或auto或绝对长度。
使用值(used value):在布局时被使用的值,即最终实际看到的效果值。

行内非替换元素

  • margin-left或margin-right的计算值为auto,使用值为0。
  • width属性不被接受。

行内替换元素

  • margin-left或margin-right的计算值为auto,使用值为0。
  • 如果height和width的计算值都为auto,元素也有本身的宽度,那么这个本身的宽度就是width的使用值。例子:img、input。
  • 如果width的计算值为auto,元素也有本身的宽度,那么这个本身的宽度就是width的使用值。
  • 如果height和width的计算值都为auto,元素没有本身的宽度,但有本身的高度和比例;或者width的计算值为auto,height有其他的计算值,且元素有本身的比例,那么width的计算值为:高度的使用值(height的计算值或元素本身的高度) * 本身的比例。简单说,就是在此情况下,如果元素的高度(设置的或者本身的)和比例确定,则宽度根据此确定。
  • 除此之外,如果width的计算值为auto,那么width的使用值为300px。如果300px太宽了不能适应屏幕,UA应该使用2:1比例的最大矩形的宽度来适应屏幕。例子:iframe、canvas。

其他类型的替换元素,其宽度的定义都参照行内替换元素的定义。

Read more »

Nuxt.js使用笔记

Posted on 2018-01-09 | In 框架/库/工具 , Vue.js

Nuxt.js原理

一开始不知道这是怎么做到服务器端渲染的,后来写着写着就明白了。启动一个Server,执行前端代码。我司后端用的是nginx,配置是将请求直接转发到这个Server。
初次请求页面时,前端代码由Server端执行,生成一个内容完整而不是依赖js动态执行展示内容的HTML文件,再返回给Client端。
之后则正常走单页面应用的逻辑。

与浏览器执行代码的不同之处

初次请求由Server端执行也带来了一些问题。在初次请求时,组件created之前的步骤全部由Server端执行,包括middleware、asyncData、beforeCreate。

cookie

因为是在Server端执行代码,本地将没有Client端有的cookie,因此:

  • 在发送ajax请求时,需要通过req.headers.cookie将cookie取出,然后设置axios,以此做到发送ajax时携带cookie。为axios设置的cookie不能为undefined,否则报错“”value” required in setHeader(“cookie”, value)”;
  • 在收到响应后,如果后台set cookie,在Server端也无法正常达到将cookie set到Client端上的效果,而需要利用res.setHeader(‘set-cookie’, ‘cookie=cookie’),从Server端设置Client端的cookie。
Read more »

Underscore.js实现链式调用

Posted on 2017-12-14 | In 框架/库/工具 , Underscore.js

underscore基本结构

在全局变量上挂载一个对象“_”,将方法全部添加在这个对象上。

1
2
3
4
5
6
7
var root = typeof self == 'object' && self.self === self && self ||
typeof global == 'object' && global.global === global && global ||
this ||
{}

var _ = {}
root._ = _

面向对象风格

调用underscore方法的两种方式:

1
2
3
4
_.each(obj, function () {})

// 面向对象风格
_(obj).each(function () {})

为实现面向对象风格,将_写为构造函数。

Read more »

对象类型判断

Posted on 2017-11-23 | In JavaScript , 基础

类型判断的方法 - Object.prototype.toString是最优解

Array.isArray()

ES5,低版本浏览器不支持。只有Array有这个方法。

typeof

无法判断出array与null,两个返回结果都是object。

instanceof

问题1:

1
2
3
4
var num = 1
num instanceof Number // false
var num = new Number()
num instanceof Number // true

如果是直接创建的原始类型,不instanceof其构造函数。当然,array、object等引用类型不受影响。

Read more »

Underscore.js源码笔记

Posted on 2017-11-23 | In 框架/库/工具 , Underscore.js

用void 0代替undefined

undefined可以被重写

  1. undefined并不是保留词(reserved word),只是全局对象的一个属性(window.undefined === undefined),因此在低版本的IE中可以被重写。
1
2
var undefined = 10
console.log(undefined) // 10 -- IE8
  1. undefined在ES5中已经是一个只读(read-only)属性了,不能被重写。但是在局部作用域中,还是可以被重写的。与浏览器版本无关。
1
2
3
4
(function () {
var undefined = 10
console.log(undefined) // 10
})()
1
2
3
4
(function () {
undefined = 10
console.log(undefined) // undefined
})()
Read more »

Vue.js双向数据绑定原理

Posted on 2017-10-10 | In 框架/库/工具 , Vue.js

写个(只有)自己能看懂的流程。

mvvm.js

  1. 数据代理;
  2. initComputed;
  3. observe(this.data)。

observer.js

  1. 监听每一个值的get/set,每一个值跟随一个dep。如果被取值,将Dep全局保存的watcher推入dep中的watcher列表。

mvvm.js

  1. compile(options.el)。

compile.js

  1. 遍历el中的所有节点,分别处理每个节点。
  2. 以text节点为例,分析出是否和data的属性关联,如果关联,新建一个watcher,watcher中包含了此节点、关联的data属性名以及updateFn(一个用于更新节点的函数,比如文本节点,就是node.textContent = val)。

watcher.js

  1. 将与节点相关联的属性名分解开来(a.b.c),挨个取值;
  2. 因取值而触发observer.js中的get方法,将该watcher推入该属性的dep中;
  3. watcher中记录下该watcher推入过哪个dep(dep标id),避免重复推入(update时也需要get值,此时不需要重复推入)。
1234…6
泉先

泉先

今天我有变得更厉害一点吗!>v<

51 posts
14 categories
23 tags
© 2017 - 2022 泉先
Powered by Hexo
Theme - NexT.Gemini