Coder Social home page Coder Social logo

recordum's People

Contributors

loeify avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

recordum's Issues

yukar - Chrome Extension JavaScript Code Editor

yukar 是一个前端代码编辑预览工具,是一个 chrome 插件。你可以从 chrome web store 上安装

https://chrome.google.com/webstore/detail/yukar/ilbmpnheigbnilnbknenakbkkdmaemlp

为什么要造这个轮子

  1. 有很多在线代码编辑预览工具,类似 jsfiddle,codepen,但都不能离线使用,还经常一些资源被墙

  2. js 新特性支持度不完整,很多都不支持 vue 的 JSX

  3. 一些类似插件不能跳过 CSP(Content Security Policy)资源加载

  4. 在线编辑器在复制黏贴测试代码需要来回切换 tab,很不方便

  5. umd 模块资源可能不可用

功能介绍

  1. ES6/7 的新特性支持
  • Async/Await
  • Class Properties
  • Object Rest Spread
  • Decorators
  1. React JSX /Vue JSX 支持

  2. 保存代码记录

  3. Console 记录支持

相关图片

screen shot 2018-05-23 at 10 39 15 am

screen shot 2018-05-23 at 10 38 30 am

screen shot 2018-05-23 at 10 38 10 am

screen shot 2018-05-23 at 10 38 01 am

screen shot 2018-05-23 at 10 37 50 am

Markdown Test

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi aliquam neque vitae ornare luctus. Nunc vestibulum eget felis ut condimentum. Nunc vel tincidunt quam.

An h1 header

Paragraphs are separated by a blank line.

2nd paragraph. Italic, bold, and monospace. Itemized lists
look like:

  • this one
  • that one
  • the other one

Note that --- not considering the asterisk --- the actual text
content starts at 4-columns in.

Block quotes are
written like so.

They can span multiple paragraphs,
if you like.

