JS实现日历

最近在捣鼓一个chrome插件,包括两个功能:1.倒计时,2.日历。

大致是下面这个样子:

倒计时模式

日历模式

倒计时模式倒还简单,日历刚开始以为困难点,仔细分析后也还挺顺利。

写过日历的一般都知道有三点很重要:

1.一个月中有几天
2.一个月中第一天星期几
2.一个月中第后一天星期几
3.正确的处理换行

从我写这个日历的思路开始:

1.刚开始思路有点乱,想着既要输出月份,又要输出月中的天数,还要处理各种换行,好多事。后来我就想倒退吧,先输出一个月的,如果指定月份的日历输出了,下面就是循环遍历月份就行了。

下面是三月份的日历输出代码:

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
let today = new Date(),
year = today.getFullYear(),
month = today.getMonth();
// ❌
let dayStr = '';
// 3月有31天
let dayInMonth = 31;
// 每个月的第一天
let firstDay = new Date(year,month,1);
// 每个月的最后一天
let lastDay = new Date(year,month,31);
//第一天星期几(0-6)
let weekday = firstDay.getDay();
// 当月的最后一天星期几
let lastDayWeekDay = lastDay.getDay();
// 每一个都是从1号开始
let date = 1;
// ❌
// 补齐前面的空格
for(let i = 0; i < weekday; i++){
dayStr += '+ ';
}
for(;date <= dayInMonth;date++){
dayStr += date + ' ';
weekday++
// 换行处理
if(weekday%7 == 0){
weekday = 0;
dayStr += '\n';
}
}
// 补齐后面的空格
for(let j = 0; j < (7 - lastDayWeekDay - 1); j++){
dayStr += '+ ';
}

可以把上面代码拷贝到控制台执行,看下效果。

可能看上去还不像日历,日历是有头的,周几,周几,把下面代码分别加入上面代码❌处。

let weeks = ['日','一','二','三','四','五','六'];

dayStr += weeks.join(' ') + '\n';

这样就比较像了。其实讲到这里基本日历就差不多了,还有一个重要的方法,就是算出指定月份的天数,其实JS的 Date 里没有给出api,所以需要自己算。
好忧伤,我查了一下python里的日历相关的给了方法。但是JS里有一个 getDate() 方法获取月份中的第几天。经过网上的搜索,得到如下方法:

function daysInMonth(month, year) {
  return new Date(year, month + 1, 0).getDate();
}

我来解释一下:当我们尝试传入0(月份是 0-11 )一月份,2017,得到 new Date(2017,1,0)。这代表是2月份的第0天,好奇怪,哪有第0天的?其实某月的第0天就是前一个月的最后一天,所以就得到了某月的天数。

完整代码如下:

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
function daysInMonth(month, year) {
return new Date(year, month + 1, 0).getDate();
}
let weeks = ['日','一','二','三','四','五','六'];
let year = new Date().getFullYear();
let dayStr = '';
for(let month = 0; month <=11; month++){
// 每个月的第一天
let firstDay = new Date(year,month,1);
let dayInMonth = daysInMonth(month,year);
// 每个月的最后一天
let lastDay = new Date(year,month,dayInMonth);
// 第一天星期几(0-6)
let weekday = firstDay.getDay();
// 最后一天星期几
let lastDayWeekDay = lastDay.getDay();
// 每一个都是从1号开始
let date = 1;
dayStr += weeks.join(' ') + '\n';
// 补齐前面的空格
for(let i = 0; i < weekday; i++){
dayStr += '+ ';
}
for(;date <= dayInMonth;date++){
dayStr += date + ' ';
weekday++
if(weekday%7 == 0){
weekday = 0;
dayStr += '\n';
}
}
// 补齐后面的空格
for(let j = 0; j < (7 - lastDayWeekDay - 1); j++){
dayStr += '+ ';
}
dayStr += '\n\n';
}

参考:

1.http://stackoverflow.com/questions/315760/what-is-the-best-way-to-determine-the-number-of-days-in-a-month-with-javascript
2.https://github.com/lishengzxc/bblog/issues/5

Vue组件通信

父->子:props

子->父: emit

兄弟:

子->父->子

全局:

非直接父->子:broadcast
非直接子->父:dispatch

VPS网站搭建

在搬瓦工买了一个VPS只装了一个Shadowsocks用来翻墙,实在是浪费。凑巧我有几个域名,就把搭建网站的简单过程走一遍,学习一下服务端的知识。

刚开始的疑问:

1.一个VPS(单IP)如何部署多个应用程序(不同的端口,且非80端口)?
2.二级域名如何配置?

需要的东西:

一个空间和多个域名

