van-list 一直触发加载问题的排查

移动端分页一般都是向下滑动加载更多,Vant 组件库提供了 van-list 来实现这一功能。

List 组件通过loadingfinished两个变量控制加载状态,当组件滚动到底部时,会触发load事件并将loading设置成true。此时可以发起异步操作并更新数据,数据更新完毕后,将loading设置成false即可。若数据已全部加载完毕,则直接将finished设置成true即可。

实际应用中发现,即使内部元素已经填满一整屏,仍然会触发加载,直到我模拟的20多页全部加载完才停下来。

我没有给这个问题写专门的 CodePen demo,比较麻烦,碰到的人也不一定多。

结论

van-list 会在内容之后增加一个 placeholder,通过 placeholder 的位置判断内容是否已填充满屏。
van-list 本身为 flex 布局时,flex-direction 必须是 column(或 column-reverse)。

过程

首先我的用法是这样的:

template
1
2
3
4
5
6
7
<van-list> <!-- flex -->
<van-grid>
<van-grid-item />
<van-grid-item />
<van-grid-item />
</van-grid>
</van-list>

首先看文档,英文文档没有提到,但中文文档有以下一段话:

使用 float 布局后一直触发加载?
若 List 的内容使用了 float 布局,可以在容器上添加van-clearfix类名来清除浮动,使得 List 能正确判断元素位置

检查了一下,我没有在使用 float 布局呀。

JS 原生对象与数组拷贝

浅拷贝单层对象

1
2
let obj = { id: 1, title: "1" }
let copyOfObj = Object.assign({}, obj)

深拷贝多层对象

1
2
3
4
5
6
7
let obj = {
id: 1,
title: "1",
tag: ['js', 'javascript'],
category: { id: 1001, title: 'frontend' }
}
let copyOfObj = JSON.parse(JSON.stringify(obj))

浅拷贝简单类型数组

1
2
let arr = [1, 2, 3]
let copyOfArr = [...arr]

深拷贝单层对象组成的数组

1
2
3
4
5
6
7
let arr = [
{ id: 1, title: "1" },
{ id: 2, title: "2" },
{ id: 3, title: "3" }
]
let copyOfArr1 = arr.map((item) => Object.assign({}, item))
let copyOfArr2 = JSON.parse(JSON.stringify(arr))

深拷贝多层对象组成的数组

1
2
3
4
5
6
7
let arr = [
{ id: 1, title: "1", subObj: { name: 'subObj1' } },
{ id: 2, title: "2", subObj: { name: 'subObj2' } },
{ id: 3, title: "3", subObj: { name: 'subObj3' } }
]
let copyOfArr1 = arr.map((item) => JSON.parse(JSON.stringify(item)))
let copyOfArr2 = JSON.parse(JSON.stringify(arr))

总结

不考虑性能的情况下,JSON.parse(JSON.stringify(value))是最简最万能的拷贝。

直接操作 Vue data 中不存在的属性导致的 v-model 绑定异常问题

直接操作 Vue data 中不存在的属性导致的 v-model 绑定异常问题

初学Vue遇到的问题,尝试了几个小时才搞明白,大佬应该一眼就能看出什么问题吧……

需要注意,不要直接在JS中操作一个Vue data对象中不存在的属性,如果同时有通过v-model绑定到该对象的不存在的属性时,会出现诡异的行为表现,console中不会报出任何 warnerror

需求是,实现三个复选框,第一个复选框初始为选中状态,一开始写出来是这样的——

HTML
1
2
3
4
5
<div id="app" style="margin: 10px;">
<van-checkbox v-for="box in checkboxes" :key="box.id" v-model="box.selected">
复选框 {{ box.title }}
</van-checkbox>
</div>
JS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
new Vue({
el: '#app',
data () {
return {
checkboxes: [
{ id: 1, title: 'a' },
{ id: 2, title: 'b' },
{ id: 3, title: 'c' }
]
}
},
created () {
this.checkboxes[0].selected = true
}
})

试下效果:

See the Pen vue-v-model-not-work by iMaeGoo (@iMaeGoo) on CodePen.

复选框a的表现显然是异常的,点击不能成功地切换选中状态,而在点击之后再点击其他复选框,才会“有延迟地”切换状态。

Node.js 实现 HTTP 访问日志

越来越咸,两个月没发文章了,刚刚换项目了,开始学一些新的知识。
近来调试 webhook 和 http callback 比较多,想要使用 Node.js 写一个接收所有 HTTP 请求,并把请求头和请求体写进log,返回 200 OK 的 service。