Use 3 dashes for an em-dash. Use 2 dashes for ranges (ex., "it's all
in chapters 12--14"). Three dots ... will be converted to an ellipsis.
Unicode is supported. ☺

An h2 header

Here's a numbered list:

  1. first item
  2. second item
  3. third item

Note again how the actual text starts at 4 columns in (4 characters
from the left side). Here's a code sample:

# Let me re-iterate ...
for i in 1 .. 10 { do-something(i) }

As you probably guessed, indented 4 spaces. By the way, instead of
indenting the block, you can use delimited blocks, if you like:

define foobar() {
    print "Welcome to flavor country!";
}

(which makes copying & pasting easier). You can optionally mark the
delimited block for Pandoc to syntax highlight it:

import time
# Quick, count to ten!
for i in range(10):
    # (but not *too* quick)
    time.sleep(0.5)
    print i

An h3 header

Now a nested list:

  1. First, get these ingredients:

    • carrots
    • celery
    • lentils
  2. Boil some water.

  3. Dump everything in the pot and follow
    this algorithm:

    find wooden spoon
    uncover pot
    stir
    cover pot
    balance wooden spoon precariously on pot handle
    wait 10 minutes
    goto first step (or shut off burner when done)
    

    Do not bump wooden spoon or it will fall.

Notice again how text always lines up on 4-space indents (including
that last line which continues item 3 above).

Here's a link to a website, to a local
doc
, and to a section heading in the current
doc
. Here's a footnote 1.

Tables can look like this:

size material color


9 leather brown
10 hemp canvas natural
11 glass transparent

Table: Shoes, their sizes, and what they're made of

(The above is the caption for the table.) Pandoc also supports
multi-line tables:


keyword text


red Sunsets, apples, and
other red or reddish
things.

green Leaves, grass, frogs
and other things it's
not easy being.


A horizontal rule follows.


Here's a definition list:

apples
: Good for making applesauce.
oranges
: Citrus!
tomatoes
: There's no "e" in tomatoe.

Again, text is indented 4 spaces. (Put a blank line between each
term/definition pair to spread things out more.)

Here's a "line block":

| Line one
| Line too
| Line tree

and images can be specified like so:

example image

Inline math equations go in like so: $\omega = d\phi / dt$. Display
math should get its own line and be put in in double-dollarsigns:

$$I = \int \rho R^{2} dV$$

And note that you can backslash-escape any punctuation characters
which you wish to be displayed literally, ex.: foo, bar, etc.

Footnotes

  1. Footnote text goes here.

Adobe CEP 扩展

Adobe 系列通常情况下宿主应用是不会运行未经签名扩展的,只有打包并签名才可以运行。但是可以打开开发者模式

启用开发者模式

Windows

打开到注册表定位到: ( 高版本类推 )

  • CC 2014: HKEY_CURRENT_USER\Software\Adobe\CSXS.5
  • CC 2015: HKEY_CURRENT_USER\Software\Adobe\CSXS.6

PlayerDebugMode 设置为 1

macOS

终端输入: ( 同样高版本类推 )

defaults write com.adobe.CSXS.6 PlayerDebugMode 1

扩展签名打包

使用 Adobe 官方提供的 ZXPSignCmd
https://github.com/Adobe-CEP/CEP-Resources/tree/master/ZXPSignCMD

71097-6671c44f605ce86a

以下为 macOS 下操作,Windows 类似。先进入文件目录

创建证书

./ZXPSignCmd -selfSignedCert <countryCode> <stateOrProvince> <organization> <commonName> <password> <outputPath.p12>
./ZXPSignCmd -selfSignedCert <国家代码> <地区> <组织名> <证书所有者名称> <证书密码> <证书名.p12>

# example
./ZXPSignCmd -selfSignedCert CN guangzhou lorem.in loeify aksdj4 lorem.p12

签名并打包

./ZXPSignCmd -sign <inputDirectory> <outputZxp> <p12> <p12Password>
./ZXPSignCmd -sign <要打包的项目目录> <输出文件路径> <证书路径> <证书密码>

# example
./ZXPSignCmd -sign xxx xxx.zxp lorem.p12 aksdj4

打包生成后的 zxpzip 一样的可以解压

手动安装插件

目录

将插件解压,放进目录

Windows

C:\Program Files\Common Files\Adobe\CEP\extensions\

macOS ( 注意是全局 Library,不是用户的 )

/Library/Application Support/Adobe/CEP/extensions/

注意最终插件 xxx 放入目录最终应该存在 /extensions/xxx/index.html

启用

重启 photoshop,选择 "Window" → "Extensions" → "xxx" 启用

参考文章

关于 react-router 的 browserHistory 模式

SPA 项目基本上都会用到路由 router。react 还有 vue 对应有其路由插件。 react-router 还有 vue-router 都有 hashHistory 和 browserHistory 模式。这里大概说一下两者区别

  • hashHistory: 不需要服务器配置,在 URL 生成一个 hash 来跟踪状态,通常在测试环境使用,也可以作为发布环境使用
  • browserHistory: 需要服务器端做配置,路径是真实的URL,是 react-router 官方推荐首选

大多数情况下,browserHistory 模式明显是优于 hashHistory 模式的,但 browserHistory 需要一定的配置

配置 browserHistory

可以看出,hashHistory 不需要什么配置,但 browserHistory 需要服务端支持,这里简单说一下两种方式做支持,其它方式基本上都是类似

使用 express

const app = express()
app.get('*', function (request, response){
  response.sendFile(path.resolve(__dirname, 'index.html'))
})

使用 nginx

server {
  ...
  location / {
    try_files $uri /index.html
  }
}

这里说明一下为什么要这样设置,browserHistory 模式下,URL 是指向真实 URL 的资源路径,当通过真实 URL 访问网站的时候(首页),这个时候可以正常加载我们的网站资源,而用户在非首页下手动刷新网页时,由于路径是指向服务器的真实路径,但该路径下并没有相关资源,用户访问的资源不存在,返回给用户的是 404 错误

通过上面所说的原理,简单起来说就是 browserHistory 模式下,需要每个路由下都要有对应的资源存在,就不会产生 404 错误,所以如果不借助服务端的话,又要实现这种模式,这种场景在自己不能配置服务器时候会碰到,例如把项目部署到 GitHub pages 上。那该怎么办呢

那么就产生 对应资源

所以,我们的做法就是在每个 路由路径 下,都放置一个跟首页一样的 index.html

下面是做法,当然也是有各种方式的,都是可以类推的

假定我们有以下的路由设定,这里以 react-router 为例子

export default (
  <Route path="/" component={App}>
    <IndexRoute component={HomePage} />
    <Route path="contact-us" component={ContactPage} />
    <Route path="dashboard">
      <IndexRoute component={Verify(Dashboard)} />
      <Route path="inbox" component={Verify(Inbox)} />
      <Route path="conversation" component={Verify(ComposeMessage)} />
    </Route>
    <Route path="*" component={NotFound} />
  </Route>
)

那么就可以路由路径为

// routes.js
const routes = [
  'contact-us',
  'dashboard',
  'dashborad/inbox',
  'dashboard/conversation'
]

module.exports = routes

接下来我们就把生成的 index.html 复制到这几个路径下就可以了

// deploy.js
const fs = require('fs-extra')
const routes = require('routes.js')
const path = require('path')
routes.forEach((route) => {
  fs.copySync('index.html', path.join(route, 'index.html'))
})

这样用户访问就不会出现 404 了,SPA 的功能也不受影响,为了方便我们可以把这个生成工具集成到 package.json

{
  "script": {
    "build": "NODE_ENV=production webpack --progress && node deploy.js"
  }
}

ok, 当我们运行 npm run build 时候,就会同时生成对应路径下的 index.html,这样就可以了完成我们所需要的功能了

问题 & 思考

看到这里,应该会有一个疑问,如果 routes 中有一些是不能穷举的路径要怎么办?例如 <Route path="posts/:id" component={Verify(Inbox)} />。这时候是没办法生成对应资源的

不过还是可以使用以下 hack 方式:

直接使用服务端 404 页面了,如果是用 GitHub pages 的话,我们可以直接生成一个 404.html 即可,直接把 404 页面弄成跟 index 内容一样,404 时候就是正常的内容页面,这时候页面功能是正常的,并且不需要前面的一堆做法了。

Mirror - 基于 issues 的博客工具

Mirror 是一个简单的博客工具,基于 GitHub API 获取 issues 数据,然后展示在页面上

该工具的方便之处在于只需要在 issue 上写你的博客文章,你的网站会自动更新博客内容

借助 GitHub,你可以轻松的用 markdown 书写你的博客内容,永久保存,不用担心数据丢失问题。还可以非常方便上传博客图片,拖入编辑器即可。

该博客工具非常适合以 issue 作为自己博客的用户,无痛生成博客网站,对原来内容毫无影响

Mirror 还支持多用户协作,你可以方便的设置哪些用户写的内容可以显示在博客网站上,避免无关内容

Mirror 在移动端同时有很好的浏览体验

预览地址

http://mirror.am0200.com/

项目地址

https://github.com/LoeiFy/Mirror

新版本使用 GitHub GraphQL API

REST API 版本:https://github.com/LoeiFy/Mirror/tree/rest-api

更详细的介绍可以看项目说明

如何使用

使用很简单,你可以直接下载资源包,下载最新的 release,然后打开 index.html 进行配置即可。

中文教程

配置好后,可以先尝试本地预览,需要一个本地服务器,放上去访问 index.html 即可,测试没问题就可以把全部文件上传到对应地址即可,也可以放到 GitHub pages 上

名字来源

MirrorDJ Okawari 所作的专辑

mirror

旧 webkit bug : css 伪类不支持 css3 动画

之前一个网站做一个css3加载动画,为了“节省” html ,就直接在 body 上使用伪类来做。

相关代码是这样的:

html, body {
    background: #fff;
    height: 100%;
    font-size: 100%;
}
body {
    overflow: hidden;
    position: relative;
}
body:before, body:after {
    content: '';
    width: 30px;
    height: 30px;
    display: block;
    border: 3px solid #d2d2d2;
    border-radius: 50%;
    -webkit-border-radius: 50%;
    -moz-border-radius: 50%;
    position: absolute;
    left: 50%;
    margin-left: -18px;
    top: 50%;
    margin-top: -18px;
}
body:after {
    border: 3px solid transparent;
    border-top-color: grey;
    -webkit-animation: rotate 1s infinite linear;
    -moz-animation: rotate linear 1s;
    -moz-animation-iteration-count: infinite;
}
@-webkit-keyframes rotate {
    from { -webkit-transform: rotate(0deg); }
    to { -webkit-transform: rotate(360deg); }
}

@-moz-keyframes rotate {
    from { -moz-transform: rotate(0deg); }
    to { -moz-transform: rotate(360deg); }
}

预览地址:http://jsbin.com/wilemolage/1/edit?html,css,output
效果还不错,并且 html 结构也很好。但是在 iOS 6 上转圈动画不动。
就觉得很奇怪,排除代码错误。于是 Google 一番:
Transitions and animations do not apply to CSS ::before and ::after pseudo-elements

相关链接:

http://css-tricks.com/pseudo-element-animationstransitions-bug-fixed-in-webkit/

使用 setTimeout 排序

原理就是将要排序的数组的每一个项作为 setTimeout 时间参数,然后就可以排序了

排序时间跟数组最大值绝对值有关 :)

需要对数组的负数项做一下处理,因为 setTimeout 参数负数的话跟参数 0 是一样的

例子 JSFiddle

具体代码说明:

// 需要排序数组
const numbers = [8, 0, 3, -1, 9, -3, -767, 4, 111, 999, 89];

async function sortArr(arr) {
  const left = arr.filter(a => a < 0).map(a => a * -1) // 获取数组负数项并转成正数
  const right = arr.filter(a => a >= 0) // 数组正数项
  const sortLeft = (await sort(left)).map(a => a * -1).reverse() // 负数项排序后需要反向
  const sortRight = await sort(right) // 正数项排序
  
  return sortLeft.concat(sortRight)
} 

