❝沉寂了两个月,我又回来了。
❞
跟你们猜的一样,我已经到淘系实习了一段时间了,从上一篇文章之后就放了更多的心思在工作上。上篇文章发出去之后,我去腾讯实习了一段时间,等待阿里实习生入职流程开启。
收到淘系的实习生 offer 后,我买了人生中的第一张机票,第一次坐上了飞机,来到了一个陌生的城市——杭州。干净的街道、宽敞的沥青马路,吸引了我这个来自小城市的年轻人。
博客很久没更新了,不管是个人的网站还是掘金,都很少有更新了,偶尔上掘金看看一些好文,总想更新一下,但又没找到好的题材。现在实习了一段时间后,上手了淘系的开源跨端框架——Rax,新奇又好玩,也总结了一些「很基础」的开发技巧,补充一下官方文档的缺漏(官方文档对于新手来讲确实不太友好)。
基础部分演示项目 Git
仓库:Rax-TODO[1]
进阶技巧演示项目 Git
仓库:Software-Engineering[2](同时也是我的课程设计,欢迎大伙点个 Star
)
前面的部分是针对只有一点 React
基础的同学的,高端玩家请点击:进阶技巧[3]
这部分官网文档比较详细了,先看一下官网文档:快速开始[4]
官网文档提供的方案还挺多的,可能会选择困难,我们就从最基础的 TODO 开始,使用 Rax 搭建一个 Web 项目:
npm init rax todo-list
输入上面的命令之后,会使用 npx
安装 rax-cli
脚手架工具,安装完成后会弹出这样的界面:
added 106 packages from 53 contributors in 10.5s
? What's your project type? (Use arrow keys)
❯ App (Build universal application)
Component (Build universal component)
API (Build universal API library)
Plugin (Build plugin for miniapp)
使用 上下键
移动箭头,后面的操作同理。
这里我们就直接使用默认的选项,创建一个 APP,按下回车。
? Choose targets your project want to run? (Press <space> to select, <a> to togg
le all, <i> to invert selection)
❯◉ Web
◯ Weex
◯ Kraken (Flutter)
◯ Alibaba MiniApp
◯ WeChat MiniProgram
使用 空格键
选择,按下 字母a
可以全选,这里我们就先选择 Web,后续如果有编译为 Weex
和 小程序
的需求可以在项目目录的 build.json
中添加。
编译为 Flutter
应用的功能目前还不稳定,且坑比较多,建议动手能力强的玩家尝试,小白就先绕道吧。
? What's your application type? (Only valid in target: Web/Weex/Kraken) (Use arr
ow keys)
❯ Single-page application (SPA)
Multi-page application (MPA)
Create lite application (The simplest project setup)
选择 APP 的类型,是 SPA
还是 MPA
,这里的选项只在 Web/Weex/Kraken(Flutter)
应用中有效。
我们选择默认的选项 SPA
,不明白 SPA
和 MPA
的区别的同学,可以移步文章:认识单页应用(SPA)与多页应用(MPA)[5]
? What's author's name? (rax): 炽翎
? What type of language do you want to use? (Use arrow keys)
❯ JavaScript
TypeScript
这里我们就先选择 JavaScript
,后续如果有引入 TypeScript
的需求,可以手动引入。
? Do you want to enable these features? (Press <space> to select, <a> to toggle
all, <i> to invert selection)
❯◯ Server-side rendering (SSR) (Only valid in target: Web)
◯ Aliyun Function Compute (FaaS) (Only valid in target: Web)
◯ Compatibility with React
这里我们就什么都不选。
当然,如果有需要我们可以选择 Compatibility with React
配置与 React 的兼容,也可以为我们的应用开启 服务端渲染(SSR)
。如果有需求开启 Serverless
,也可以选择开启 功能即服务(FaaS)
。SSR
和 FaaS
都只能在 Web
应用中有效。
不懂 SSR
和 Serverless
的同学请自行百度(Google)哈。
? Do you want to install dependences automatically after initialization? (Y/n)
这里就直接回车,这个选项的意思是询问是否在初始化完成后自动安装依赖。默认是 Yes
,就不用我们手动进入项目文件夹执行 npm install
了。
To run your app:
cd todo-list
npm start
当终端出现这一段文字的时候,就说明依赖安装完了,我们可以进入到项目的文件夹下,执行 npm start
跑起我们的项目。
在执行 npm start
后,终端会显示:
Rax development server has been started:
[Web] Development server at:
http://localhost:3333/
这时候我们就可以在浏览器输入 Dev Server
的地址,查看我们的项目了。
Home
随便选择一款自己喜欢的 IDE,进入项目的文件夹,我们会看到这样的一个目录结构:
.
├── README.md # 项目说明
├── build.json # 项目构建配置
├── package.json
└── src # 源码目录
├── app.js # 应用入口文件
├── app.json # 应用配置,包括路由配置,小程序 window 配置等
├── public # (可选)静态资源目录,会拷贝内容至 build 目录
├── components # 应用的公共组件
│ └── Logo # 组件
│ ├── index.css # Logo 组件的样式文件
│ └── index.jsx # Logo 组件 JSX 源码
├── document # 页面的 HTML 模板
│ └── index.jsx
└── pages # 页面
└── Home # home 页面
└── index.jsx
开发之前,我们需要了解一些 Rax 下的一些小规矩:
rpx
:默认以 750rpx
为屏幕宽度,即 1rpx = 1/750 * 屏幕宽度
。样式简写
:在 Rax 中,由于目前兼容性的问题,不支持 部分
样式简写,例如:在写 border
样式时,应该将各个部分分开:border-width
、border-style
、border-color
。在遇到属性简写在非 Web 平台不生效的问题时,尝试将属性分开或许就能解决问题。我们要做的第一件事是删除初试化后默认的 Home
页面中的 Logo
组件,在 src/components
文件夹下,整个删除。
删除之后,src/pages/Home/index.jsx
肯定会报错,我们先稍作修改,改成 Hello World!
。
// index.jsx
import { createElement } from 'rax';
import View from 'rax-view';
import Text from 'rax-text';
import './index.css';
export default function Home() {
return (
<View className="home">
<Text>Hello World!</Text>
</View>
);
}
这个时候会发现页面变成了 Hello World!
,后面应该不用讲解太多,就是使用 React
应用开发的方式,开始愉快的 coding
过程。
可能你会发现,为什么在这里我们只能用 Rax 提供的 View
和 Text
组件?
因为为了使跨端显示效果一致,Rax 为开发者抹平了不同平台之间样式显示不一致的问题。
当然,如果你只是想用 Rax 做一个 Web 应用,那你可以使用 HTML
标签(汗)。
View
组件和 Text
组件的用法可以移步文档:基础组件-View[6] 和 基础组件-Text[7]
按照 耦合度
,我们应该将组件放在 src/pages/Home
文件夹下。
在这个文件夹下,我们创建一个这样的目录:
src/pages/Home
└── components # 组件文件夹
└── ListItem # ListItem 组件
├── index.css # CSS
└── index.jsx # JSX
首先我们应该构思一下这个 ListItem
应该暴露给父组件哪些接口:
id
onClick
事件明确了组件应该暴露的接口之后,就可以开始写代码了:
// index.jsx
import { createElement } from 'rax';
import View from 'rax-view';
import Text from 'rax-text';
import './index.css';
const ListItem = (props) => {
// 解构 id 完成状态 内容 onClick 事件
const { id, done, content, onClick } = props;
// 完成项文字样式
const style = {
fontSize: '64rpx',
lineHeight: '96rpx',
textDecoration: done && 'line-through'
};
return (
<View className="list-item" onClick={() => onClick(id)}>
<View className="list-dot"></View>
<Text style={style}>{content}</Text>
</View>
);
};
export default ListItem;
/* index.css */
.list-item {
flex-direction: row;
justify-content: flex-start;
align-items: center;
width: 100%;
height: 100rpx;
}
.list-dot {
width: 20rpx;
height: 20rpx;
margin-right: 20rpx;
border-radius: 10rpx;
background-color: #333;
}
还是一样,先创建文件:
src/pages/Home
└── components # 组件文件夹
├── List # List 组件
│ ├── index.css # CSS
│ └── index.jsx # JSX
└── ListItem # ListItem 组件
├── index.css # CSS
└── index.jsx # JSX
创建一个 List
组件作为 ListItem
的容器管理所有的 Item
,实现 添加/删除
的功能。
既然要做 添加
功能,那输入框肯定是必不可少的,在我们创建的项目里,默认是没有输入框组件的依赖的,所以我们要先安装 Rax 提供的输入框组件:
npm install rax-textinput --save
组件的用法可以转战文档:基础组件-TextInput[8]
// index.jsx
import { createElement, useState } from 'rax';
import View from 'rax-view';
import Text from 'rax-text';
import TextInput from 'rax-textinput';
import ListItem from '../ListItem';
import './index.css';
const List = () => {
// 初始化 itemId 每次添加新列表项就 +1
const [itemId, setItemId] = useState(0);
// 初始化列表
const [list, setList] = useState([]);
// 初始化 TextInput 内容
const [inputValue, setInputValue] = useState('');
// 输入框输入事件
const handleUserInput = (e) => {
setInputValue(e.target.value);
};
// 添加按钮点击事件
const handleAddButtonClick = () => {
// 构造列表项数据结构
const item = {
id: itemId,
content: inputValue,
done: false
};
// immutable 思想 生成新的引用
const newList = [...list, item];
setList(newList);
// 清空输入框
setInputValue('');
// itemId ++
setItemId(itemId + 1);
};
// 列表项点击事件
const handleItemClick = (id) => {
// 遍历列表 当事件未完成时标记为已完成 当事件已完成时删除
const newList = list.filter((item) => {
if (item.id === id) {
if (item.done) {
return false;
} else {
item.done = true;
}
}
return true;
});
setList(newList);
};
return (
<View className="list">
<View className="list-input-wrapper">
<TextInput
className="list-input"
value={inputValue}
onInput={handleUserInput}
/>
<View className="list-add-button" onClick={handleAddButtonClick}>
<Text>添加</Text>
</View>
</View>
<View className="list-item-wrapper">
{list.map((item) => (
<ListItem
key={item.id}
id={item.id}
content={item.content}
done={item.done}
onClick={handleItemClick}
/>
))}
</View>
</View>
);
};
export default List;
.list {
align-items: center;
}
.list-input-wrapper {
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.list-add-button {
justify-content: center;
align-items: center;
width: 150rpx;
height: 100rpx;
margin-left: 20rpx;
border-radius: 10px;
background-color: #dcdcdc;
}
.list-input {
width: 100%;
height: 100rpx;
line-height: 96rpx;
font-size: 64rpx;
border-width: 1px;
border-color: #dcdcdc;
}
.list-item-wrapper {
width: 100%;
}
至此,组件的基本功能就完成了。
现在我们要将组件引入首页 Home
中:
import { createElement } from 'rax';
import View from 'rax-view';
import List from './components/List';
import './index.css';
export default function Home() {
return (
<View className="home">
<List />
</View>
);
}
现在就能看到一个能完成基本功能的 TODO 应用了。
我猜,有些高玩看到我前面写的部分,肯定会说:
❝啊~ 你这个这么简单,不是有手就行嘛~
❞
有一说一,确实有手就行(误)。
前面的部分只是写给不爱读官方文档或者只有一点 React
基础的同学的,从这个部分开始,会开始引入一些高级的内容。
在前面创建的项目中,我们会看到项目的文件夹下有一个 app.json
文件,打开它你会看到:
{
"routes": [
{
"path": "/",
"source": "pages/Home/index"
}
],
"window": {
"title": "Rax App"
}
}
这个文件就是用来控制项目路由,如果后续的开发增加了更多的页面,就需要在 routes
下添加对象。path
就是你新加入的页面的访问路径(URL
),source
就是你新添加的页面所在的文件目录。
在项目文件夹下还有一个 build.json
文件,里面的内容是这样的:
{
"plugins": [
[
"build-plugin-rax-app",
{
"targets": ["web"]
}
]
]
}
因为我们之前创建项目的时候,选择的是单页应用(SPA),我们想改成多页应用怎么办?很简单:
先安装多页应用依赖:
npm install build-plugin-rax-multi-pages --save-dev
然后在 targets
所在的对象下,增加一个键 "type"
,值为 "mpa"
,像这样:
{
"plugins": [
[
"build-plugin-rax-app",
{
"targets": ["web"],
"type": "mpa"
}
]
]
}
重启 Dev Server
后会发现页面变成了这样:
MPA
我们在最开始创建项目的时候,并没有选择多平台,但是 Rax 作为一个跨端开发框架,不添加跨端支持怎么行,这里会给一个教程教大家添加跨端支持(当然一开始就选择好更方便)。
还是 build.json
文件,有一个 targets
数组,想要添加跨端支持,就在数组中添加对应的内容即可:
{
"plugins": [
[
"build-plugin-rax-app",
{
"targets": ["web", "weex", "miniapp", "wechat-miniprogram"],
"type": "mpa"
}
]
]
}
weex
对应 Weex
平台,miniapp
和 wechat-miniprogram
对应 阿里小程序
和 微信小程序
。
我们在 build.json
中使用了上面的配置后,页面会变成这个样子:
Weex
点开 Weex Preview
后,你会发现是一堆 JavaScript
代码,那怎么预览?
有一个稍微麻烦一点的方法,就是先确定你本机在内网的 IP
地址,将 URL
中的 localhost
改成内网 IP
,然后将 URL
转换为二维码(Chrome
有很多插件可以实现)。
在手机上下载 Weex Playground
然后扫描二维码,就能在手机上预览到 APP 的效果。
Weex Playground 下载地址[9]
在前面的项目里,我们没有引入 TypeScript
,那如果想引入应该怎么办?
很简单,在官网的文档中也有讲解:项目开发- TypeScript 支持[10]
只需要先安装 rax-types
和 typescript
:
npm install rax-types typescript --save-dev
在项目文件夹下创建 tsconfig.json
文件,使用以下配置:
{
"compilerOptions": {
"module": "esNext",
"target": "es2015",
"outDir": "build",
"jsx": "preserve",
"jsxFactory": "createElement",
"moduleResolution": "node",
"sourceMap": true,
"alwaysStrict": true,
"baseUrl": ".",
"paths": {
"rax": ["node_modules/rax-types"]
}
},
"include": ["./src/**/*"]
}
即可添加 TypeScript
支持。
这是一个比较大的坑,以至于让我摸索了一个上午才解决。
Rax 官方文档中并没有自动化测试相关配置的教程,以至于我只能直接在钉钉找负责 Rax 维护的师兄求助,历经千辛万苦终于将测试用例跑通。
首先,我们需要安装几个依赖,数量有点多,建议分开安装:
npm install jest --save-dev
npm install @types/jest --save-dev
npm install @babel/preset-env --save-dev
npm install babel-jest --save-dev
npm install rax-test-renderer --save-dev
npm install @babel/plugin-proposal-class-properties --save-dev
npm install @babel/plugin-proposal-decorators --save-dev
npm install @babel/plugin-proposal-export-default-from --save-dev
npm install @babel/preset-flow --save-dev
npm install @babel/preset-react --save-dev
npm install babel-plugin-transform-jsx-stylesheet --save-dev
依赖安装好之后,在项目的目录下创建 .babelrc.js
对 Babel
进行配置:
module.exports = function (api) {
// Cache the returned value forever and don't call this function again.
if (api) api.cache(true);
return {
presets: [
'@babel/preset-flow',
[
'@babel/preset-env',
{
loose: true
}
],
[
'@babel/preset-react',
{
pragma: 'createElement'
}
]
],
plugins: [
'@babel/plugin-proposal-export-default-from',
['@babel/plugin-proposal-class-properties', { loose: false }],
'babel-plugin-transform-jsx-stylesheet',
['@babel/plugin-proposal-decorators', { legacy: true }]
],
ignore: ['build', 'coverage', 'node_modules']
};
};
配置好之后,Jest
还是无法跑通的,要在 package.json
中添加启动脚本:
{
"scripts": {
"build": "build-scripts build",
"start": "build-scripts start",
"lint": "eslint --ext .js --ext .jsx ./",
// 添加 jest 启动脚本
"test": "jest"
}
}
同时,还要对 Jest
进行配置:
{
"jest": {
"collectCoverage": true,
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js"
}
}
}
配置添加完成之后,在项目的目录下创建一个文件夹:
.
└── __mocks__
├── fileMock.js # 静态资源处理
└── styleMock.js # 样式处理
分别在两个文件中加入添加代码:
// fileMock.js
module.exports = 'test-file-stub';
// styleMock.js
module.exports = {};
配置这个部分的目的是让 Jest
处理样式和静态资源时到 mock 的文件夹下找。因为在测试的时候,测试脚本并不会真的去访问引入的静态资源,遇到需要引用静态资源的地方就引导到 __mocks__
文件夹下查找,就不会因为找不到资源而报错。配置来源于 Jest
官网处理静态文件[11]。
一切配置完成后,就可以在一个需要做测试的组件下创建 __test__
文件夹并将测试脚本放在文件夹下了,或者你也可以直接使用 xxx.test.jsx
为文件命名,这些文件都会被 Jest
识别为测试脚本。
除了 Jest
,Rax 团队还为 Rax 提供了 Enzyme
适配器,示例项目:raxjs/enzyme-adapter-rax[12],提供了 Enzyme
的使用示例。
得益于淘系强大的技术实力,Rax 的相关生态相对比较完善。同时,性能也非常强大,这里我就不过多介绍了。
Rax 在小程序上的性能甚至优于市面上其他小程序框架:Rax ——完美融合编译时与运行时的双引擎小程序框架[13]。
其他的一些介绍 Rax 的文章可以移步官网的博客[14]。
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/yASag-LE_IFotrLdjRaLug
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。