This commit is contained in:
dntzhang 2017-03-16 08:32:30 +08:00
parent 91f8c696e7
commit 378a69593e
5 changed files with 702 additions and 0 deletions

13
tutorial/README.md Normal file
View File

@ -0,0 +1,13 @@
# 深入Omi
(待续...
* [环境搭建](./cn_env.md)
* [Hello Omi](./cn_hello.md)
* [手Q附近Web页Omi实战](./cn_nearby.md)
* 局部CSS揭秘
* 组件嵌套揭秘
* 事件处理揭秘
* 服务器端渲染揭秘
* 模板切换揭秘
* 容器系统揭秘

132
tutorial/env.md Normal file
View File

@ -0,0 +1,132 @@
<h2 id="环境搭建">环境搭建</h2>
[Omi框架](https://github.com/AlloyTeam/omi)使用 Webpack + ES6 的方式去开发使用karma+jasmine来作为Omi的测试工具。
## Karma介绍
Karma是一个基于Node.js的JavaScript测试执行过程管理工具Test Runner。该工具可用于测试所有主流Web浏览器也可集成到CIContinuous integration工具也可和其他代码编辑器一起使用。这个测试工具的一个强大特性就是它可以监控(Watch)文件的变化然后自行执行。但是集成到travis ci要把singleRun设置成true,让其只执行一遍。
## Jasmine介绍
Jasmine 是一款 JavaScript BDD行为驱动开发测试框架它不依赖于其他任何 JavaScript 组件。它有干净清晰的语法,让您可以很简单的写出测试代码。
## 开发依赖包
在package.json中有如下配置:
```js
"devDependencies": {
"babel-core": "^6.0.20",
"babel-loader": "^6.0.1",
"babel-preset-es2015": "^6.0.15",
"node-libs-browser": "^0.5.3",
"webpack": "^1.14.0",
"jasmine-core": "^2.5.2",
"karma": "^1.3.0",
"karma-chrome-launcher": "^2.0.0",
"karma-jasmine": "^1.1.0",
"karma-webpack": "^1.8.1"
}
```
* ES6+相关依赖有babel-core、babel-loader和babel-preset-es2015
在webpack.config.js中配置js文件使用babel-loader编译。
```js
loaders: [
{
loader: 'babel-loader',
test: /\.js$/,
query: {
presets: 'es2015',
}
}
]
```
* webpack相关依赖有node-libs-browser和webpack
* 其余都是单元测试相关依赖
注意这里使用了karma-webpack。因为使用Omi框架支持ES6+和ES5,使用karma-webpack是为了在单元测试里面使用ES6+的import和Class等语法。
在karma.conf.js中配置webpack:
```js
webpack: webpackConfig,
webpackMiddleware:{
noInfo:false
},
plugins: [
'karma-webpack',
'karma-jasmine',
'karma-chrome-launcher'
]
```
具体配置看test目录下的[karma.conf.js](https://github.com/AlloyTeam/omi/blob/master/test/karma.conf.js)和[webpack.test.config.js](https://github.com/AlloyTeam/omi/blob/master/test/webpack.test.config.js)便可。
注意karma.conf.js需要设置
```js
// if true, Karma captures browsers, runs the tests and exits
singleRun: true,
```
不然travis ci脚本执行的时候不会中断导致执行超时异常。
## npm 脚本
```js
"scripts": {
"build": "webpack -w",
"test": "karma start test/karma.conf.js",
"hello": "webpack -w",
"todo": "webpack -w"
}
```
其中:
* npm run build : 生成dist目录的omi.js文件
* npm run test : 执行单元测试
* npm run hello : 编译hello的demo
* npm run todo : 编译todo的demo
在webpack.config.js中会根据 process.env.npm_lifecycle_event去设置不同的入口文件。所以同样是执行webpack -w执行结果可以不一样。
来看下build的相关webpack配置:
```js
if(ENV === 'build'){
config = {
entry: {
omi: './src/index.js'
},
output: {
path: 'dist/',
library:'Omi',
libraryTarget: 'umd',
filename: '[name].js'
},
```
这里把libraryTarget设置成了umdwebpack会帮助我们build出umd的Omi。
如果是打包demonpm run hello 和 npm run todo的话会进入下面的条件判断
```js
else {
config.entry = './example/' + ENV + '/main.js';
config.output.path = './example/' + ENV + '/';
}
```
会去example下对应的目录查找main.js作为webpack入口文件。
这里可以看到我们不仅用webpack build出Omi框架也使用webpack build所有demo。
详细配置参考[webpack.config.js](https://github.com/AlloyTeam/omi/blob/master/webpack.config.js)的配置。
## 参考文档
* [http://www.cnblogs.com/cqhaibin/p/5867125.html](http://www.cnblogs.com/cqhaibin/p/5867125.html)
* [https://karma-runner.github.io/latest/intro/installation.html](https://karma-runner.github.io/latest/intro/installation.html)
* [https://karma-runner.github.io/latest/intro/configuration.html](https://karma-runner.github.io/latest/intro/configuration.html)

262
tutorial/nearby.md Normal file
View File

@ -0,0 +1,262 @@
## 写在前面
Omi很适合大型复杂的Web页面开发例如一些Web在线工具的开发。但是制作这种简单的QQ附近用户列表Web页也不会有大炮哄蚊子的感觉。
项目开始之前,实现选择一个脚手架。可以使用[omi-cli](https://github.com/AlloyTeam/omi/tree/master/cli)快速创建项目脚手架。脚手架主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。
Gulp用来串联整个流程Webpack + Babel让你可以写ES6和打包BrowserSync用来帮你刷浏览器不用F5了。
这里需要注意的是BrowserSync会启动localhost:3000导致你的AJAX请求跨域而无法拿到数据。
![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184323476-1150194475.png)
所以要使用Fiddler并配置Extention
![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184331445-1124037886.png)
## 目录
![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184337726-1825094998.png)
目录结构也是和[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)一样。
组件全放在component目录公共的工具库放在common其他资源文件放在asset里。
## 命令
开发
```js
npm run dev
```
发布
```js
npm run dist
```
## 开始写码
万事具备,开始写码。先写组件:
```js
import Omi from 'omi'
class UserList extends Omi.Component {
constructor(data) {
super(data)
}
install() {
this.data.uin_info || (this.data.uin_info = [])
this.data.uin_info.forEach(user => {
this.prepareData(user)
})
}
prepareData(user){
user.desc_d = user.desc.split("&nbsp;")[0]
user.desc_t = user.desc.split("&nbsp;")[1]
user.isBoy = user.sex === "男"
user.qlogo = user.url.replace("http://", location.protocol + "//").replace(/&amp;/g, "&")
if (user.profession_desc) {
user.hasProfession_desc = true
}
}
appendUsers (users) {
users.uin_info && users.uin_info.forEach(user =>{
this.prepareData(user)
this.data.uin_info.push(user)
})
this.update()
}
sendGift(uin, nick, qlogo) {
//送礼物并关闭webview,此处省略
//..
//..
}
render() {
return `
<div class="user_list">
{{#uin_info}}
<div class="item" onclick="sendGift('{{uin}}','{{nick}}','{{qlogo}}')">
<div class="qlogo">
<img style="width: 70px;" src="{{qlogo}}" />
</div>
<div class="main b1 bb">
<div class="nick">{{{nick}}}</div>
<div class="icons">
{{#isBoy}}<span class="boy_age"><img src="component/user_list/boy.png" alt="" /><span>{{age}}</span></span> {{/isBoy}}
{{^isBoy}}<span class="girl_age"><img src="component/user_list/girl.png" alt="" /><span>{{age}}</span></span> {{/isBoy}}
{{#hasProfession_desc}} <span class="profession"><span>{{profession_desc}}</span></span> {{/hasProfession_desc}}
</div>
<div class="action">{{{intro}}}</div>
</div>
<div class="distance_info">{{desc_d}} · {{desc_t}}</div>
</div>
{{/uin_info}}
<div style="text-align:center;font-size:13px;line-height:30px;height:30px;"><span class="loading"></span> 加载中...</div>
</div>
`
}
style() {
return `
.qlogo {
overflow: hidden;
width: 70px;
height: 70px;
-webkit-border-radius: 50%;
border-radius: 50%;
position: absolute;
top: 10px;
left: 12px;
}
...
...
..这里省略大量.....
...
...
.distance_info {
position: absolute;
top: 15px;
right: 9px;
color: #7B7B84;
font-size: 10px;
}
`
}
}
export default UserList
```
组件里面有5个方法:
* constructor 组件的构造函数生命周期的一部分其实在super上面和super调用下面可以对data做一些处理。super之上不能拿到this
* install 组件的初始化安装生命周期的一部分这里也可以拿到用户传进的data进行处理
* prepareData 对数据进行一些处理来满足模板的渲染
* appendUsers 新增数据用来处理用户向下滚动的load more 的行为的时候调用
* sendGift 送礼物,点击每一项的时候会有送礼物的行为,业务相关,可以无视..
其他两个方法的render和style用来生成组件的HTML和局部CSS不再叙述。
render里面使用了[mustache.js](https://github.com/janl/mustache.js)模板引擎;
如果使用omi.lite.js版本(不包含[mustache.js](https://github.com/janl/mustache.js)模板引擎)的话你也可以使用ES6 map去遍历数据生成HTML或者重写 Omi.template去使用任意你喜欢的模板引擎非常灵活方便。
这里友情提醒一下如果使用webstorm的话可以把js version设置成JSX Harmony或者ECMAScript 6这样才是写ES6+的姿势。
![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184433148-472636444.png)
下面来看index.js:
```js
import Root from './config.js'
import Omi from 'omi'
import UserList from '../component/user_list/index.js'
Omi.makeHTML('UserList', UserList)
class Main extends Omi.Component {
constructor(data) {
super(data)
}
installed() {
window.onscroll = () => this.loadMore()
this.requestData(data => this.list.appendUsers(data))
}
loadMore() {
const body = document.body,
html = document.documentElement,
height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),
vp_height = window.innerHeight
if (height - document.body.scrollTop - vp_height < 200) {
this.requestData(data => this.list.appendUsers(data))
}
}
requestData(callback) {
if (Root.isDev) {
require.ensure([], ()=> {
callback(require('./mock_data.js').default)
})
}else{
//ajax 请求数据,这里省略
}
}
render() {
return `
<div class="main">
<UserList name="list" />
</div>`
}
}
Omi.render(new Main(),'body')
```
通过Omi.makeHTML('UserList', UserList)这句代码UserList变成了可以嵌套至render方法中的标签。如
```js
render() {
return `
<div class="main">
<UserList name="list" />
</div>`
}
```
下面这行代码是监听滚动快滚动到底部的时候在loadMore里面会去请求。
```js
window.onscroll = () => this.loadMore()
```
通过height - document.body.scrollTop - vp_height < 200判断用户快要滚动底部滚动到底部有个加载更多的行为
```js
if (height - document.body.scrollTop - vp_height < 200) {
this.requestData(data => this.list.appendUsers(data))
}
```
requestData是去服务器请求分页的数据请求成功会去调用this.list.appendUsers进行数据的添加。
慢着this.list哪里来的appendUsers又是哪里定义的方法且看下面
```js
<UserList name="list" />
```
上面标记的name让你可以直接通过this.list访问到UserList对象的实例所以也就可以调用它的appendUsers方法
再来看下数据模拟:
```js
if (Root.isDev) {
require.ensure([], ()=> {
callback(require('./mock_data.js').default)
})
}
```
这里在dev环境下是mock数据使用了require.ensure这样当你npm run dist的时候mock的数据就不会被打包进js里了
## 最后
好了就这么多Omi让代码真心方便简洁~~~
### 相关地址
* [演示地址](http://alloyteam.github.io/omi/example/qq_nearby/dev/index.html)
* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/qq_nearby)

140
tutorial/omi-cli.md Normal file
View File

@ -0,0 +1,140 @@
# Omi命令行界面omi-cli发布
通常认为命令行界面CLI没有图形用户界面GUI那么方便用户操作。但是CLI比GUI节约资源在熟悉命令之后CLI会比GUI更加高效地帮你完成想要的任务。
下面来介绍下[pasturn](https://github.com/pasturn)童鞋为Omi开发的CLI的两种使用姿势
## 姿势一
```js
$ npm install omi-cli -g //安装cli
$ omi init your_project_name //初始化项目
$ cd your_project_name //转到项目目录
$ npm run dev //开发
$ npm run dist //部署发布
```
## 姿势二
当我们在一个空文件夹的时候,可以执行下面的命令。
```js
$ npm install omi-cli -g //安装cli
$ omi init //初始化项目
$ npm run dev //开发
$ npm run dist //部署发布
```
这里不用再去跳转目录了,当前目录就是项目的目录。
## 安装过程截图
安装omi-cli:
![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100545470-696026058.png)
安装初始化项目omi init:
![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100554891-1802174132.png)
上面的成功的界面。注意初始化项目会自动安装相关的npm依赖包所以时间较长请耐心等待。
安装完成之后,在项目目录下你可以看到下面的目录结构:
![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100755845-465268116.png)
开发 npm run dev:
![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100601235-1477801934.png)
![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100608985-921528126.png)
如果你看到了上面的界面说明一切OK了。创建出来的项目主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。Gulp用来串联整个流程Webpack + Babel让你可以写ES6和打包BrowserSync用来帮你刷浏览器不用F5了。
## 组件开发
页面的组件都在component目录:
![](http://images2015.cnblogs.com/blog/105416/201703/105416-20170309091322484-527946546.png)
你可以把组件的HTML、CSS和JS分离成三个文件然后通过require的方式使用
```js
import Omi from 'omi';
const tpl = require('./index.html');
const css = require('./index.css');
class Footer extends Omi.Component {
constructor (data) {
super(data);
}
style () {
return css;
}
render () {
return tpl;
}
}
export default Footer;
```
也可以直接all in js的方式
```js
import Omi from 'omi';
class Header extends Omi.Component {
constructor (data) {
super(data);
}
style () {
return `
<style>
.menu a:hover{
color: white;
}
</style>
`;
}
render () {
return `
<div class="head bord-btm">
<div class="logo_box">
<a href="https://github.com/AlloyTeam/omi"></a>
</div>
<ul class="menu">
<li class="github_li"><a href="https://github.com/AlloyTeam/omi">Github</a>
<li><a href="http://alloyteam.github.io/omi/example/playground/">Playground</a></li>
<li><a href="https://github.com/AlloyTeam/omi/tree/master/docs">[Edit the Docs]</a></li>
</li>
</ul>
</div>`;
}
}
export default Header;
```
如果需要更多动态编程能力可以all in js。如果纯静态不怎么需要改动的话直接分离成三个文件通过require进来便可。
## 后续
更多脚手架模板以及更多功能的命令正在开发中,如果有什么意见或者建议欢迎让我们知道。
## 相关
* Omi的Github地址[https://github.com/AlloyTeam/omi](https://github.com/AlloyTeam/omi)
* 如果想体验一下Omi框架可以访问 [Omi Playground](http://alloyteam.github.io/omi/example/playground/)
* 如果想使用Omi框架或者开发完善Omi框架可以访问 [Omi使用文档](https://github.com/AlloyTeam/omi/tree/master/docs#omi使用文档)
* 如果你想获得更佳的阅读体验,可以访问 [Docs Website](http://alloyteam.github.io/omi/website/docs.html)
* 如果你懒得搭建项目脚手架,可以试试 [omi-cli](https://github.com/AlloyTeam/omi/tree/master/cli)
* 如果你有Omi相关的问题可以 [New issue](https://github.com/AlloyTeam/omi/issues/new)
* 如果想更加方便的交流关于Omi的一切可以加入QQ的Omi交流群(256426170)
![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170208095745213-1049686133.png)

View File

@ -0,0 +1,155 @@
# omi-cli新版发布-升级webpack2和支持sass生成组件局部CSS
[omi-cli](https://github.com/AlloyTeam/omi/tree/master/cli)是[Omi](https://github.com/AlloyTeam/omi)的命令行工具。在v0.1.X以及之前版本中生成出来的项目脚手架
是基于webpack1的。由于
* webpack1不支持tree-shakingwebpack2 支持tree-shaking
* webpack1不支持 sass-loaderwebpack2 支持sass-loader
tree-shaking 作用是移除没有使用的代码有效的减小包体积
sass-loader 可以让你把sass转成css在omi项目里可以把sass转成组件的局部CSS
所以果断把omi-cli的项目模板升级为基于webpack2。感兴趣的同学可以立马尝试下。
```js
$ npm install omi-cli -g //安装cli
$ omi init your_project_name //初始化项目
$ cd your_project_name //转到项目目录
$ npm run dev //开发
$ npm run dist //部署发布
```
## 采坑之路
在升级的过程中遇到了不少问题,这里记录一下。
### 问题1
![](http://images2015.cnblogs.com/blog/105416/201703/105416-20170316082316448-1429354256.jpg)
webpack2中CommonsChunkPlugin不再支持上面的传参形式必须传JSON形式。
### 问题2
![](http://images2015.cnblogs.com/blog/105416/201703/105416-20170316082330885-1671968338.jpg)
webpack2中不在允许省略-loader的形式标记loader
```js
{test: /\.html$/, loader: "string"},
```
都要改成:
```js
{test: /\.html$/, loader: "string-loader"},
```
### 问题3
![](http://images2015.cnblogs.com/blog/105416/201703/105416-20170316082340745-1920766716.jpg)
使用webpack-stream的同学可能会碰到上面这个错误。找了好久发现
![](http://images2015.cnblogs.com/blog/105416/201703/105416-20170316082349604-1404731044.jpg)
在gulp里要修改下第二个参数把 null 改成 require('webpack')。
## sass生成组件局部CSS
在传统的webpack项目脚手架中都会包含css相关的三个loader
```js
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}]
}]
}
};
```
* sass-loader负责把sass编译成css
* css-loader负责把编出来的css转成CommonJS模块用于js里面进行require获取
* style-loader负责把css插入到页面的head里面
那么问题来了Omi内部本身组件可以定义style方法
```js
class Hello extends Omi.Component {
...
style () {
return `
h1{
cursor:pointer;
}
`;
}
...
}
```
在Omi内部的管线里面会把执行style方法把返回的css转成局部css然后插入到页面的head里面。所以和webpack三个loader里的管线有冲突怎么解决去掉一个loader便可
```js
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}]
}]
}
};
```
我们只需要能够在js里动态获取到编译好的css字符串然后拼在style方法里便可两个管线就打通了具体代码
```js
import Omi from 'omi';
const style = require('./index.scss');
class Header extends Omi.Component {
...
style () {
return style.toString();
`;
}
...
}
export default Header;
```
这里需要注意require到的style不是字符串对象需要执行toString才能获取到css字符串。
## 相关
* Omi的Github地址[https://github.com/AlloyTeam/omi](https://github.com/AlloyTeam/omi)
* 如果想体验一下Omi框架可以访问 [Omi Playground](http://alloyteam.github.io/omi/example/playground/)
* 如果想使用Omi框架或者开发完善Omi框架可以访问 [Omi使用文档](https://github.com/AlloyTeam/omi/tree/master/docs#omi使用文档)
* 如果你想获得更佳的阅读体验,可以访问 [Docs Website](http://alloyteam.github.io/omi/website/docs.html)
* 如果你懒得搭建项目脚手架,可以试试 [omi-cli](https://github.com/AlloyTeam/omi/tree/master/cli)
* 如果你有Omi相关的问题可以 [New issue](https://github.com/AlloyTeam/omi/issues/new)
* 如果想更加方便的交流关于Omi的一切可以加入QQ的Omi交流群(256426170)
![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170208095745213-1049686133.png)