function sort(arr) {
  return new Promise((resolve) => {
    let len = arr.length
    const back = []
    
    arr.forEach(item => {
      setTimeout(() => {
        back.push(item)
        len -= 1
    	if (len === 0) {
          resolve(back) // 完成排序
        }
      }, item) // 以每个项作为时间
    })
  })
}

;(async () => {
  document.body.innerHTML = 'Before: ' + numbers.join(', ') + '<br>After: ' + (await sortArr(numbers)).join(', ')
})()

// 排序结果: [-767, -3, -1, 0, 3, 4, 8, 9, 89, 111, 999]

加载图片获取宽高问题

浏览器在加载图片过程中,可能很早就获得图片宽高,这时候可以用 js 获取宽高,而不用在 onload 时候获得

var img = new Image();
img.src = 'xxx.jpg?'+ +new Date();

// interval
var check = function(){
    console.log('unload:'+ img.width +'####'+ img.height)
}
var set = setInterval(check,40);

// loaded
img.onload = function(){
    console.log('loaded:'+ img.width +'####'+ img.height)
    clearInterval(set)
}

黑苹果

也算是完成了读书时候的心愿,以前读书时候老想着弄个黑苹果,但是一直没有成功。最近折腾安装前后花的时间就两三天那样,参考了一堆前人经验,所以不会很折腾,总体上算是完美的

黑苹果情况

screen shot 2017-02-04 at 10 30 35 am

正常部分

  • 显卡(HD530),声卡,网卡驱动正常
  • USB 3 识别正常
  • CPU 可以变频
  • SSD TRIM 正常

问题

  • 不能休眠/睡眠,因为是台式机,不理会
  • 开机偶尔会出现禁止符号,拔掉/换接口 usb 就可以,应该是 usb 驱动问题吧,经常不关机不理会
  • 开机过程会有一瞬间花屏现象,不影响使用,不理会

机器配置

  • CPU: i5-6500 散
  • 主板: 微星 B150i GAMING PRO
  • 内存: 金士顿 8G*2
  • 显卡: 内置集显
  • 机箱: 迎广肖邦
  • 电源: 机箱内置
  • SSD: Crucial_CT960M500 (之前没有用到的)

安装过程

主要参考:https://www.tonymacx86.com/threads/unibeast-install-macos-sierra-on-any-supported-intel-based-pc.200564/

需要 3 个软件 UniBeast, MultiBeast, Clover Configurator

usb 启动盘相关都是在 MacBook air 上操作的,教程上制作软件需要在英文系统下操作

BIOS 设置

  • settings\高级\整合周边设备: SATA模式 - AHCI模式

  • settings\高级\USB设置: XHCI Hand-off - 允许

  • settings\高级\超级IO配置\串口0配置: 串口0 - 禁止

  • settings\启动: 启动模式选择 - UEFI

  • Overclocking\CPU 特征: CFG 锁定 - 禁止

  • Overclocking\CPU 特征: Intel 虚拟化技术 - 禁止 / Intel VT-D 技术 - 禁止

UniBeast 制作安装启动盘

  • 格式化 U 盘:USB/OS X Extended (Journaled)/GUID Partition Map
  • 写入 macOS Sierra 镜像,过程有点长,慢慢等

安装完成将需要的设置软件 MultiBeast, Clover Configurator 拖入 U 盘保存,后续需要

安装系统

  • 开机 F11 选择 U 盘启动
  • 磁盘工具格式化硬盘:Sierra/OS X Extended (Journaled)/GUID Partition Map
  • 安装,然后提示重启
  • 重启后选择 U 盘启动,启动刚刚安装的 Sierra,继续完成安装

系统设置

完成安装后,这时候系统还没有相关驱动,打开相应软件进行设置

使用 MutiBeast 进行驱动相关设置

  • Quick Start: UEFI Boot Mode
  • Audio: Realtek ALCxxx - ALC887/888b, Optional HD 3000/HD 4000/HD 530 HDMI Audio
  • Network: Realtek - RealtekRTL8111 v2.2.1
  • Graphics Configuration: Intel HD 530
  • SSDT Options: Sandy Bridge Core i5

plist 设置

使用 Clover Configurator mount EFI 分区,用 sublime 打开 EFI/CLOVER/config.plist,添加对应字段

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Devices</key>
	<dict>
		<key>AddProperties</key>
		<array>
			<dict>
				<key>Device</key>
				<string>IntelGFX</string>
				<key>Key</key>
				<string>AAPL,Gfx324</string>
				<key>Value</key>
				<data>
				AQAAAA==
				</data>
			</dict>
			<dict>
				<key>Device</key>
				<string>IntelGFX</string>
				<key>Key</key>
				<string>AAPL,GfxYTile</string>
				<key>Value</key>
				<data>
				AQAAAA==
				</data>
			</dict>
			<dict>
				<key>Device</key>
				<string>IntelGFX</string>
				<key>Key</key>
				<string>AAPL00,PanelCycleDelay</string>
				<key>Value</key>
				<data>
				+gAAAA==
				</data>
			</dict>
			<dict>
				<key>Device</key>
				<string>IntelGFX</string>
				<key>Key</key>
				<string>AAPL00,PanelPowerDown</string>
				<key>Value</key>
				<data>
				PAAAAA==
				</data>
			</dict>
			<dict>
				<key>Device</key>
				<string>IntelGFX</string>
				<key>Key</key>
				<string>AAPL00,PanelPowerOff</string>
				<key>Value</key>
				<data>
				EQAAAA==
				</data>
			</dict>
			<dict>
				<key>Device</key>
				<string>IntelGFX</string>
				<key>Key</key>
				<string>AAPL00,PanelPowerOn</string>
				<key>Value</key>
				<data>
				GQEAAA==
				</data>
			</dict>
			<dict>
				<key>Device</key>
				<string>IntelGFX</string>
				<key>Key</key>
				<string>AAPL00,PanelPowerUp</string>
				<key>Value</key>
				<data>
				MAAAAA==
				</data>
			</dict>
			<dict>
				<key>Device</key>
				<string>IntelGFX</string>
				<key>Key</key>
				<string>graphic-options</string>
				<key>Value</key>
				<data>
				DAAAAA==
				</data>
			</dict>
			<dict>
				<key>Device</key>
				<string>IntelGFX</string>
				<key>Key</key>
				<string>hda-gfx</string>
				<key>Value</key>
				<string>onboard-1</string>
			</dict>
		</array>
	</dict>
</dict>
</plist>

kexts

复制 FakeSMC.kext, RealtekRTL8111.kext, VoodooHDA.kext 到 EFI/CLOVER/kexts/other

ssd trim

输入相关命令重启即可

sudo trimforce enable

默认启动

config.plist/Boot/DefaultVolume 的 ‘值’ 改成你的启动盘(Sierra),默认为 macHDD

[about]Beginning Again

Things happen full circle for me
Like waking up from such a long dream
It never ended

