0%

组件划分

cascader组件共划分成了三个组件:

  • cascader.vue
  • caspanel.vue
  • casitem.vue

其中,cascader是最外层的组件,包括一个slot和caspanel。slot内部默认是一个input框。

caspanel则是弹出的面板,里面包括若干个casitem选项,和一个子caspanel面板(如果有)。

casitem则是简单的选项组件,存放选项。

DOM结构

大致的DOM结构如下:

1
2
3
4
5
<Cascader>
<Input>
<Caspanel>
<Caspanel>
<Casitem>

逻辑思路

阅读全文 »

好久没有记一些东西了,本菜鸡又来水文章了。

写在前面

  • iview里面的树组件思路跟vue官网上的树形视图示例类似,应用了组件的递归使用(好像是废话

  • 整个树组件里有两个vue文件,一个是递归使用的node.vue,一个是父组件tree.vue

  • 组件内的事件大致分为三种:expand(展开)、select(点击节点title触发)和check(复选框的选中与取消触发)

node.vue

这个组件内包括树组件的一个选项,以及它的children(如果有)

template

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<collapse-transition>
<ul :class="classes" v-show="visible">
<li>
<span :class="arrowClasses" @click="handleExpand">
<Icon type="arrow-right-b"></Icon>
</span>
<Checkbox
v-if="showCheckbox"
:value="data.checked"
:indeterminate="indeterminate"
:disabled="data.disabled || data.disableCheckbox"
@click.native.prevent="handleCheck"></Checkbox>
<span :class="titleClasses" v-html="data.title" @click="handleSelect"></span>
<Tree-node
v-for="item in data.children"
:key="item.nodeKey"
:data="item"
:visible="data.expand"
:multiple="multiple"
:show-checkbox="showCheckbox">
</Tree-node>
</li>
</ul>
</collapse-transition>
</template>

collapse-transition应该是父节点展开收起的动画效果,ul则是包括一个父节点,里面的tree-node是这个父节点的所有子节点,通过v-for循环渲染出来,而其子节点的每一项跟父节点是一样的结构,所以tree-node实际上就是node.vue组件本身。

然后是script部分

主要props

阅读全文 »

情景

有的时候会遇到这种问题,比如说有两个人,在同一个分支进行开发,假设是我自己,跟我的同伴;现在,我写了一部分代码,准备push到远程了,于是我执行git add、git commit,一切ok,没问题,然后git push,这下问题来了,git告诉我说我的push被rejected了,原来,我的同伴在我执行push之前,已经push了若干个commit到远程,因此我不能直接push,而是需要先把他的commits拉到我本地的repo才行。git的提示如下图。

push rejected

按照git的提示做

好,git的提示已经很清楚了,rejected的原因通常是远程有了另外的push,询问了同伴,我们知道,就是ta先进行了push。那么,根据git的提示,我们可能想要先把远程的改变进行整合,再来push。那怎么整合呢,rejected那行告诉我们,要“fetch first”,而下面的e.g.说,我们可以用git pull来整合。也就是说,我们可以用git fetch,也可以用git pull来整合远程的改变到我们本地仓库中。

使用git pull

由于我本人对fetch不太了解,看着pull好像跟push是反义词比较亲切,那就用它吧。于是我执行了git pull,然后git push。emmmm,好像没什么问题,但是…在source tree里面看着分支的图谱怎么怪怪的?

git fetch

图谱里面显示,我提交了两个commit,但实际上我改动的地方只进行了一次提交。我们看看多出来的commit的描述,写着“Merge branch ‘master’ of github.com:ChuChencheng/test”。

嗯?意思是这个提交做的改动是把远端的master分支进行合并。

阅读全文 »

关于git的基本理解

git:一种分布式版本控制系统

git保存的是每一次改动,而不是文件本身。


git有三个区:

工作区(Working Directory)

这个区就是你在电脑上创建项目的地方,文件的编辑修改都在这个区中进行。

暂存区(Stage Area)

暂存区存放的是待提交到repo的修改,当你使用git add命令时,就是把工作区的修改添加到暂存区。

版本库/仓库(Git Directory/Repository)

阅读全文 »

**Block helper可以让你自定义迭代器和其他可以传入新的上下文的功能** # 基本块 Block helper的定义方法是:在一个mustache中,以`#`开头,后面跟着helper的名称,然后对应的在一个mustache中以`/`开头,加上相同的名称作为这个块的结尾。 形如:
1
2
3
{{#hello}}
{{item}}
{{/hello}}
在helper中,function接收一个hash参数options,而options有个fn方法,该方法可接收一个context参数来改变block中的上下文,返回一个类似于编译后的Handlebars模板,明确地说,就是一个字符串。
1
2
3
Handlebars.registerHelper('hello', function(options){
return options.fn(this);
});
在上面的代码中,我们给options.fn传入了一个新的上下文,这个新的context是this,就是代表当前的上下文,因此,如果当前的上下文是:
1
2
3
4
5
{
title: 'This is the title.',
body: 'body',
item: 'item'
}
那么block中的item标识符最终返回字符串`'item'` 注:以这种方式定义的helper,在模板中,可以使用path,如上面的`{{item}}`可以写成`{{./item}}` # with helper(内置) with helper会把传入的context直接调用,实现如下
1
2
3
Handlebars.registerHelper('with', function(context, options) {
return options.fn(context);
});
当处理json的时候用with比较方便
1
2
3
4
5
6
7
<div class="entry">
<h1>{{title}}</h1>
{{#with story}}
<div class="intro">{{{intro}}}</div>
<div class="body">{{{body}}}</div>
{{/with}}
</div>
context:
1
2
3
4
5
6
7
{
title: "First Post",
story: {
intro: "Before the jump",
body: "After the jump"
}
}
# 简单迭代器 先来看一下内置的each helper是怎么实现的
1
2
3
4
5
6
7
8
<div class="comments">
{{#each comments}}
<div class="comment">
<h2>{{subject}}</h2>
{{{body}}}
</div>
{{/each}}
</div>
helper:
1
2
3
4
5
6
7
8
9
Handlebars.registerHelper('each', function(context, options) {
var ret = "";

for(var i=0, j=context.length; i<j; i++) {
ret = ret + options.fn(context[i]);
}

return ret;
});
其实就是在helper中遍历了一次context。明白了这一点,我们就可以对其进行改造,实现自定义的迭代器了。如:
1
2
3
{{#list nav}}
<a href="{{url}}">{{title}}</a>
{{/list}}
context:
1
2
3
4
5
6
{
nav: [
{ url: "http://www.yehudakatz.com", title: "Katz Got Your Tongue" },
{ url: "http://www.sproutcore.com/block", title: "SproutCore Blog" },
]
}
阅读全文 »

# 场景 使用`{{expression}}`时,输出的内容会被转义,如:
1
<div>{{title}}</div>
context为
1
2
3
{
title: '<p>Hello world</p>'
}
结果生成html:
1
<div>&lt;Hello world&gt;</div>
最终在页面上显示的就是字符串`

Hello world

` 如果不想进行html的转义,有两种方法: * {{{ * SafeString # {{{ 在模板中将两个花括号替换成三个花括号,即可避免html字符串被转义
1
2
<div>{{title}}</div>
<div>{{{body}}}</div>
传入的context为
1
2
3
4
{
title: '<p>Hello world</p>',
body: '<p>Hello world</p>'
}
生成的结果:
1
2
<div>&lt;Hello world&gt;</div>
<div><p>Hello world</p></div>
页面上显示的就是
1
2
<p>Hello world</p>
Hello world
# SafeString Handlebars提供一个SafeString方法,使用这个方法返回的值即便在{{expression}}中也不会被转义 Handlebars模板:
1
{{sayhi}}
JavaScript:
1
2
3
4
Handlebars.registerHelper('sayhi', function(){
var str = '<p>Hello world</p>';
return new Handlebars.SafeString(str);
});
阅读全文 »

**Handlebars表达式是Handlebars模板的基本单元,可以单独在{{mustache}}中使用它,将它们传入Handlebars helper,或将它们作为hash arguments的值使用** # 基本使用
1
<h1>{{title}}</h1>
这个表达式的意思是:在当前上下文中查找`title`属性 Handlebars也可以使用`.`来分隔标识符,这类表达式被称为path
1
<h1>{{article.title}}</h1>
这个表达式的意思是:在当前上下文中查找`article`属性,并在查找结果中查找`title`属性 也支持用`/`来分隔,但不推荐使用 标识符可以是任何Unicode编码的字符,除了:
1
空格 ! " # % & ' ( ) * + , . / ; < = > @ [ \ ] ^ ` { | } ~
要引用一个不是合法标识符的属性,可以用方括号`[`,如:
1
2
3
4
5
6
{{#each articles.[10].[#comments]}}
<h1>{{subject}}</h1>
<div>
{{body}}
</div>
{{/each}}
上述`articles.[10].[#comments]`相当于JavaScript中的`articles[10]['#comments']` 当使用{{expression}}时,handlebars会转义其中的html内容,而使用{{{expression}}}时不会转义
1
2
3
4
5
6
7
Handlebars.registerHelper('link', function(str){
return '<span>'+ str +'</span>';
});

{{link 'hello'}} //<span>hello</span>

{{{link 'hello'}}} //hello
# Helpers handlebars helper相当于一个函数,先在js代码中注册一个helper:
1
2
3
Handlebars.registerHelper('link', function(str){
return '<span>'+ str +'</span>';
});
然后在模板文件中调用helper,第一个标识符为注册的helper的名称,在本例中为"link",后面跟着helper回调函数的参数,可以是0个或多个,用空格隔开
1
{{{link 'hello'}}}
此外,handlebars还可以接收一些可选的键值对序列作为helper回调函数最后一个参数的值(这在Handlebars中被称为hash arguments)。 hash arguments的key是一个普通的标识符,value则是一个Handlebars表达式,因此可以是标识符、path或字符串 模板文件中:
1
{{{hash 'hello' href='world'}}}
1
2
3
handlebars.registerHelper('hash', function(str, options){
console.log(options.hash);
});
输出
1
{ href: 'world' }
阅读全文 »

Handlebars介绍

Handlebars 是 JavaScript 一个语义模板库,通过对view和data的分离来快速构建Web模板。它采用”Logic-less template”(无逻辑模版)的思路,在加载时被预编译,而不是到了客户端执行到代码时再去编译, 这样可以保证模板加载和运行的速度。Handlebars兼容Mustache,你可以在Handlebars中导入Mustache模板。

在Express中使用

在Express中使用Handlebars,有一个hbs模块,对Handlebars进行了包装,可以代替Express自带的jade或ejs模板引擎

安装

1
npm install hbs --save

在app.js中设置view engine

1
app.set('view engine', 'hbs');

如果要在不同扩展名的文件中使用Handlebars(如.html文件)

1
2
app.set('view engine', 'html');
app.engine('html', require('hbs').__express);
阅读全文 »

问题

使用webpack进行打包时,发现bundle.js竟然有2M多。

解决办法

网上有去除插件、提取第三方库、压缩代码等方法。

还有一个比较容易忽略的原因就是开了sourcemap

在生产环境中,应使用devtool: false

关闭sourcemap后bundle.js的大小从2.46M降到302k

webpack bundle.js

参考

阅读全文 »

问题

某龙的笔试题,问console.log(+new Array(017));输出什么

第一反应是考察new Array()跟017

其实考察的是+

+运算符作为二元运算符时,有两个功能

  • 数字相加
  • 连接字符串

数字相加没啥好说的,连接字符串时,会先把两个参数都转换成字符串再进行连接。

+作为一元运算符时,会将参数转换为数字返回

结果

所以console.log(+new Array(017));输出的是NaN

阅读全文 »

用js写的根据前序、中序构造二叉树,并输出后序的一段代码,不知道有没有问题。

先上树:

1
2
3
4
5
6
7
       A
/ \
B C
/ \ / \
D E F G
/
H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
var preOrder = 'ABDHECFG';
var inOrder = 'HDBEAFCG';
var postOrder = '';

var tree = {};

create(preOrder, preOrder.length, inOrder, inOrder.length);
console.log(tree);

getPostOrder(preOrder[0]);
console.log(postOrder);

function create(preStr, preLen, inStr, inLen){
var root = preStr[0];
tree[root] = {};
tree[root].l = tree[root].r = null;

if(preLen == 1)
return root;

var rootInPos = inStr.indexOf(root);
var lStr = inStr.substr(0, rootInPos);
var rStr = inStr.substr(rootInPos + 1);
if(lStr.length > 0){
tree[root].l = create(preStr.substr(1), preStr.substr(1).length, lStr, lStr.length);
}
if(rStr.length > 0){
tree[root].r = create(preStr.substr(rootInPos + 1), preStr.substr(rootInPos + 1).length, rStr, rStr.length);
}

return root;
}

function getPreOrder(root){
if(root){
preOrder += root;
getPreOrder(tree[root].l);
getPreOrder(tree[root].r);
}
}

function getInOrder(root){
if(root){
getInOrder(tree[root].l);
inOrder += root;
getInOrder(tree[root].r);
}
}

function getPostOrder(root){
if(root){
getPostOrder(tree[root].l);
getPostOrder(tree[root].r);
postOrder += root;
}
}

输出结果:

1
2
3
4
5
6
7
8
9
10
{ A: { r: 'C', l: 'B' },
B: { r: 'E', l: 'D' },
D: { r: null, l: 'H' },
H: { r: null, l: null },
E: { r: null, l: null },
C: { r: 'G', l: 'F' },
F: { r: null, l: null },
G: { r: null, l: null } }
HDEBFGCA

阅读全文 »

来源

今年某度校招笔试题

题目

1
2
3
4
5
(function(){
var x=y=1;
})();
console.log(x);
console.log(y);

答案是:
ReferenceError跟1

因为x是用var声明的,所以在函数外无法访问,而y不是。

一个小坑,记录一下。

阅读全文 »

问题来源

昨天早上某面试提出的一个问题,脑子一热漏写了一个条件,心塞。

问题大概是写一个两列布局,左边固定,高度都是默认填满页面,右边内容高度超出浏览器窗口出现滚动条。

解决办法

今天仔细想了下,用浮动做的话,高度不好弄成填满的。折腾了一会儿,搞出两种方案(不使用js的)。

  • 左侧:fixed,右侧:absolute,min-height:100%,width为calc(100% - [左侧的width]),同时margin-left也为左侧的width
  • html的overflow-x设置为hidden,右侧就可以不用calc了,直接width: 100%,不过这样的话,右侧元素使用margin 0 auto居中就会向右边偏移,偏移的长度为左侧的width

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>test layout</title>
<style type="text/css">
*{
padding: 0;
margin: 0;
}
/*html{
overflow-x:hidden;
}*/ /*方法2*/
.left{
position: fixed;
top: 0;
left: 0;
width: 100px;
height: 100%;
background-color: red;
}
.right{
position: absolute;
width: calc(100% - 100px); /*方法1*/
/*width: 100%;*/ /*方法2*/
min-height: 100%;
margin-left: 100px;
background-color: blue;
}
.center{
width: 100px;
background-color: yellow;
margin: 0 auto;
}
</style>
<script>
window.onload = function(){
var addBtn = document.getElementsByClassName('js-add-btn')[0];
var delBtn = document.getElementsByClassName('js-del-btn')[0];
var right = document.getElementsByClassName('right')[0];
addBtn.onclick = function(e){
var pNode = document.createElement('p');
pNode.innerText = 'content';
for(var i = 0; i < 20; i++){
var cpNode = pNode.cloneNode(true);
right.appendChild(cpNode);
}
}
delBtn.onclick = function(e){
var children = right.children;
var len = children.length;
var delCount = len > 20 ? 20 : len;
for(var i = 0; i < delCount; i++){
right.removeChild(children[len - (i + 1)]);
}
}
}
</script>
</head>
<body>
<div class="left">
<p>left</p>
<button class="js-add-btn">增加右侧内容</button>
<button class="js-del-btn">删除右侧内容</button>
</div>
<div class="right">
<div class="center">
<p>centered content</p>
</div>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
<p>lots of content</p>
</div>
</body>
</html>

jsfiddle: https://jsfiddle.net/g9j8mcf4/1/

阅读全文 »

来源

今年某前端笔试的一道题,大概就是实现一遍filter,包括一个可以改变上下文的要求,其实就是改变this啦,跟原生的filter一样的功能跟参数。

解析

filter的功能就是过滤,传入一个函数作为条件,返回true则将元素加入最终返回的数组中。

实现

1
2
3
4
5
6
7
8
9
10
11
Array.prototype.filter = function(cb, context){
context = context || this; //确定上下文,默认为this
var len = this.length; //数组的长度
var r = []; //最终将返回的结果数组
for(var i = 0; i < len; i++){
if(cb.call(context, this[i], i, this)){ //filter回调函数的三个参数:元素值,元素索引,原数组
r.push(this[i]);
}
}
return r;
};

要点

个人觉得考察的是call的使用

阅读全文 »

应用层协议、基于tcp

HTTP/0.9

命令

GET

特点

  • 服务器只能回应HTML字符串
  • 服务器发送完毕后就关闭tcp连接

HTTP/1.0

命令

GET POST HEAD

特点

阅读全文 »

这个老问题,网上普遍都有了,为什么要再写一遍呢,主要是为了记个笔记。。。

遍历时搜索结果数组

思路很明确,如下

  • 新建一个数组存放结果
  • 循环遍历原数组,对于每一个元素,在结果数组中搜索是否存在
  • 若不存在则存入结果数组中,返回第二步,直到循环结束

代码就不上了,网上一大把。

这是最直接的方法,但由于嵌套了循环,效率不高。

先排序后比较

  • 先将原数组进行排序
  • 新建一个结果数组
  • 遍历排序后的数组,比较第i个元素与结果数组的最后一个元素是否相等
  • 如果不相等则存入结果数组

同不上代码。

速度是快了些,但返回的是一个排序后的数组,并且有更快的方法。

阅读全文 »

问题的发现

最近搞一个页面,用div直接包裹了两个button,本以为很寻常的东西,div的高度却被莫名其妙的撑开了。

1
2
3
4
5
6
7
8
9
10
11
<style>
html{
font-size: 100px;
}
button{
font-size: 0.16rem;
}
</style>
<div style="background-color:aqua;">
<button>Button 1</button>
</div>

想来想去怀疑是line-height的问题,于是查了一下,搜到zxx的一篇文章CSS深入理解vertical-align和line-height的基友关系

于是把div的line-height设置成0,button的vertical-align设置成top或bottom,问题解决。

1
2
3
4
5
6
7
8
9
10
11
<style>
#div2{
line-height: 0;
}
#btn2{
vertical-align: top;
}
</style>
<div id="div2" style="background-color:aqua;">
<button id="btn2">Button 2</button>
</div>

不过vertical-align设置成middle时button距离上边会有1px的间隙。

1
2
3
4
5
6
7
8
9
10
11
<style>
#div3{
line-height: 0;
}
#btn3{
vertical-align: middle;
}
</style>
<div id="div3" style="background-color:aqua;">
<button id="btn3">Button 3</button>
</div>

研究中…

贴上测试代码

阅读全文 »

声明:本篇blog部分内容摘自阮一峰老师的ECMAScript 6入门,全部内容参考自上述链接

声明变量的方法

var function let const import class
作用域 函数或全局 顶层、函数和块级作用域 所在代码块 所在代码块 - -
变量提升 存在 存在 不存在 不存在 存在 不存在
暂时性死区
重复声明 允许 允许 不允许 不允许 - 不允许
值可变 -
属于全局对象 -

作用域

可访问到变量的代码区块

1
2
3
4
5
6
7
{
let a = 10;
var b = 1;
}

a // ReferenceError: a is not defined.
b // 1

变量提升

不存在变量提升的声明方式,变量一定要在声明后使用,否则会报错。

1
2
3
4
5
console.log(foo); // 输出undefined
console.log(bar); // 报错ReferenceError

var foo = 2;
let bar = 2;

暂时性死区

阅读全文 »

看了几篇文章,理一下网易跟淘宝移动端适配的思路,主要是参考 从网易与淘宝的font-size思考前端设计稿与工作流

像素相关概念

物理像素(physical pixel)

一个物理像素是显示器(手机屏幕)上最小的物理显示单元,在操作系统的调度下,每一个设备像素都有自己的颜色值和亮度值。

其值也就是我们常说的分辨率

设备独立像素(density-independent pixel)

设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如: css像素),然后由相关系统转换为物理像素。

简称dip,也可以称为CSS像素

设备像素比(device pixel ratio)

设备像素比(简称dpr)定义了物理像素和设备独立像素的对应关系,它的值可以按如下的公式的得到:

阅读全文 »

tl;dr

1
2
firewall-cmd --permanent --zone=public --add-port=2888/tcp
firewall-cmd --reload #重新载入服务

永久配置firewalld开启端口。

之前的一些坑

之前的一篇文章CentOS 7部署Node.js+MongoDB:在VPS上从安装到Hello world中,讲到了CentOS开启端口用这个命令

1
firewall-cmd --add-port=3000/tcp

这样是没错,开启了端口,但是后面发现这个端口会莫名其妙的被关闭

Google一番后了解到这样添加端口是运行时配置(Runtime configuration),在重载或重启firewalld后,这个配置就失效了。

自动关闭原因

CentOS 7 采用了firewalld作为防火墙服务,在Red Hat官方文档的Security Guide中有介绍firewalld

阅读全文 »