不久之前我重构了一个古老的项目,总结了一些js方面的想法,不过对于一个前端项目而言不仅仅只由js组成的嘛,上学的时候老师和我说html+css+JS对应的是页面的骨架、皮肤和肌肉。既然骨架我们有了,肌肉也聊完了,今天我们就来聊聊“皮肤”吧。
由于我重构的是一个react-native项目,所以我们先来说说在react-native上是怎么写样式的吧,和传统的web不一样的是,在react-native上面是没有css代码,不过得益于Yoga,我们可以在客户端上像写css一样的去书写我们的样式。我们来看看react-native文档上是怎么说的吧:
在React Native中,你并不需要学习什么特殊的语法来定义样式。我们仍然是使用JavaScript来写样式。所有的核心组件都接受名为style的属性。这些样式名基本上是遵循了web上的CSS的命名,只是按照JS的语法要求使用了驼峰命名法,例如将background-color改为backgroundColor。style属性可以是一个普通的JavaScript对象。这是最简单的用法,因而在示例代码中很常见。你还可以传入一个数组——在数组中位置居后的样式对象比居前的优先级更高,这样你可以间接实现样式的继承。
没错,你几乎不需要什么成本就可以按照写css一样的写法去写我们的rn样式,我们来看一下文档中的例子:
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
export default class LotsOfStyles extends Component {
render() {
return (
<View>
<Text style={styles.red}>just red</Text>
<Text style={{
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
}}>just bigblue</Text>
<Text style={[styles.bigblue, styles.red]}>bigblue, then red</Text>
<Text style={[styles.red, styles.bigblue]}>red, then bigblue</Text>
</View>
);
}
}
const styles = StyleSheet.create({
bigblue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});
AppRegistry.registerComponent('LotsOfStyles', () => LotsOfStyles);
在上面的demo中,我们有两种方式去写我们的样式,它和我们在写css时候遇到的外联式样式、内联式样式很相似,而项目中我们总是习惯将样式和页面分离,然后把他们都放在另外一个style.js文件中。这是个非常不错的习惯,但是也造成了一些困扰。
面对一个页面,我该怎么去模块化它的样式呢?在之前的项目中虽然做到了样式和页面的分离,让页面“看起来”干净了很多,但是在 style.js 文件中仍然是杂乱的代码,大量重复的变量、重复的内容、重复的声明。。。这个时候又有同学说了,我们可以把这些公共的变量、代码分离出来放到一个主题文件中呀,于是项目中除了各个页面的style.js之外又在全局出现了一个theme.js文件,在这里大家愉快的把诸如颜色、大小、布局等公共的代码放了进来。
这看似解决了style.js里重复冗余的代码,但是也会让我的import变得混乱:
import { StyleSheet } from 'react-native';
import {
px,
COLOR_BG_RED,
COLOR_BG_GREEN,
STYLE_FR_VC_HSB,
STYLE_FR_VC_HC,
STYLE_FR_VC_HFS,
} from 'MyStyle';
export default StyleSheet.create({
// TODO
});
看到这里,我想你除了知道我import进来了两个颜色之外,对于其它变量会一头雾水吧,除非你去MyStyle模块里面亲眼看一下才会知道真正引入进来的是些什么了,如果这里的样式特别的多的话,除了再新建一个sytle.js之外,你就只能每次回到头部去看看自己引入了些什么。这是我不能忍受的。。。
除了由于一次性引入太多的公共样式导致我要来回滑动之外,当我再去写一个新的styel.js文件时,复制这么多引入也是一件头疼的事情,那么我能不能每次只需要写一行import呢?如果我的样式都是按固定规则分类放好的是不是每次就可以只import这几个类了呢?
经常写css的同学一定注意过样式的书写顺序,某一类的属性写在一起,虽然在web中,这样写是为了优化css引擎,但是这也体现出了样式是有一定类型的,控制颜色的、控制边距的、控制布局的,那么我们的公共变量是不是也可以按照这样的规则来声明呢?
import { color, size, layout } from 'MyStyle';
这样我们文件的头部是不是就清晰多了呢?在写代码的时候,也不需要再关心我之前引入了些什么了,只要只要关注我们要写什么就行了:
export default StyleSheet.create({
lines: {
height: px(88),
backgroundColor: color.background,
borderLeftWidth: size.border,
borderRightWidth: size.border,
borderBottomWidth: size.border,
borderColor: color.border,
// 子元素横向排列,垂直居中,水平分布,中间用空格填满,最两边元素各自靠边
...layout.flex.vchbs,
},
});
在我的项目中默认边框的大小就是一个像素(1px),那么只要在最外层声明了 size.border的大小,后面写代码的时候就可以畅行无阻的书写下去了,其实我们已经模块化了,只是我们还不够彻底,不彻底就代表着我们的代码不完美,而且可复用性差,就如上面的demo,如果我们这里需要一个三面的边框,那么其它组件需不需要呢?如果需要的话是不是也可以像我这样写呢?
当然是不可以!为什么?因为我们是在复用这个边框,所以我们就不该再写一份一模一样的代码了,而是应该写类似这样的:
export default StyleSheet.create({
lines: {
height: px(88),
backgroundColor: color.background,
// 一个边框粗细为1px的红色边框
...layout.border
// 子元素横向排列,垂直居中,水平分布,中间用空格填满,最两边元素各自靠边
...layout.flex.vchbs,
},
});
这样我们的代码不仅少了很多,结构也清楚了,而且到时候替换或者修改的时候也容易一些了,不过写成这样就结束了嘛?当然不是了,我们现在有一个红色的边框,所以我们在layout模块下新增了一个border属性,那么如果我们有一个蓝色的边框呢?一个绿色的粗边框呢?我们会一直往layout模块上新增属性嘛?那最后你知道layout上面究竟有多少属性嘛?那不就又回到一开始了嘛。。。
所以,我的建议是,处于根节点的模块最好控制在3个左右:
那么第二级中的属性我也建议控制在5个左右:
这样虽然增加了深度,但是分类清晰,结构明确,复用性也比较高。虽然可能会增加项目新建时的成本(创建各种分类),但是会给后续的开发、迁移、重构、复用等带来极大的便捷。但这就结束了嘛?有的同学和我说,我有很多的边框啊,我有很多样式要复用啊,到最后我的layout也会大到看不懂啊。。。还有的同学说我没有那么多可复用的样式啊,那是不是你总结的思路就用不上了啊。当然不是咯,我们只完成了样式模块化的第一步(抽离样式),接下来开始第二步。
现在很多web开发者在书写css的时候已经不再去写原生的css了吧,而是采用例如scss、less这样的预编译语言去写样式了,那么这些预编译语言给我们带来了哪些方便呢?我想大多数同学第一时间都会想到Mixin。
利用混合器,可以很容易地在样式表的不同地方共享样式。如果你发现自己在不停地重复一段样式,那就应该把这段样式构造成优良的混合器,尤其是这段样式本身就是一个逻辑单元,比如说是一组放在一起有意义的属性。
在react-native上面,我们的样式代码是js代码,所以很天然的就自带预编译,不需要其它额外的语言去处理它,要做的只是判断你的属性是否需要一个Mixin。
判断一组属性是否应该组合成一个混合器,一条经验法则就是你能否为这个混合器想出一个好的名字。如果你能找到一个很好的短名字来描述这些属性修饰的样式,比如rounded-cornersfancy-font或者no-bullets,那么往往能够构造一个合适的混合器。如果你找不到,这时候构造一个混合器可能并不合适。
那么在js上面,我该如何实现一个Mixin呢?太简单了!我们只需要一个函数就可以了,没错,只需要一个返回对象的函数就可以做到这样的效果了,加上ES7的拓展运算符,我们就可以做到一个混合器的效果:
export default StyleSheet.create({
lines: {
height: px(88),
backgroundColor: color.background,
...layout.border(1px, '#fff')
},
});
常写react-native的同学一定都头疼过这样一个问题吧,就是我们并不能像写css样式一样在一行中把所有的属性都写完,在css中我们如果想要声明一个四面边框的大小,可以这样写:
.border {
border: 10px 5px 10px 5px;
}
那么在我们写样式的时候是不是也可以这样写:
export default StyleSheet.create({
lines: {
height: px(88),
backgroundColor: color.background,
...layout.border(10px, 5px, 10px, 5px),
},
});
我们可以通过函数的不同数量的参数来模拟传统css开发的简写属性,很多时候我们更习惯在View上面去做样式的运算,利用react-native样式的覆盖数组去不断的覆盖之前的样式来达到运算的结果,这就导致View中除了需要计算你的组件要不要展示、如何展示之外,还要去计算样式该如何写,既然我们要做样式和页面的分离,那就应该做彻底一些,将样式的计算也放在style.js中。
最后总结一下我们所做的:
我建议无论你的项目多大,代码多少,前三步都应该是一个必备的环节,可能你的项目不复杂,暂时用不到第四点,但前三条无论如何都应该尽早的去完善,这不仅仅能帮助你实现后续的迭代,也能在你的脑中保留出一个对于项目完整结构的印象,要知道样式是寄生于页面的,清楚了样式,那么页面如何你也多少会烂熟于心了。而相比于通过梳理js的逻辑去了解整个项目,我想通过页面也许会更快吧,这对刚刚接手项目的新同学来说,是非常友善的。
一般到这里,就该放上自己开源的项目地址或者安利一波作者写的库了,不过和上一篇一样,这里我们只讨论思路,表述想法,而具体的实践和代码还是要靠我们自己在项目中不断的总结和积累~
我相信很多同学对于我提到的前三点都会很快的理解,而对于第四点可能就有些懵了,该怎么去理解这个混合器呢?我该怎么用js去实现一个呢?下面我就用一段代码来举个例子,该如何实现一个Mixin:
const layout = {
// 这里的形参顺序遵循css中的 “上、右、下、左”
margin(...arg) {
let margin = {};
switch (arg.length) {
case 1:
margin = {
marginTop: arg[0],
marginRight: arg[0],
marginBottom: arg[0],
marginLeft: arg[0],
};
break;
case 2:
margin = {
marginVertical: arg[0],
marginHorizontal: arg[1],
};
break;
case 3:
margin = {
marginTop: arg[0],
marginHorizontal: arg[1],
marginBottom: arg[2],
};
break;
case 4:
margin = {
marginTop: arg[0],
marginRight: arg[1],
marginBottom: arg[2],
marginLeft: arg[3],
};
break;
default:
break;
}
return margin;
},
};
这是一个最简易的Mixin,你可以根据你的需求去写更多这样的Mixin,其实我个人觉得在项目一开始的时候是不一定需要这个的,这个存在的意义是对于复杂样式书写的,更多的情况下,你的项目只要做到了前三点,在样式这一块就已经非常的整洁、完善了,多数情况下你不需要Mixin就能组织好你的代码。
原文地址:https://www.cnblogs.com/fuhuixiang/p/8461200.html
初始化 wkwebview,设置 message handler,native 端注册了 testecho 的messageHandler,实现 WKScriptMessageHandler协议,执行JS 代码 ,所以 JS 可以通过 window.webkit.messageHandlers.testecho.postMessage 来回调客户端,和文档中说的一样
因为js语言的特性,使用node开发程序的时候经常会遇到异步处理的问题。对于之前专长App开发的我来说,会纠结node中实现客户端API请求的“最佳实践”。下面以OAuth2.0为场景,需要处理的流程:获取access token、使用获取到的token,发起API请求、处理API数据
GraphQL是一个API查询语言,他可以将使用PostgreSQL写的server代码自动生成Query或者Mutation,非常的方便。而Apollo Client就是一个强大的JavaScript GraphQL客户端。对于cache,在Apollo Client中有着强大的管理策略。
React Native 是 Facebook 2015年开源的 Javascript 框架,旨在使用 Javascript 高效开发手机端 App。根据大众的需求,我们列出了一个有用的React-Native UI库列表,可以帮助你更好地入门React Native。
在React Native 中由于业务的需要, 我们往往要在诸多的页面间,组件之间做一些参数的传递与管理, 在这里我总结了几大经过验证,稳定好用的方式给大家
随着 H5 标准的发布以及推广,使得移动应用的开发也受到了很大影响,出于效率、成本等原因,移动应用的开发不再完全依赖于 “原生”。近日越发火热的混合应用(Hybrid App)介于 Web 应用和原生应用之间
react-native打包安卓apk的时候,报错Cannot get property packageName on null object,完全没有头绪,研究了半天才发现竟然是因为package.json里面scripts自定了命令导致的,无法理解为何会影响安卓打包并且报错packageName null
之前写的项目都是人家编写好的脚手架,里面包含项目所需的环境文件,但由于有些东西用不到打包增加软件体积,所以自己从头搭建个环境。是基于 Native Base + react-navigation + Redux 的 React Native 脚手架,现在项目环境如下
Flutter作为备受关注的跨平台的开发框架,长远来看,前景肯定是比较好的,在其基础组件还未完善与成熟之前,能够高效的复用现有的native组件,是比较合适的方案。官方提供了Plugin的方式,允许将一个成熟的native组件(比如mapview)
近些年,移动端普及化越来越高,开发过程中选用 Native 还是 H5 一直是热门话题。Native 和 H5 都有着各自的优缺点,为了满足业务的需要,公司实际项目的开发过程中往往会融合两者进行 Hybrid 开发。Native 和 H5 分处两地,看起来无法联系,那么如何才能让双方协同实现功能呢?
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!