So now I do what I do to get things going again
Get my life on track again
I know it's not real without your lips
But I've been working hard for so long
I want things to be right for me and you, so we can be together again
I'll be worthy of you

先看一下矩阵的显示效果:
实例:$$f(x)=x$$ 测试

安装与配

How did I get back to the beginning again. be there(waiting?) for you
I thought I've come so far
But I must get(put) myself together to be better for you
Every song has its start and I hear it repeating in my head
Over and over again
Like a cymbal keeping song playing
I know the reason why I keep moving places not believe in where I am
If I were to take my time to make things right...

记录一下处理 iOS 6 页面奇怪 bug 过程

首先是问题

  • 正常页面是这样的
    img_0566
  • 旋转屏幕之后
    img_0567
  • 再次旋转回来变成这样
    img_0568

右边多处的空白是怎么回事?其他正常浏览器都是没有问题的,包括 pc Android iOS 7 以上。看来代码是没有问题的。

首先想到的是用 Safari debug 工具看看页面结构,发现空白处就真的是 空白
来回查看页面 DOM 结构,页面居然很快恢复正常,这时候明白是页面渲染相关,只要再触发页面渲染(重绘或者重排)一次,页面就会正常,在 debug 工具来回查看 DOM 时候会触发页面的渲染。

接着想到 Google 搜索一下相关问题,但这个关键字不好写,我是这样的关键字:ios 6 rotate page overflow,然后就搜到一些不相关的内容:怎么屏蔽浏览器旋转之类的问题。

搜索无果,就尝试删减 css 相关 html body 处的 css 定义,删除一些比较可疑的样式,没有找到问题。

于是查看其他页面,有了新发现,一部分代码相同的某个页面并没有这样的问题,无论怎么旋转屏幕都是正常的。这样就好办了,我可以用排除法一步步找到最终问题所在。

排除法去找问题也没什么好说的,运气好,直觉好一点的就很快找到问题代码,最终找到问题所在 input 的 css width 定义:

input {
    width: 100%;
    ...
}

只要这个 width 的不定义,或者定义为 px 单位就没有问题了。

但是这个 width 不定义 100%,页面布局会有问题,于是就再次 Google, 这次的关键字是:ios 6 input rotate overflow ,然后就找到相应解决办法

解决这个问题方法也有一些,最终解决办法是 input 父级添加 css:overflow: hidden
这里我的理解是 overflow 这个定义有点触发页面渲染的意味,不管怎样,这个属性是挺有意思的。

AcyOrt - 基于 Node.js 的静态网站生成框架

AcyOrt 是一个简单的静态网站生成框架,基于 NodeJS 构建。通过这个框架你可以自定义各种类型的静态网站。可以通过插件完全自定义网站的生成

项目:https://github.com/acyortjs/acyort
文档:https://acyort.js.org

主要特色

  • 定制系统,你可以非常轻松自由地定制各种网站
  • 丰富的插件,内置插件系统,支持脚本以及 NPM 模块
  • CI 部署,能够自动被 CI 构建部署,只需要在浏览器操作

框架定位

AcyOrt 定位为一个流程控制器,同时提供一些辅助函数

流程控制

提供一个函数注册接口,注册的函数会严格按照注册顺序执行,包括异步函数

辅助函数

提供文件处理,多语言,数据存储,通信,页面渲染等基础静态页面生成辅助函数,方便快速生成静态页面

其他介绍

一些使用例子,及一些插件介绍

nycticorax - 简洁的 React 状态管理

nycticorax 是一个 JavaScript 应用状态管理器,并且默认集成 React 使用

项目地址:https://github.com/fratercula/nycticorax

在 React 上使用非常简单,只需要用 connect 这个 API,没有 Providerreduceraction 等概念

使用

1.创建 store,这个是基本的操作

import { createStore } from 'nycticorax'
createStore({ name: 0 })

当然也可以忽略这个步骤,不创建 store,这样就不检查数据类型以及是否存在当前 key,非常自由 :)

2.然后需要关联起 view 跟 store 吧,不然咋知道那些需要视图更新

import { connect } from 'nycticorax'

function A({ dispatch, name }) { // connect 过的组件可以使用 dispatch
  return (
    <div>
      <p>{name}</p> {/* 使用 store 中 name 的值 */}
      <button 
        onClick={() => dispatch({ name: 1 })} {/* 这里 dispatch 改变 store 里的 name 的值为 1 */}
      >
        set
      </button>
    </div>
  )
}

export default connect('name')(A) // 这里是 connect,表示需要使用 store 中的 name 的值

然后就这样可以啦,不需要像 Redux 那样需要 Provider 在最外层包裹容器

问题/对比

以上是最基本用法,当然还支持其他高级功能

异步 dispatch

nycticorax 允许函数 dispatch,并传入相关参数