其实就是简单的 access.log 啦。
其实就是刚学习 Node.js 写的 demo 啦。
啊这是很简单你不要拆穿啦。

这是输出的 log 的样子,优化了可读性,时间、method、path、URL参数(Query)、请求头(Header)、请求体(Body)都详细记录了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
info: 2019-07-25 18:04:36
POST /v1.0/standard
Query:
search: keyword
Header:
cache-control: no-cache
postman-token: f4103067-4b07-447d-9fab-f09a75b6ddda
content-type: application/json
user-agent: PostmanRuntime/3.0.11-hotfix.2
accept: */*
host: localhost:4000
accept-encoding: gzip, deflate
content-length: 209
connection: keep-alive
Body:
appId: XXX
data:
userId: 123
requestId: 456
timestamp: 0

AngularJS 给 directive scope 绑定的 function 传参

如果我们想要给directive的scope中绑定的方法传递参数,需要传递对象,而不是直接传值。

举个栗子,这里的clickOutside是从用的地方传入的一个方法,debug时我们会发现绑进来的clickOutside并不是我们传的clickOutSideAction

1
2
3
4
5
6
7
8
9
10
11
12
13
app.directive('clickOutSide', ['$document', function($document) {
return {
restrict: 'A',
scope: {
clickOutside: '&'
},
link: function (scope, el) {
$document.on('click', function (e) {
scope.clickOutside();
});
}
}
}]);
1
<div data-click-out-side click-Outside="$ctrl.clickOutSideAction()"></div>

如果需要在这里给clickOutSideAction传参数,应该这样改:

1
2
3
4
5
6
7
8
9
10
app.directive('clickOutSide', ['$document', function($document) {
return {
...
link: function (scope, el) {
...
scope.clickOutside({event: e});
...
}
}
}]);
1
<div data-click-out-side click-Outside="$ctrl.clickOutSideAction(event)"></div>

好处是在实际使用directive的地方,不需要考虑参数列表顺序,只需要保证参数名称正确。

AngularJS <input> 输入框自适应内容宽度

在Gist上找到的一个directive,用来让input输入框的宽度自适应内容宽度。
https://gist.github.com/mbenford/8016984

原理是生成一个相同样式的,隐藏的span,通过span的宽度动态改变input的宽度。
同时兼顾了input有placeholder的情况。

如果是在比较大的系统中,可以用throttle节流阀包装一下resize方法,避免性能问题。

如果是textarea,对应的directive在这里:
https://github.com/monospaced/angular-elastic

AngularJS Material制作气泡弹出效果

AngularJS Material制作气泡弹出效果

点击一个按钮后需要弹出一个对话气泡,气泡内有各种设置项,点击外侧可以退出。

现在的效果:

在线测试:https://codepen.io/iMaeGoo/pen/KYVRGL

编写Chrome插件将googleapis替换为国内可访问的CDN

编写Chrome插件将googleapis替换为国内可访问的CDN

由于公司不能安装梯子,所以不能访问谷歌商店,平时频繁地要访问国外的AngularJS网站,比如AgGrid,AngularJS Material,AngularJS官网等,很多用了Google的CDN源,页面就无法正常加载。

一开始的思路是改host文件,但是我们没有Google CDN的证书,会造成证书错误。

参考并优化了:https://github.com/justjavac/ReplaceGoogleCDN ,动手写了一个Chrome插件,对所有特定请求重定向,解决痛点!

Make simple <md-chip> work without <md-chips> in AngularJS Material?

Make simple <md-chip> work without <md-chips> in AngularJS Material?

I’m using AngularJS Material v1.1.1.
I’m finding a way to use simple <md-chip> without <md-chips>.

Here is an easy way in Vue Material: https://codesandbox.io/s/lyoqv4l0z?module=App.vue

1
<md-chip class="md-primary" md-deletable>Deletable</md-chip>

But I can not find the similiar way in AngularJS Material document.
https://material.angularjs.org/latest/api/directive/mdChip

AngularJS表达式无法引用$rootScope变量

Angular version: 1.6.6
在HTML中想使用$rootScope中的变量时发现取不到,加上$root之后解决。

HTML表达式对应的JS变量
{{abc}}$scope.abc
{{$ctrl.abc}}this.abc
{{$root.abc}}$rootScope.abc
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×