从环境搭建到工具选择,从开发实例到基本概念,用简单的方式给 bnorth 编程一个快照。仅为初次接触开发准备的教程,大牛请绕行。
编程没有那么难,做了15年的码农,写代码真的和搬砖一样的水到渠成了。但是编程真的很难,没写一句都涉及了太多的语法,知识点,约定,设计思路,新手很容易望而却步。甚至都不知道怎么开始编写,需要搭建编译环境,运行环境,调试环境。《从零开始》就是希望从一步步的步骤式的引入门,再逐步补充知识。只想做到从入门到熟练而不是从入门到放弃。
注: 简单了解 html js css 知识即可阅读
开发要从底层开始,基础牢固。但是老程序员知道,站在前人肩膀上,将一部分工作外包给开源社群,让一部分代码是稳定的,是可以升级,然后集中注意力在业务上,稳定输出,高效完成任务。有了余力再去补充知识疆界。而补充知识疆界最好的方式,依然是读前人代码和分享自己设计的代码。编程是一个社群行为,而不是一个个人行为。
仅仅是跟随步骤321:
执行如下 2 条命令
npx @bnorth/cli create
npm start
几个步骤下来后,将自动启动 chrome 显示页面内容,并等待调试。
npx @bnorth/cli create
执行后,将下载并执行 bnorth 提供的脚手架命令并执行 create 子命令。create 子命令在当前目录按照模板建立了工程,工程结构如下:
import App from '@bnorth/core';
import routes from './routes';
import initStyle from './style';
import initPlugins from './plugins';
let app = new App({
plugin:{
onAppStartConfig: ()=>{app.router.setRoutes(routes) },
},
})
initStyle(app);
initPlugins(app);
app.start();
src/routes.js 文件是路由表。是地址 ‘/’ 与 Home 文件建立了联系
import Home from './pages/home';
export default {
'/': Home,
}
src/pages 是约定的页面放置的路径,其中 Home 文件是 Home 页面的代码,页面用 jsx 语法返回了一个 html 元素
import React from 'react';
let Component = props=><h1>Home Page</h1>;
Component.controller = (app,page)=>({
onPageStart: ()=>console.log('onHomePageStart'),
})
export default Component;
npm start
命令执行后:
接下来开发一个具体的 h5 小应用,看看稍微有一点业务逻辑的应用如何开发
应用由两个页面组成,主页面和城市选择页面。 主页面显示默认城市的天气信息,默认城市为北京,见下图: 城市选择页面,显示城市列表,点击后回到主页面并显示选择城市的天气信息,同时修改默认城市,见下图:
应用是对数据的获取,加工和显示。有些数据可以通过所在终端的 api 去获取,比如拍照,录音。有些数据需要通过网络请求,从服务器获取。天气预报信息,终端无法获取,而是从天气预报提供服务器获取。关于网络请求参见下面章节。 天气预报应用需要两个请求接口,可以直接在浏览器地址栏输入试试:
创建工程并进行定制化的配置
npx @bnorth/cli create
建立模板工程npm install --save @bnorth/rich.css @bnorth/components @bnorth/plugin-network @bnorth/plugin-request
, 安装几个 bnorth 工具集,分别是 样式库,组件库,网络请求库和网路请求数据单元库在 style.js 文件中,配置样式样式,其中 normal.css 是标准化样式,可消除不同浏览器差异。genCss 函数动态生成应用使用的样式库
import '@bnorth/rich.css/css/normalize.css';
import genCss from '@bnorth/rich.css';
export default function(app) {
genCss();
}
在 plugins.js 文件中,配置需要使用的插件,其中 notice 是弹出提示信息的插件,loading 是指示网络正在请求中的插件,network 和 request 配合用来从服务器获取信息
```js app.plugins.add(require(‘@bnorth/components/lib/notice’).default); app.plugins.add(require(‘@bnorth/components/lib/loading’).default); app.plugins.add(require(‘@bnorth/plugin-network’).default); app.plugins.add(require(‘@bnorth/plugin-request’).default, {request: app.network.fetch.bind(app.network)});
在 route.js 文件中,配置路由信息。即配置了两个页面路由,分别是对应 ‘/’ 的主页面和对应 ‘cities’ 的城市选择页面
export default {
'/': require('../pages/home').default,
'cities': require('../pages/cities').default,
}
页面一般由页面的 view 组件和 controller 控制器组成,view 组件描述了页面的组成和样式,controller 描述的页面的逻辑。直接上代码,先有个直观的感受,然后在下面章节逐步说明。
主页面
import React from 'react';
import View from '@bnorth/components/lib/View'
import Panel from '@bnorth/components/lib/Panel'
import NavBar from '@bnorth/components/lib/NavBar'
let Component = props=>{
let {
app,
stateWeather:{cityInfo:{city}={},
data:{
forecast:[{type,high,low,fx,fl}]=[],
ganmao, quality
}={}}
} = props;
return (
<View>
<NavBar>
<NavBar.Title>{city}</NavBar.Title>
<NavBar.Item app={()=>app.router.push('citys')}>切换城市</NavBar.Item>
</NavBar>
<Panel main className="padding-a-">
<Panel className="flex-display-block flex-align-center">
<Panel b-theme="primary" b-size="3x" className="flex-display-block flex-direction-v flex-justify-center flex-align-center">
{type}
</Panel>
<Panel className="flex-display-block flex-direction-v flex-justify-center">
<span>最高温度:{high}</span>
<span>最低温度:{low}</span>
<span>风向:{fl}</span>
<span>风力:{fx}</span>
</Panel>
</Panel>
<Panel className="border-set-a- padding-a-">
<Panel>空气质量:<Panel inline b-size="xxxl" b-theme="notice">{quality}</Panel></Panel>
<Panel>{ganmao}</Panel>
</Panel>
<Panel>
</View>
)
}
Component.controller = (app,page)=>({
stateWeather: ()=>{
state: app.Request, fetchOnStart: true, fetchOnActive: true,
url: 'http://t.weather.sojson.com/api/weather/city/'+(app.cityCode||'101010100'),
},
})
export default Component;
城市选择页面
import React from 'react';
import View from '@bnorth/components/lib/View'
import Panel from '@bnorth/components/lib/Panel'
import List from '@bnorth/components/lib/List'
let Component = props=>{
let { app, stateCitys: [] } = props;
return (
<View>
<NavBar>
<NavBar.Item app={()=>app.router.back()}>返回</NavBar.Item>
<NavBar.Title>城市选择</NavBar.Title>
</NavBar>
<Panel main>
<List>
{stateCitys.filter(v=>v.pid===0).map(v=>(
<List.Item
onClick={()=>{app.cityCode=v.city_code; app.router.back()}}
key={v.city_code} title={v.city_name} />
))}
</List>
<Panel>
</View>
)
}
Component.controller = (app,page)=>({
stateCitys: ()=>{
state: app.Request, fetchOnStart: true, initialization: [],
url: 'http://cdn.sojson.com/_city.json?attname='),
},
})
export default Component;
"dependencies": {
"@bnorth/build": "^3.1.6",
"@bnorth/core": "^3.1.6"
}
同时也配置了运行子命令:
"start": "bnorth-build server",
"build": "bnorth-build build",
因此执行 npm start
相当于运行依赖库 @bnorth/build
的 server
命令。该命令编译了工程的代码,并启动的调试服务器,之后启动系统的浏览器,打开了调试服务器的代码。并守护着,一旦用户修改了代码,将自动重新编译,并刷新页面。
启动后,将读取配置的路由表,读取指定文件的代码
加载首页面后,首先加载 controller ,首页的 controller 中配置了一个 state 名为 stateWeather 。并设置了 state: app.Request
, 说明不是一个普通的数据 state,而是 request 插件配置的网络请求的 state。其他参数 fetchOnStart: true, fetchOnActive: true,
,告诉 request,进入和回到顶层时,触发请求。因此进入时,根据参数 url 发起网络请求,请求返回时,将更新 state。
首页的组件是一个 react 无状态组件,看上去是一个普通的箭头函数(es6 定义的函数类型,具体参见后面章节),只有一个参数,页面和组件属性以 object 形式传递进来。使用解构(es6 语法,具体参见后面章节)的方式获取数据。函数的返回值,是 html 与 js 混编的 jsx 语法的布局描述。
jsx 语法并不特殊,也不是真的混编,仅仅是语法糖,bnorth-build 会通过 babel 将其转换为标准 js。见下例:
return (<h1 className="greeting">Hello, world!</h1>);
转换后:
return React.createElement('h1', {className: 'greeting'}, 'Hello, world!');
let text = 'click me';
return <button onClick={()=>alert('click')}>{text}</button>
jsx 语法中,通过 {}
将 js 代码嵌入进去
app.router.push('citys')
,调用 router 模块的 push 函数,跳转到 citys 页面app.cityCode
中,调用 app.router.back()
, 返回后首页在层回到顶层页面,触发更新,显示所选城市的天气信息当终端要处理的数据由服务器提供时,需要用到服务器通讯。移动互联网应用主要都是基于服务器通讯的应用。终端一般采集坐标,图像,声音和视频。而比如商品信息数据,天气数据,新闻资讯数据等都是由服务器以接口方式提供。
服务器通讯就是基于经典的 tcp/ip 协议,但是一般使用更高级的应用层协议 http。和一些使用或者平行于 http 的协议,比如 soap 和 websocket。现在服务器一般是轻量级的 http + json 通讯。作为大前端开发,仅需要了解基本的 http 通讯,就可以根据服务器规定的格式进行信息交互。(如果做实时通讯,比如即时通讯,邮件等还需要了解 websocket)。
与服务器通讯分为,通讯和数据承载两个方面。
在通讯方面,广泛使用的 Http 是单向通讯,即终端向服务器发出请求,服务器接收处理并返回结果给终端显示。发送的请求主要由以下几部分组成:
服务器处理后返回的结果,主要包括以下部分:
在数据承载方面,一般使用 存数据,xml 与 json。json 具体简单,体积小,与 js 结合紧密,因此一般使用 json 作为数据承载格式。
具有一个字符串属性 a,一个数值属性 b,一个布尔属性的对象 c, 一个嵌套对象的属性d, 一个嵌套数组的属性 e
{
a: 'hello',
b: 1,
c: true,
d: {a: 1},
e: [1, 2]
}
json 数组
[1, 'a', true, {a:1}]
如果是文件数据,需要通过 formdata 来承载。
let formdata = new FormData(document.getElementById("file-input"));