function asyncDispatch({ dispatch, getStore }, ...args) {
  console.log(args)
  return new Promise((resolve) => {
    // get current store
    const { name } = getStore()

    // update name
    dispatch({ name: 'a' })

    setTimeout(() => {
      dispatch({ name: 'b' })

      // resolve
      resolve(name)
    }, 1000)
  })
}
dispatch(asyncDispatch, 'a', 'b').then(() => {
  dispatch({ name: 'c' })
}

不同的实例

直接使用是在同一个实例下的,当然可以新建实例

import Nycticorax from 'nycticorax'
const { createStore, connect } = new Nycticorax()

性能

跟 Redux 一样,最小化更新,nycticorax 只有在 connect 绑定的 key 值发生变化时候才会更新对应组件,并且对 dispatch 做优化处理

import { dispatch } from 'nycticorax'

// this
dispatch({ a: 1, b: 2 })
dispatch({ b: 1 })

// will be merged as
dispatch({ a: 1, b: 1 })

对比 Redux

在我看来,Redux 是一种代码设计模式,强调的是函数式编程,而状态管理只是 Redux 附带的一个功能

nycticorax 是纯粹的数据状态共享管理器,其工作模式非常直观简洁 dispatch => store => view。简单说就是共享一些数据状态,然后在适当时候更新数据状态,更新对应的视图

跟踪变化

dispatch 允许传入对象直接修改 store,同时也支持传入 function,这样就可以记录所有变化了,遵循特定的约定,统一来管理,让状态的变化可以预测

AMD + React 组件级别的前端开发上线方案

⼀个项⽬随着功能添加,开发时间的增⻓,通常会遇到如下问题

  1. 开发成本

我们⼀直说的组件开发,其实可以说成是在组件堆⾥开发。开发接⼿⼀个项⽬,要理清组件/⻚⾯逻
辑,嵌套思路。甚⾄还有⼀些⿊魔法的结构。当项⽬很⼤的时候,理解是⼀个⽐较⼤的开发成本

  1. 发布成本
    改动⼀个⼩功能,甚⾄是修改⼀段⼩⽂案,都需要整个应⽤打包构建发版本,项⽬越⼤时间越⻓,并
    且修改带来的⻛险越⼤

  2. 优化/改造成本
    通常在⼀个系统内,组件通信成本很低,所以开发过程⽐较少考虑组件的独⽴性。导致组件间关联⾮
    常多且复杂。这样也不⽅便测试及后续维护

  3. 组件共享成本
    通常业务定制化组件在系统间复用是比较麻烦的,例如一个定制的富文本编辑器,如果想在多个系统间复用,通常方式是

  • 发布 npm 包,但这样有一定的问题
    • 违背 npm 包**,npm 包应该是通用的,而不是业务定制化
    • 编辑器更新,使用的系统也必须进行更新构建。并且整个流程繁琐
  • 复制方式,将组件复制到各个系统,这样就更难以管理

目标

希望有⼀种⽅式,只关注单个组件逻辑,不需要去了解页面其他的嵌套结构逻辑,只需要关注⾃⼰的组件功能。具体来说可以细分

  • 组件按需加载
  • 组件独⽴开发构建部署,组件更新主应⽤不需要重新构建
  • 安全稳定性(组件隔离,组件出错不会导致主应⽤出错)
  • 组件间能通信

另外还有一些开发体验上的要求

  • 开发配置,API 之类要简单⼀些
  • 当组件独⽴了,需要有预览功能,可以测试真实情况,例如事件触发的测试
  • 不需要每次都安装 webpack 之类的构建⼯具(当组件⾜够多时候,每个组件都安装⼀次 webpack, babel,这是⼀种折磨),同时统⼀的构建⼯具保证统⼀稳定性

方案

以下是一些方案对比

方案 按需加载 组件独⽴ 通信 发布 备注
路由跳转 ⻚⾯级 ⻚⾯独⽴ Url 参数, 浏览器存储 独⽴ 太普通,意义不⼤
iframe ⻚⾯级 ⻚⾯独⽴ postMessage, Url 参数, 浏览器存储 独⽴ 太普通, 意义不⼤
Webpack 代码分割 ⻚⾯级 不独⽴ 完整 全量发布 没有解决组件独⽴,发布⻛险问题
single-spa ⼦应⽤ 应⽤独⽴ 应⽤间⽆通信 ⼦应⽤单独发布,主容器需重新构建 改⽅案的出发点是:解决历史遗留系统,考虑怎么将这些系统合在一起

以上都不大符合要求,使⽤以下⽅案

  • 按需加载:使⽤ RequireJS,业界成熟的 AMD 加载规范。同时也解决组件依赖问题
  • 组件通信:使⽤ JS 发布-订阅 模式,Redux 底层也是基于这个模式
  • 组件隔离:AMD 规范使 JS 隔离,使⽤ CSS Modules 进⾏ CSS 隔离

开发体验

  • 提供开发者⼯具:⽅便测试,统⼀打包模式,不重复构建 Polyfill
  • 开发构建⼯具安装⽅便,⼀次安装,多处使⽤,⽅便升级

设计实现

以下为⽅案的⼀些具体说明及具体 DEMO

方案:https://github.com/fratercula/humpback

基本流程:组件 AMD ⽅式加载 --> React HOC 处理 --> 组件拥有调度⽅法及全局数据

基本介绍

DEMO:https://loeify.github.io/humpback-demo/9 个组件及 1 个全局容器构成,每个都是独⽴构建发布

// 每个组件都可以独立发布,有自己独立的版本号
{
  global: 'cdn/to/global/0.2.0/index.js', // 全局容器组件
  button: 'cdn/to/button/0.0.0/index.js',
  card: 'cdn/to/card/0.0.1/index.js',
  description: 'cdn/to/description/0.1.0/index.js',
  error: 'cdn/to/error/0.0.1/index.js',
  photo: 'cdn/to/photo/0.0.3/index.js',
  timeline: 'cdn/to/timeline/0.4.0/index.js',
  user: 'cdn/to/user/0.0.2/index.js',
  input: 'cdn/to/input/0.1.0/index.js',
  posts: 'cdn/to/posts/0.2.0/index.js',
  post: 'cdn/to/post/0.0.4/index.js',
}

可以自定义页面布局,例如 DEMO 为以下页面组件配置

[
    {
      path: '/',
      name: 'index',
      icon: 'dashboard',
      components: {
        type: 'index',
        left: ['card', 'timeline'],
        right: ['button', 'error'],
      },
    },
    {
      path: '/switch',
      name: 'switch',
      icon: 'customer-service',
      components: {
        type: 'user',
        left: 'user',
        right: ['description', 'photo'],
      },
    },
    {
      path: ['/posts', '/posts/:id'],
      name: 'posts',
      icon: 'book',
      components: {
        type: 'user',
        left: 'posts',
        right: ['post'],
      },
    },
  ]

参数说明

全局容器组件

interface GlobalProps {
  dispatch: Function; // 调度函数,访问全局或者组件
  Routes: ReactNode; // 组件容器
  componentCreator: Function; // 组件包装⽅法
  store: object; // 全局 store
  mountedComponents: array; // 当前⻚⾯已经加载完成组件
  config: object; // ⾃定义参数配置
}

组件

interface ComponentProps {
  config: object; // ⾃定义参数配置
  mountedComponents: array; // 当前⻚⾯已加载完成组件
  store: object; // 全局 store
  dispatch: Function; // 调度函数,访问全局或者组件

  // react-router 参数
  match
  history
  location
}

调度方法定义

type dispatch = (
  type: string, // 类型,‘global’ 或者 ‘组件名’
  name: string, // 调度⽅法名
  value: any, // 参数
) => any;

组件开发并没有特殊 API 或者协议,跟普通开发使⽤⼀样。
组件提供静态⽅法给其他组件调⽤,这样其他组件不能直接访问到当前组件的上下⽂,保证安全

import React, { Component } from 'react'
import Nycticorax from 'nycticorax'

const {
  createStore,
  connect,
  dispatch,
  getStore,
} = new Nycticorax() // 可以使⽤ redux/mobx 之类

createStore({ name: '233' })

class X extends Component {
  // 静态⽅法⽤于给其他组件调⽤,同时也保证组件数据安全
  static getName = () => getStore().name
  static updateName = async (name) => {
    dispatch({ name })
  }

  render() {
    return ...
  }
}

export default connect('name')(X)

开发体验

本⽅案提供开发⼯具:https://github.com/fratercula/megaptera

以下为以下说明介绍

  1. 提供两种类型的开发,组件开发及全局容器开发

Screen Shot 2020-04-30 at 10 25 46 PM

  1. 提供模拟环境,模拟事件处理,窗⼝模拟

Screen Shot 2020-04-30 at 10 26 23 PM

  1. 不需要重复的安装依赖环境,同时也保证构建⼯具的统⼀

  2. ⾃动安装包依赖

工作流对比

普通模式下的开发上线⼯作流

  • 每次更改必须整个项⽬构建⼀次
  • 组件出错很可能会影响全局

Screen Shot 2020-04-30 at 10 28 09 PM

基于本⽅案的开发上线⼯作流

  • 每次更改只需要改对应功能的组件,全局不需要变更
  • 组件出错也只影响组件本⾝,对全局没影响

Screen Shot 2020-04-30 at 10 28 58 PM

性能说明

提高比普通方式更好的性能,开发者只需要关系自己组件的性能

  • 加载性能(AMD ⾃带):

    • 按需加载
    • 缓存加载
  • 组件(应⽤)性能:

    • 最⼩化更新,只有绑定的数据更新才会导致组件更新
    • 容器⽆法直接更新组件(应⽤),保证性能,同时也保证组件(应⽤)状态不会刷新

Screen Shot 2020-04-30 at 10 31 18 PM

方案优点

  1. 定制化

可以根据需求进行组件颗粒度的一些处理。例如数据埋点,在普通方式下,需要对系统某部分功能进行一些统计情况,可以需要一定改造成本。但在本方案下,组件天然的独立性会带来方便

  1. 开放能力

系统可以有类似 小程序 的能力,可以方便的接入一些功能,但同时接入并不需要系统进行重新构建。

  1. 多人协作

大型项目通常需要多个开发共同合作,由于该方案的天然组件独立性,每个人可以单独负责几个组件,或者某一类能力的组件,这样更好关注组件开发

  1. 系统维护

由于开发往组件化**及独立性。这样会更方便测试维护。同时也不用再担心系统随着功能添加变得越来越大的问题,因为一切都是按需加载。当⼀个⻚⾯使⽤⼀个组件时候就类似 webpack 代码分割的效果

  1. 稳定性

同意由于组件独立,隔离能力,组件的错误并不会影响全局,这样就减少发布带来的风险及故障

  1. 提高效率

组件往功能化**⽅向开发,会促进系统间的组件复用。这样就能提高开发效率。项⽬开发构建发布可以变成

Screen Shot 2020-04-30 at 10 32 15 PM

方案缺点

  • 组件复用可能带来兼容性问题,这点类似 npm 包的问题,现在任何方式都不能解决
  • 因为组件间完全独立,所以通信引用不能像以前那样方便。但这样子更能提高组件的稳定性

FAQ

  1. 如何解决依赖问题?
    RequireJS (AMD)已经解决

  2. 组件重名了怎么办?
    这个问题跟 npm 包重名⼀个问题,最终就是要约定,⽐较好办法就是把所有组件项⽬放在 gitlab�的
    ⼀个组内,项⽬创建就避免重复问题

  3. 依赖组件重复打包?
    ⼀些⼤型基础库,例如 antd,可以在项⽬设定好依赖,这样所有组件都可以使⽤了(组件打包时
    候注意 externals 基础库)
    但组件仍然可以⾃⼰去依赖⼀些组件,最终打包就是该组件会⽐较⼤,但不影响全局

  4. 如何知道其他组件有没有提供调⽤的⽅法?
    组件是否加载完成参数
    调⽤错误提⽰
    通常⽐较少互相调⽤的场景,更多的是组件调⽤全局的场景

参考

Thinking in Microfrontend

css animation 绕方块旋转动画效果

一个比较好玩的动画效果,具体代码:

HTML

<div id="container">
    <li>
        <a href="#"></a>
    </li>
    <li>
        <a href="#"></a>
    </li>
    ...
    <li>
        <a href="#"></a>
    </li>
</div>

CSS

#container {
    background: #000;
}
#container li {
    width: 100px;
    height: 100px;
    padding: 1px;
    display: inline-block;
    vertical-align: top;
    position: relative;
}
#container a {
    display: block;
    width: 100px;
    height: 100px;
}
#container a:before, #container a:after {
    content: '';
    position: absolute;
    background: blue;
    height: 1px;
    z-index: 3;
}
#container li a:before {
    -webkit-animation: rounda 2s linear forwards infinite;
    top: 0;
    left: 0;
}
#container li a:after {
    -webkit-animation: rounda 2s 1s linear forwards infinite;
    bottom: 0;
    right: 0;
}