我首先在空间上跑了一个简单的NodeJS程序,端口3000,然后直接用IP + port 可以访问,然后我就到域名服务商的域名管理那里添加域名解析,将域名解析到对应的IP,然后成功访问。刚开始我以为可以直接在那里添加端口,然后映射到不同程序呢。然后搜了一些资料貌似不是这样的,基本是用Nginx、Apache做转发。
这就基本解决了第一个问题:一个VPS(单IP)如何部署多个应用程序(不同的端口,且非80端口)?

具体如何做呢?(centos)

1.首先安装Nginx

sudo yum install epel-release
sudo yum install nginx

2.启动Nginx:

sudo /etc/init.d/nginx start

3.配置Nginx:

http{
    server {
        listen 80;
        server_name a.com;
        location / {
            proxy_pass http://localhost:8080;
        }
    }
    server {
        listen 80;
        server_name b.com;
        location / {
            proxy_pass http://localhost:8081;
        }
    }
}

当请求过来的时候Nginx首先拿到请求,然后根据域名分发到不同的应用服务器(不同端口)

4.重新加载配置

nginx -s reload

二级域名如何玩呢?

本来以为会很难,其实也很简单。类似上面解析域名的操作,添加一个A记录,然后主机名填你想填的比如:blog、mail、bbs等,然后到Nginx配置一下server_name:

server {
    listen 80;
    server_name blog.b.com;
    location / {
        proxy_pass http://localhost:8081;
    }
}

然后就可以访问了!

还有一点如何让NodeJS程序一直跑着?就是我退出终端或程序异常中断等,这里我选择了:PM2,其实还有好多选择 nodemon 、forever 等没有做过对比,有时间在看看区别。

pm2 start app.js

参考资料:

http://www.west.cn/cms/news/domain/2014-10-22/1404.html

https://segmentfault.com/q/1010000003756513

https://segmentfault.com/q/1010000004112942

http://httpd.apache.org/docs/current/vhosts/examples.html

https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-centos-6-with-yum

https://www.npmjs.com/package/pm2

JavaScript Template实现

模板引擎做了两件事:

  1. 拼接字符串
  2. 执行字符串(new Function)

var re = /<%([^%>]+)?%>/g;

这句正则表达式会捕获所有以<%开头,以%>结尾的片段。

dp&sp&dpi&pt

dp

Density-independent Pixels - An abstract unit that is based on the physical density of the screen. These units are relative to a 160 dpi (dots per inch) screen, on which 1dp is roughly equal to 1px. When running on a higher density screen, the number of pixels used to draw 1dp is scaled up by a factor appropriate for the screen’s dpi. Likewise, when on a lower density screen, the number of pixels used for 1dp is scaled down. The ratio of dp-to-pixel will change with the screen density, but not necessarily in direct proportion. Using dp units (instead of px units) is a simple solution to making the view dimensions in your layout resize properly for different screen densities. In other words, it provides consistency for the real-world sizes of your UI elements across different devices.

sp

Scale-independent Pixels - This is like the dp unit, but it is also scaled by the user’s font size preference. It is recommend you use this unit when specifying font sizes, so they will be adjusted for both the screen density and the user’s preference.

pt

Points - 1/72 of an inch based on the physical size of the screen, assuming a 72dpi density screen.

px

Pixels - Corresponds to actual pixels on the screen. This unit of measure is not recommended because the actual representation can vary across devices; each devices may have a different number of pixels per inch and may have more or fewer total pixels available on the screen.

mm

Millimeters - Based on the physical size of the screen.

in

Inches - Based on the physical size of the screen.

单位换算

https://www.w3.org/Style/Examples/007/units.en.html

1in = 2.54cm = 25.4mm = 72pt = 6pc

ES6的6个小特性(二)

继上一篇的 《Six Tiny But Awesome ES6 Features》,这次我再分享6个可以减少代码和最大化效率的方法。

1.Object Shorthand

新的对象声明方法允许我们可以不声明对象的 key :

var x = 12;
var y = yes;
var z = {one:'1',two:'2'};

// The old way
var obj = {
    x:x,
    y:y,
    z:z
}
// The new way
var obj = {x,y,z};

2.Method Properties

避免 function 关键字声明函数:

var davidwalsh = {
    makeItHappen(param){
        // do stuff
    }
}

必须承认去除掉 function 关键字确实使代码简洁、更好维护。

3.Blocks vs Immediately Executed Functions

下面创建立即执行方法的模式有点难看:

(function(){
    // do stuff
})();

通过ES6我们可以通过 {} 和 let 来创建块级作用于,完成立即执行函数的作用:

{
    let j = 12;
    let divs = document.querySelectorAll('div');

    // do stuff
}

j; // ReferenceError: j is not defined...

如果在 Block 内部声明函数,它将会被外部访问到。但你如果使用 let 关键字声明函数自变量,将不使用括号的情况下实现 IEF 的功能。

4. for loops and let

因为在JS里面会存在变量提升,我们经常会在作用域前面声明一些”无用”的迭代变量,例如(for var x = …)。ES6 使用 let 解决了此恼人的问题:

for(let x = 0; x < len; i++){
    //do stuff
}

x; // ReferenceError: x is not defined

不久以后 let 会被应用的更多。

5.get and set for Classes

class Cart{
    constructor(total){
        this._total = total;
    }
    get total(){return this._total;}
    set total(v){this._total = Number(v);}
}

var cart = new Cart(100);

cart.total // 100

能为属性设置 get、set 是这部分最棒的。不需要使用函数来进行特殊的设定–当执行 obj.prop = {value} 时,一切都会自动执行。

6.startsWith,endsWith and includes

"MooTools".startsWith("Moo"); // true;
"MooTools".startsWith("moo"); // false;

"MooTools".endsWith("Tools"); // true;

"MooTools".includes("oo"); // true;

注:includes 方法兼容性还是很多,曾有一个线上bug,就是因为不支持此方法导致的。

原文:https://davidwalsh.name/es6-features-ii/amp

ES6的6个小特性

JS社区的每个人都喜欢新的API、语法以及一些简单、明了更高效的完成重要任务的新特性。过去一年ES6带来了十足的进步,下面是6个我最喜欢的JS新增特性。

1.Object[key]

有时候不能在对象变量声明时设置所有的key/value,所以得再声明之后添加key/value。

let myKey = 'key3';
let obj = {
    key1: 'One',
    key2: 'Two'
};
obj[myKey] = 'Three';

往好的说这有点不方便,往坏的说这种方式令人疑惑而且有点丑陋。ES6提供给开发者一种更优雅的方式:

let myKey = 'variableKey';
let obj = {
    key1: 'One',
    key2: 'Two',
    [myKey]: 'Three' /* yay! */
};

开发者可以使用[]包裹变量从而使用一条语句完成所有的功能。

2.Arrow Functions

你不需要跟上ES6的所有改变,箭头函数已经是许多讨论的话题并且也给JS开发者带来了一些困惑。即使我可以写很多博文来说箭头函数的特点,但是我想指出箭头函数是如何提供一个为简单函数压缩代码的方法。

// Adds a 10% tax to total
let calculateTotal = total => total * 1.1;
calculateTotal(10) // 11

// Cancel an event -- another tiny task
let brickEvent = e => e.preventDefault();
document.querySelector('div').addEventListener('click', brickEvent);

functionsreturn关键词,有时甚至不需要添加(),箭头函数为写函数提供了一种简短的代码书写方式。

find/findIndex

JS为开发者提供了Array.prototype.indexOf方法来获取数组中的指定元素下标,但是indexOf并没有提供一个根据判断条件来获取指定元素的方法,findfindIndex两个方法提供了取出第一个满足计算条件的元素和下标。

let age = [12,19,6,4];

let firstAdult = ages.find(age => age >= 18); // 19
let firstAdultIndex = ages.findIndex(age => age >= 19); // 1

…扩展修饰符

扩展修饰符表示数组和可迭代对象在调用的时候应该拆分成单个参数:

// Pass to function that expects separate multiple arguments
// Much like Function.prototype.apply() does
let numbers = [9, 4, 7, 1];
Math.min(...numbers); // 1

// Convert NodeList to Array
let divsArray = [...document.querySelectorAll('div')];

// Convert Arguments to Array
let argsArray = [...arguments];

这个特定的另一个红利可以把可迭代对象(NodeListarguments)变成真的数组,以前我们经常使用Array.from或其他方法实现的。

Template Literals

JS里多行字符起初通过+\来完成的,但是都很难维护。许多开发者甚至一些框架使用<script>标签来容纳模板,然后使用DOM方法的outerHTML来获取HTML字符。

ES6提供了Template Literals使用反引号来容易的创建多行字符串:

// Multiline String
let myString = `Hello

I'm a new line`;

//Basic interpolations
let obj = {x:1,y:2};

console.log(`Your total is: ${obj.x + obj.y}`); // Your total is 3

Default Argument Values

为函数参数提供默认值在服务端语言已经提供(python、php),现在JS也有此能力:

//Basic usage

function great( name = 'Anon' ){
    console.log(`Hello ${name}`);
}

great(); // Hello Anon!

//You can have a function too!

function greet( name = 'Anon',callback = function(){} ){
    console.log(`Hello ${name}!`);
    // No more "callback && callback()" (no conditional)
    callback();
}

// Only set a default for one parameter
function greet(name, callback = function(){}) {}

以上列出的6个特性就是ES6提供给开发者,当然还有许多特性。

评论里提供的:

1 .

const isRequired = () => {throw new Error('param is required');};

const hello = (name = isRequired()) => { console.log(`hello ${name}`) };

2 .

const is = {
    get required(){
        throw new Error('Required argument')
    }
}

import {is} from 'utils'

const foo(name = is.required) => Array.from(name)

原文:https://davidwalsh.name/es6-features