#container li:before, #container li:after {
    content: '';
    position: absolute;
    background: blue;
    width: 1px;
    z-index: 3;
}
#container li:before {
    -webkit-animation: roundb 2s 0.5s linear forwards infinite;
    right: 0;
    top: 0;
}
#container li.animate:after {
    -webkit-animation: roundb 2s 1.5s linear forwards infinite;
    left: 0;
    bottom: 0;
}

@-webkit-keyframes rounda {
  0% {
      width: 0;
  }

  25% {
      width: 100%;
  }

  50% {
      width: 100%;
  }

  50.1% {
      width: 0;
  }
}
@-webkit-keyframes roundb {
  0% {
      height: 0;
  }

  25% {
      height: 100%;
  }

  50% {
      height: 100%;
  }

  50.1% {
      height: 0;
  }
}

DEMO

http://jsfiddle.net/am0200/x9u4w12x/
这里是针对 webkit 的动画,Firefox 之类的代码需要另外加,所以请使用 webkit 浏览器

说明

当页面多个这样动画运行时候,效果蛮不错,当然 MacBook 发热开始了

test

我开个issue会怎么样。

使用 canvas 的 drawImage 方法时候必须确保 image 已经加载完成

image 通过 ajax 方式加载,加载完成调用 drawImage 方法,chrome 完成 canvas 图片,但是 firefox 却 canvas 空白,Google 一下
Try calling the drawImage function inside the image's load function to ensure that the image is actually loaded before trying to draw it.

image.onload = function() {
    // context.drawImage...
}

但这样做可能再次打开页面,drawImage 不会发生,原因是 image 可能不触发 onload,而是 complete,所以

image.onload = function() {
    // context.drawImage...
}
if (image.complete) image.onload();

零配置运行 ES6/TS/React/Vue/ 代码

Falco 是基于 webpack,npm 的一层封装。解决的问题是 demo 代码的构建打包问题,而直接运行代码是附加的一个功能

项目地址:https://github.com/fratercula/falco

背景

JavaScript 模块或者框架需要 demo 展示来说明使用方式,例如 antd 里面就有很多 demo 的展示。那么怎么快速生成这些 demo 呢,一些框架可以做类似事情,例如 docz

docz 只是解决本地已经安装的问题,也就是说 demo 的展示需要本地已经安装好依赖。那这样就有问题了,如果 demo 代码是各种 js 依赖的,那就是说要不断的本地安装依赖。无法运行时构建

方案

动态分析代码所需要的依赖,然后自动安装对应的依赖,再用 webpack 进行构建,完美解决上述问题。详细可以查看 Falco 的实现。简单的步骤为

  1. 分析代码依赖,获取需要安装的 js 依赖
  2. 安装依赖到系统临时目录
  3. webpack 构建

扩展

开发这个工具的主要目的就如上述所说,但是开发过程中发现,结合 webpack-dev-server 可以做到运行和构建 js 代码,只要在某些步骤中做一些处理

  1. 分析代码过程,需要递归的去分析文件依赖树,再进行分析 js 包的依赖
  2. 此步骤还是一样
  3. webpack 构建,区分运行或者打包模式,然后选择使用 webpack-dev-server 运行构建

其他

开发过程中遇到的一些问题

  1. node 方式使用 webpack-dev-server 时候需要手动引入一些依赖
...
entry.unshift('webpack-dev-server/client?', 'webpack/hot/dev-server')
plugins.unshift(new webpack.HotModuleReplacementPlugin())
...

这里有个特殊的地方 webpack-dev-server/client?,问好后面不能带域名跟端口,可能跟我的使用方式有关,不过这些依赖在新版已经不需要加上了,所以也不用纠结了

  1. @babel/plugin-transform-runtimeabsoluteRuntime 配置,这个配置在原来 babel 官方是没有展示的,我自己翻源代码找到的。不过后面 babel 官方把这个设置放出来了。相关 issue

输入框输入值自动格式化

这里说的自动格式化是指当用户在输入框里面输入数字,例如银行卡号,为了方便用户输入,希望在输入过程中对输入数字进行加空格处理,优化用户体验

先看一下例子: http://jsfiddle.net/am0200/qugp8tvL/

注意例子里面的输入框的类型是 tel,而不是 number,主要原因是 number 类型

  • 会导致 Android 上某些系统不显示 placeholder
  • 无法插入非数字内容,例如空格

代码实现

data-gap 代表第几位开始加空格,不为 0

<input data-gap=4 maxlength="24" size="30" autocomplete="off" type="tel" placeholder="请输入卡号"/>

原理就是获取用户输入内容,格式化处理完成后再填入输入框

var input = document.querySelectorAll('input')[0]
var gap = parseInt(input.getAttribute('data-gap'))

input.oninput = function() {
  var numbers = this.value.replace(/\s+/g, '').split('')     // 获取原始值
  var back = '' 

  numbers.forEach(function(n, i) {
    back += n + ((i + 1) % gap === 0 ? ' ' : '')    // 处理加空格
  })
  
  var len = back.length
  var last = back.charAt(len - 1)

  if (last === ' ' || isNaN(last)) {
    back = back.substring(0, len - 1)    // 移除末尾无用字符
  }

  this.value = back
  
  // 兼容处理
  setTimeout(function() {
    this.setSelectionRange(len, len)
    this.focus()
  }.bind(this), 0)
}

获取输入原始值

input.value.replace(/\s+/g, '')

扩展

可以设置格式化分割字符,例如用 - 代替空格,还可以设定不规则位数空格,具体可以修改处理条件即可

关于浏览器直接使用 ES6 的一些简单介绍

在浏览器端直接运行 ES6 代码通常可以这样做

首先引入 babel-standalone

<script src="https://unpkg.com/[email protected]/babel.min.js"></script>

然后就可以直接写 ES6 代码了

<script type="text/babel">
class A {
  constructor() {
    this.a = 0
  }
  log() {
    console.log(this.a)
  }
}
</script>

当然也可以直接写 React JSX 相关

<!-- 需要引入 React 相关 -->
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

<script type="text/babel">
ReactDOM.render(
  <div>
    <h1>JSX</h1>
  </div>
, document.body)
</script>

还可以文件引入方式来写 ES6 代码

<script type="text/babel" src="/main.js"></script>

通常要写一些更高级的 js 特性,还需要添加 babel-standalone 一些插件,例如需要支持 class properties 这时候需要这样做

<script type="text/babel" data-plugins="transform-class-properties">
class Bork {
  instanceProperty = "bork";
  boundFunction = () => {
    return this.instanceProperty;
  }
}
</script>

如果需要 import 其他模块,还需要引入 es2015-modules-umd 插件。插件列表可以参考这里:https://babeljs.io/docs/plugins/

<script type="text/babel" data-plugins="transform-class-properties transform-es2015-modules-umd">
import { Breadcrumb } from 'antd';

ReactDOM.render(
  <Breadcrumb>
    <Breadcrumb.Item>Home</Breadcrumb.Item>
    <Breadcrumb.Item><a href="">Application Center</a></Breadcrumb.Item>
    <Breadcrumb.Item><a href="">Application List</a></Breadcrumb.Item>
    <Breadcrumb.Item>An Application</Breadcrumb.Item>
  </Breadcrumb>
, mountNode);
</script>

接下来写一些稍微 正式 的代码

<!-- 同样引入 React 相关 -->
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

<script type="text/babel" data-plugins="transform-class-properties transform-es2015-modules-umd">
import React, { Component } from 'react'
import ReactDOM from 'react-dom'

class Editor extends Component {
// ...
}

class Main extends Component {
  // ...
  render() {
    return (
      <div>
        <Editor {...this.props} />
      </div>
    )
  }
}
</script>

不出意外,console 会得到一些类似错误提示

Uncaught TypeError: Cannot read property 'Component' of undefined

通过测试试验,出现这样提示是因为引入的模块 umd 打包出来不符合标准,根据 umd 标准,react 的 libraryName 应该为 react,而不是 React。同样 react-dom 的 libraryName 应该为 reactDom 而不是 ReactDOM

所以解决办法也很简单,加上对应 libraryName 的定义即可

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

<script>
window['react'] = window.React
window['reactDom'] = window.ReactDOM
</script>

<script type="text/babel" data-plugins="transform-class-properties transform-es2015-modules-umd">
// ...
</script>

同样,当我们需要引入 react-router 时候,同样也需要做对应处理

window['reactRouterDom'] = window.ReactRouterDOM
window['reactRouter'] = window.ReactRouter

最后,总结一下浏览器写 ES6 + React 模板

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/umd/react-router-dom.min.js"></script>

<script>
window['react'] = window.React
window['reactDom'] = window.ReactDOM
window['reactRouterDom'] = window.ReactRouterDOM
</script>

<script type="text/babel" data-plugins="transform-class-properties transform-es2015-modules-umd">
// ...
</script>

可能会有疑问:为什么要在浏览器做这样事情,为什么不直接用 webpack 之类的。这里说明一下,正常情况下我们的 webapp 是不应该这样子做,应该预先打包后发布。所以这种浏览器处理方式的使用场景是在展示,测试一些小 demo 时候使用的

创建类似 http://ithinkimight.com/ 随机大小排布界面

ithinkimight.com 这个网站图片来自 Instagram,图片随机大小,位置也是随机,图片可以重叠,但是并没有 过分 重叠。这种随机大小,位置排版页面元素跟平常的整齐 grid 或者 瀑布流 风格很不一样,下面我们尝试一下实现类似效果

从网站源文件上看并不能看出网站是如何随机排布这些图片,因为是后端直接输出图片的位置参数,并不是前端实现的位置计算。不过这里有一种简单方法,可以实现类似效果。先看一下具体效果

例子以及实际运用效果

http://jsfiddle.net/am0200/1mn5xbf8/

http://stone.am0200.com/

实现思路

首先把 container 划分为 4 个块,然后需要随机定位的 4 个块分别放到这 4 个区域,最后定义这 4 个块距离左边跟上边的最远,最近距离即可

实现代码

html 部分,我们只是生成 4 个容器,每个容器都可以放置一张图片

<section>
    <div id="d0"></div>
    <div id="d1"></div>
    <div id="d2"></div>
    <div id="d3"></div>
</section>

css 部分,我们使用绝对定位来设置每个容器的主要位置

section {
    width: 100%;
    height: 100%;
    position: relative;
}
section div {
    position: absolute;
}
#d0 {
    left: 50%;
    top: 0;
}
#d1 {
    top: 50%;
    left: 50%;
}
#d2 {
    left: 0;
    top: 50%;
}
#d3 {
    left: 0;
    top: 0;
}

js 部分,我们设置 4 个块随机大小,并且随机上下左右距离,需要注意的是,这个距离是有一定的范围的

function rd(n,m){
    var c = m-n+1;  
    return Math.floor(Math.random() * c + n);
}

var w = parseInt($('section').width()),
    h = parseInt($('section').height());

$('div').each(function() {
    var wh = rd(150, 200)
    $(this).css({
        width: wh,
        height: wh
    })
})

var d0 = parseInt($('#d0').width()),
    d1 = parseInt($('#d1').width()),
    d2 = parseInt($('#d2').width()),
    d3 = parseInt($('#d3').width());

var a1 = rd(-(d0 / 4), w / 2 - d0),
    a2 = rd(0, h / 2 - d0 / 4 * 3);

var b1 = rd(-(d1 / 4), w / 2 - d1),
    b2 = rd(-(d1 / 4), h / 2 - d1);

var c1 = rd(0, w / 2 - d2 / 4 * 3),
    c2 = rd(-(d2 / 4), h / 2 - d2);    

var e1 = rd(0, w / 2 - d3 / 4 * 3),
    e2 = rd(0, h / 2 - d3 / 4 * 3); 


$('#d0').css('margin-left', a1 +'px')
$('#d0').css('margin-top', a2 +'px')

$('#d1').css('margin-left', b1 +'px')
$('#d1').css('margin-top', b2 +'px')

$('#d2').css('margin-left', c1 +'px')
$('#d2').css('margin-top', c2 +'px')

$('#d3').css('margin-left', e1 +'px')
$('#d3').css('margin-top', e2 +'px')

其他问题

这种定位简单方便,但是如果是单数块的时候,就要做一下相关处理了

使用 inline-block 水平垂直居中任意内容

挺好用的水平垂直居中任意内容代码,并且支持度很高

相关代码

html

<!-- 注释用于去除 inline-block `间隙` -->
<div class="container"><!--
 --><div class="center">
            <h2>这个是居中标题</h2>
            <p>这里是一些文字,文字</p>
     </div><!--
--></div>

css

.container {
    text-align: center;
    width: 100%;
    height: 300px;
}
.container:before,
.container:after    /* :after 可以不需要 */
{
    display: inline-block;
    vertical-align: middle;
    content: '';
    height: 100%;
}
.center {
    display: inline-block;
    vertical-align: middle;
    max-width: 100%;
}

demo

http://jsfiddle.net/am0200/49sp6e9n/3/

Pavane - 基于 Node.js 的 LiveReload Server

Pavane 是一个基于 Node.js 的 LiveReload Server 工具。

提供修改文件自动刷新浏览器页面的能力。Pavane 提供丰富的自定义选项,满足大部分的使用开发需求。

项目地址:https://github.com/fratercula/pavane

安装

$ npm i pavane -D # 作为模块使用
$ npm i pavane -g # 全局 CLI 使用

使用

Pavane 既可以作为一个 Node 模块使用,也可以作为一个命令行工具全局使用,还可以在其他 web 服务上使用

Node 模块

const { join, extname } = require('path')
const Pavane = require('pavane')

/*
  监听目录
  文件, 目录, glob 匹配, 或者 数组
  默认: 当前运行目录
*/
const watches = join(process.cwd(), 'src')

/*
  静态资源目录
  默认: 当前运行目录
*/
const publics = __dirname

const server = new Pavane(watches, publics)

server.listener = (args) => {
  const {
    event,        // 文件信息 'add', 'change', 或者服务器信息 'info' ...
    path,         // 修改路径,当事件为 'info', 为空
    message,      // 服务器信息,如果事件为 'info', 此时为空
    reloadCss,    // 触发客户端 css 重置
    reloadPage,   // 触发客户端刷新页面
  } = args
  const { log } = global.console

  if (event === 'info') {
    log(message)  // 输出服务器信息
    return
  }

  // 获取当前改变文件的后缀,然后进行 css,js 构建之类
  const ext = extname(path)

  if (ext === '.css') {
    reloadCss()   // 重置 css
  } else {
    reloadPage()  // 刷新页面
  }

  log(`${event} ${path}`) // 输出当前信息
}

server.start(2222) // 默认端口 2333

// 另外一种方式获取当前状态
console.log(server.status)
/*
{
  running: true,
  event: 'change',
  path: 'file path',
}
*/

CLI 全局使用

$ pavane # 默认使用,当前目录作为监听文件变化目录,同时也作为静态服务器目录
$ pavane -p 2000 # 自定义端口
$ pavane -c # 使用配置启动
$ pavane -w src -s dist # 设置监听目录 src,静态 server 目录 dist

# pavane 可以简写为 pv
$ pv -p 2000

使用配置启动需要在运行目录添加一个配置文件 pavane.config.js

const { extname } = require('path')

module.exports = {
  watches: ['*.js', '*.css', '*.html', '**/*.html'], // 监听目录,文件, 目录, glob 匹配, 或者 数组
  publics: __dirname, // 静态文件目录
  port: 2222, // 端口
  listener(args) {
    const {
      event,
      path,
      message,
      reloadCss,
      reloadPage,
    } = args
    const { log } = global.console

    if (event === 'info') {
      log(message)
      return
    }

    // 获取当前改变文件后缀
    const ext = extname(path)

    if (ext === '.css') {
      // 这里可以进行一些 css 构建之类的
      // 然后刷新页面 css
      reloadCss() 
    } else {
      // 同样可以进行 js,html 之类的构建
      // 然后刷新页面
      reloadPage()
    }

    log(`${event} ${path}`)
  }
}

在其他 web 服务上使用

如果当前的应用是由 python,php 之类的应用,可能会有自己的 web 服务。如果需要引入 Pavane 的 LiveReload 能力也是可以的,只需要在应用的前端模板页面上相应位置加上这个 script

<!-- 假设当前启动的服务端口是 2333 -->
<script src="http://127.0.0.1:2333/_.js"></script>

这时候在模板目录启动 Pavane,修改模板文件,静态资源后就可以自动刷新页面了

适用场景

每个工具都具有自己相应的使用场景,所以 Pavane 的适用场景是

  • 简单静态页面开发,例如活动页面,宣传页面
  • 前后端揉合的 web 应用,例如 python django 的后台页面
  • 需要转码的前端页面,例如需要 less,sass,babel 转码的应用

但是如果你的应用是前后端分离的单页应用,vue,react 之类的,还是直接上 webpack 构建工具吧,具有更高级的刷新页面功能

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.