豪翔天下

Change My World by Program

0%

基础概念

**特别注意: **

  • React-Native是基于React实现的,更多语法可以参考React 开发手册
  • 如果是自己开发新产品,那么希望每次都把各个基础组件升级到最新稳定版。

React Native开发的优点

  • 拥有系统级别的通知或提醒
  • 可以访问本地通讯录、相册等资源
  • 可以针对不同的平台提供不同的体验

React Native采用的是ES2015(即ES6)的语法标准,模板上使用了自己的JSX语法(在代码中嵌入结构标记)。

环境搭建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 初始化项目
npm uninstall -g react-native-cli # 官方说不要用这个来初始化了,并且得卸载了,否则可能出现奇怪的问题
npx react-native init testProject --verbose # 新建项目目录,并初始化项目。命令会执行很久,且--verbose像没用似的,像卡死了一样
npx react-native init testProject --version 0.68.2 --verbose # 创建指定版本的项目
npx react-native init testProject --template react-native-template-typescript --verbose # 创建一个typescript的项目
npx react-native init testProject --template "react-native-template-typescript@6.10.*" --verbose # 创建一个typescript的项目,指定版本

## 运行项目
cd testProject
npx react-native start
npx pod-install
npx react-native run-ios # 第一次启动会很慢。等模拟器运行起来后可以直接Cmd+R刷新应用,Cmd+D打开调试菜单
npx react-native run-ios --simulator='iPhone 13 Pro Max' # 指定云行的模拟器的名称
npx react-native run-android # 安卓开发最好安装上android studio,这不仅会帮你安装java、jdk,而且还能直接管理安卓模拟器,把android studio配置好了以后,android的开发环境也好了

npm install --save react-native@X.Y # 直接指定版本号的更新升级,手动升级更爽。我不喜欢用react-native-git-upgrade来升级,需要注意的是,升级以后一定要顺便升级一下命令行工具react-native-cli,否则会可能会出现不预期的错误

prop&&state

两者可以说是大同小异,在大多数情况下,两者没什么很大的差别。两者的改变的时候,渲染的地方都会重新渲染。

prop: 一个组件的设置参数,可以理解为初始化参数或者对象的静态变量,并且可以在父组件中设置,在子组件中不可改变,但是可以一直往下传递至子子孙孙。

state: 更像是对象的一些变量,并且确实是经常改变的,只是父子之间不能传递。

1
2
3
4
// 动态设置某个状态值
this.setState({
results: value,
});

布局

不用css,但是类似css。所有的组件都有style属性。样式名是将默认的css的命名更改为了驼峰命名。一般使用StyleSheet.create在组件外面集中定义组件的样式。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 指定固定的高度和宽度用width和height,React Native中的尺寸都是无单位的。
<View style={{width: 50, height: '50%', backgroundColor: 'powderblue'}} />

// 弹性的高度和宽度用flex。flex为1的时候表示撑满所有的剩余空间,如果多个并列子组件一起使用,则他们会平分空间,并且值越大所占比例就越大。例如
<View style={{flex: 2, backgroundColor: 'skyblue'}} />

<View style={[styles.css1, styles.css2]} /> // 包含多个样式

// 这样还能直接看出来层级关系。例如<Text style={styles.red}>test</Text>
const styles = StyleSheet.create({
bigblue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});

Flexbox布局

规定某个组件的子元素的布局。flex的值就类似于栅栏布局中的row宽度,一个2一个1,那么画面总共可以分成三份这种,如果直接flex:1,那么就表示直接占据整个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 父视图属性
<View style={{
flex: 1,
flexDirection: 'row', // 规定布局方向,默认是column垂直方向布局,row表示水平方向布局
flexWrap:'wrap', // 默认为nowrap,表示子元素是否允许多行排列
justifyContent: 'flex-start', // 规定子元素沿着主轴的排列方式。可选项有flex-start、center、flex-end、space-around以及space-between
alignItems: 'stretch', //规定子元素沿着次轴(与主元素垂直的轴)的排列方式。可选项有flex-start、center、flex-end、stretch
}}>

// 子视图属性
<View style={{
alignSelf: 'auto', // 定义了flex容器内被选中项目的对齐方式可选auto, flex-start, flex-end, center, stretch
}}>

// flexGrow与flex有些类似,但是flex会使子元素的空间大小限定在父元素空间范围内,而flexGrow会使子元素起码维持其本身大小,再根据父元素是否有剩余空间进行空间分配。

居中问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 图标悬浮与图片的正中间,两者均居中对齐
<View style={{
justifyContent: 'center',
alignItems: 'center',
}}>
<Icon name="microphone" size={70} style={{
position: 'absolute',
zIndex: 1,
justifyContent: 'center',
alignItems: 'center'
}}/>
<Image source={require('../img/test.png')} style={{
width: 250,
height: 250,
alignItems: 'center',
justifyContent:'center',
}}
/>
</View>

定位问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 获取屏幕尺寸
import Dimensions from 'Dimensions';
Dimensions.get('window');

// 获取元素的位置: https://stackoverflow.com/questions/30096038/react-native-getting-the-position-of-an-element
class MyComponent extends React.Component {
render() {
return <View ref={view => { this.myComponent = view; }} />
}
componentDidMount() {
// Print component dimensions to console
this.myComponent.measure( (fx, fy, width, height, px, py) => {
console.log('Component width is: ' + width)
console.log('Component height is: ' + height)
console.log('X offset to frame: ' + fx)
console.log('Y offset to frame: ' + fy)
console.log('X offset to page: ' + px)
console.log('Y offset to page: ' + py)
})
}
}

组件

Animated动画

第三方库里面那些酷炫的效果均是通过动画来实现的

1
2
3
4
5
6
7
8
9
10
11
12
const top = useRef(new Animated.Value(100)).current;	// 将一个属性变为可以执行动画的属性

<Animated.View>
<View style={{top}}></View>
</Animated.View>

top.setValue(1000); // 当改变值的时候用setValue来执行,就能让改变变得平滑
Animated.timing(top, { // 也可以自定义执行时间
toValue: 1000,
duration: 500, // 默认500
delay: 100, // 默认为0
}).start()

Button基础按钮

这个组件的样式是固定的,如果需要自定义,那么高级的按钮参考Touchable系列

1
2
3
4
<Button
onPress={() => this._func()}
title="按钮标题必填"
/>

Image

图片组件,如果我们在同一个目录里面同时包含a.png/a@2x.png,a@3x.png那么react native就能通过屏幕的分辨率自动选择不同尺寸的图片,并且在代码里面仅需要require(./img/check.png)就行了。

Navigation文档,Navigation已经单独成为一个模块,强烈建议不再使用老的导航器,导航器对比,在这里有其更详细的文档。在0.44版本移除了Navigator,该模块被移动到react-native-custom-components现在也仅用于兼容老版本。使用前得先安装npm install --save react-navigation。有如下三种类型的导航器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 看官网的意思就是要安装这些东西
npm install --save @react-navigation/native react-native-screens react-native-safe-area-context @react-navigation/native-stack

# ios需要执行
npx pod-install ios

# android需要再MainActivity中添加一个方法
import android.os.Bundle;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
}

# 然后需要全局使用NavigationContainer包裹app,在app.js中
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';

export default function App() {
return (
<NavigationContainer>{/* Rest of your app code */}</NavigationContainer>
);
}

StackNavigator

类似于普通的Navigator,体现在屏幕上方的导航栏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// StackNavigator用于创建多页面应用。其中每一个都是一个Component
import React from 'react';
import { View, Text } from 'react-native';
import { StackNavigator } from 'react-navigation';

class HomeScreen extends React.Component {
static navigationOptions = ({navigation}) => {return ()}; // 可以使用return的方法,这样可以在上面写一些逻辑
static navigationOptions = ({navigation}) => ({
title: '头部标题',
headerStyle: {
backgroundColor: '#ffffff', // 设置头部样式
},
headerTintColor: '#fff',
headerTitleStyle: { // 设置头部字体样式
fontWeight: 'bold'
},
headerRight: ( // 设置header bar的左右按钮
<Button
onPress={() => alert('This is a button!')}
title="Info"
color="#fff"
/>
),
// header头中直接进行页面跳转
headerRight: (<Button onPress={() => navigation.navigate('Setting')} title={'设置'} />),

});

componentWillMount() {} // render之前执行,并且永远只执行一次
render() {} // 渲染页面
componentDidMount() {} // 组件加载完成后执行,在render之后,已经有了DOM结构,不要把其他逻辑写在render,以防阻塞UI
componentWillReceiveProps() {} // 组件接收到一个新的prop时执行,这个方法在初始化render时不会被调用
shouldComponentUpdate() {} // 返回一个布尔值
componentWillUpdate() {} // 在组件接收到新的props或者state但还没有render时执行,初始化时不会执行
componentDidUpdate() {} // 组件更新完成后

render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
}

// 可以在App.js中声明所有的页面,默认放在第一个的为首页
export default StackNavigator({
Home: {
screen: HomeScreen,
},
});

// 组件之间跳转方式
this.props.navigation.push('Home'); // 跳转至新的场景,并且将场景入栈
this.props.navigation.navigate('Home', {param1: '...'}) // 将新路由推送到堆栈导航器,如果它不在堆栈中,那么跳转到该页面
this.props.navigation.goBack()

TabNavigator

类似于ios的TabBarController,屏幕下方的标签栏

DrawerNavigator

侧边弹出的抽屉效果

SafeAreaView

  • 使用该组件包裹可以自动实现异形屏的padding,也不用考虑android还是iOS
1
2
import { SafeAreaView } from 'react-native'	// 如果不工作,就使用下面的方式
import { SafeAreaView } from 'react-native-safe-area-context'

ScrollView滚动

可以在该组件下面添加任意组件,能轻松实现几个组件的共同滑动

1
2
3
4
5
6
7
8
9
const scrollViewRef = useRef<ScrollView>(null);

<ScrollView
ref={scrollViewRef}
scrollEnabled={false} // 禁用滚动
></ScrollView>

scrollViewRef.scrollToEnd() // 滑动到底部
scrollViewRef.scrollTo({x: 0, y: 100, animated: true}) // 滑动到指定位置

StatusBar状态栏

Text

  • 默认情况下,系统字体的大小会直接影响到APP里面的显示,我们需要防止这种情况,防止用户把字体调得太大,可以在app.tsx中全局设置:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import {Text, TextInput} from 'react-native';

    if (Text.defaultProps == null) {
    Text.defaultProps = {};
    Text.defaultProps.allowFontScaling = false;
    }
    if (TextInput.defaultProps == null) {
    TextInput.defaultProps = {};
    TextInput.defaultProps.allowFontScaling = false;
    }
1
2
3
4
<Text 
numberOfLines={2} // 最多显示几行,多的会被隐藏
ellipsizeMode={'tail'} // 多的显示省略号
/>

TextInput输入框

TextInput默认宽度与父节点相同。如果想要其在没有文字的时候也能占据宽度,可以设置flex:1并且父View也得设置flex:1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<TextInput
style={{
height: 40,
alignSelf: 'center', // 输入框文字居中
alignItem: 'center',
textAlign: 'center', // 这个才是输入框里面的文字居中
}}
autoCapitalize="none" // 禁用自动大写
textContentType="oneTimeCode" // 禁用自动填充,不显示键盘上面的password选项
returnKeyType="next" // 定义keyboard键盘右下角的字体或样式,可选next、done、go、join、search、send等
onSubmitEditing={() => {
nextInputRef.current.focus(); // 如果上面的是next,并不会自动跳转,而是需要使用下一个input的ref来进行focus操作
Keyboard.dismiss(); // 隐藏键盘
}}
onChangeText={(text) => this.setState({text})}
clearTextOnFocus={true}
keyboardType="numeric" // 仅允许数字
placeholder='请输入' // 默认是灰色的
value={this.state.text}
/>

Touchable*系列

  • hitSlop属性可以让可以点击的区域比实际的要大,非常适合在移动端的点击操作

  • 包括了触摸的相关事件(触摸、点击、长按、反馈等):

    • onPressIn: 触摸开始

    • onPressOut: 触摸离开

    • onPress: 单击事件

    • onLongPress: 长按事件

TouchableHighlight

触摸点击高亮效果。点击的时候,不透明度会降低,同时会看到变暗或者变量。只支持一个子节点,如果要多个子视图组件,可以用View进行包装。

1
2
3
4
5
6
7
8
9
10
11
12
13
<TouchableHighlight onPress={this._onPressButton.bind(this)} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>TouchableHighlight</Text>
</View>
</TouchableHighlight>

// 可点击的图片
<TouchableHighlight onPress={this._onPressButton}>
<Image
style={styles.button}
source={require('./myButton.png')}
/>
</TouchableHighlight>

TouchableNativeFeedback

仅限android。

TouchableOpacity

透明度变化。

TouchableWithoutFeedback

不带反馈效果的。

API

Share分享功能

1
2
3
4
5
6
import { Share } from 'react-native';
Share.share({ // 官方文档说android用message、ios用url,但经过我的测试最好都用url,因为分享到不同的app,获取的字段并不相同
title: url,
message: url,
url: url,
})

JSX语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 使用循环
<View>
{this.state.voices.map((voice, index) => {
return (
<Text key={`voice-${voice.id}`}>
{voice.text}
</Text>
)
})}
</View>

// 定义模板(自定义标签)
const InfoText = ({ text }) => ( // 其中text是模板的参数
<View style={styles.container}>
<Text style={styles.infoText}>{text}</Text>
</View>
)
<InfoText text="haofly"/> // 使用模板

样式stylesheet

  • 官方建议不要将stylesheet放在render函数中
  • 最好不同的组件使用不同的名称,不要全都用styles命名
  • 原生不支持scss那样的嵌套语法,好像也没有啥好用的嵌套方式,就是感觉原生就是不支持什么复杂的样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const page = StyleSheet.create({
container: {
flex: 1,
padding: 24,
alignItems: "center"
}
})

const typography = StyleSheet.create({
header: {
color: "#61dafb",
fontSize: 30,
marginBottom: 36
}
})

网络请求

React Native使用的网络请求是Fetch API,但是,统治js的http请求库明显是axios,所以我还是喜欢用axios,另外,网络请求天生就应该是异步的,这两个库都是不支持同步的。

1
2
3
// 安装npm install --save axios
import axios from 'axios';
axios.get('...').then((response)=>(console.log(response.data))); // 得到响应结果,不用像fetch那样responseJson了

Debug

  • 如果是真机,可以通过摇一摇弹出debug菜单,但是基本上没啥用,最有用的可能就是Chrome里面调试了,至少能看到打印出来的object的详情

  • LogBoxrelease/production中是自动禁用的

常用插件推荐

Awesome React Native

  • 包含很多的react native的插件扩展

customauth-react-native-sdk

  • torus sdk

  • 如果运行不起来可以试试它项目里面的example,虽然文档少了,但是那个example还是更新的挺及时的,照着看有没有遗漏的,我在1.0.1版本上发现有这些需要额外配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    // ios/Podfile,具体行数参考example中的配置
    use_modular_headers
    pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec', :modular_headers => false
    installer.pods_project.build_configurations.each do |config|
    # config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
    end

    installer.pods_project.targets.each do |target|
    if target.name == "web3.swift"
    target.build_configurations.each do |config|
    config.build_settings["SWIFT_INCLUDE_PATHS[sdk=iphonesimulator*]"] = "$(inherited) $(PODS_CONFIGURATION_BUILD_DIR)/BigInt $(PODS_CONFIGURATION_BUILD_DIR)/GenericJSON $(PODS_TARGET_SRCROOT)/web3swift/lib/**"
    config.build_settings["SWIFT_INCLUDE_PATHS[sdk=iphoneos*]"] = "$(inherited) $(PODS_CONFIGURATION_BUILD_DIR)/BigInt $(PODS_CONFIGURATION_BUILD_DIR)/GenericJSON $(PODS_TARGET_SRCROOT)/web3swift/lib/**"
    end
    end
    end

    // AppDelegate.m,我最开始就是点了登录后没反应,后来发现是它根本没有监听openURL
    - (BOOL)application:(UIApplication *)app
    openURL:(NSURL *)url
    options:(NSDictionary<NSString *, id> *)options {

    NSString *myString = url.absoluteString;

    NSLog(@"String to handle : %@ ", myString);
    if (@available(iOS 10.0, *)) {
    [RNCustomAuthSdk handle:myString];
    } else {
    // Fallback on earlier versions
    }

    // Your additional URL handling (if any) goes here.
    return NO;
    }


    // ios/xxx/Info.plist,添加url scheme
    <dict>
    <key>CFBundleTypeRole</key>
    <string>Editor</string>
    <key>CFBundleURLSchemes</key>
    <array>
    <string>torusapp</string>
    </array>
    </dict>

react-native-geolocation-service

  • 谷歌定位插件,能够获取当前的定位

  • 如果出现获取不到地理位置,经常提示timed out并且time out设置为很大依然报错,可以参考这个issueLocation request timed out most of the time,下载谷歌地图然后定位一下,再重新安装一下应用试试

  • 如果出现Location settings are not satisfied: 根据我的尝试,可能是因为国内或者说是因为小米手机的问题,ios和android得不同的设置才行:

    1
    2
    3
    4
    5
    Geolocation.getCurrentPosition(
    (position) => {console.log(position)},
    (error) => {console.log(error)},
    Platform.OS === 'ios' ? { enableHighAccuracy: true, timeout: 25000, maximumAge: 20000 } : { enableHighAccuracy: false, maximumAge: 20000, forceRequestLocation: true, forceLocationManager: true, distanceFilter: 250, accuracy: { android: 'balanced', ios: 'threeKilometers' } }
    );

react-native-async-storage

  • 能够用来持久化mobx等的状态,在应用退出后不会清空
  • React-native iOS, Async storage error: "Invalid key - must be at least one character. Key: 出现这个错误是因为在getItem/setItem的时候key的值为空,需要修改一下,注意如果key的值修改后可能需要重新build才能生效

react-native-bottom-sheet

  • 一个比较好用的底部弹出功能,drawer,抽屉
  • snapPoints: 定义弹出的区域的高度,这之外的地方不能点击
  • enablePanDownToClose: 向下滑自动关闭
  • 如果是多个sheet叠加显示,好像DOM后面的就是最上层

react-native-dotenv

react-native-config

  • react-native-configreact-native-dotenv更通用,不用为每个环境变量声明typescript,并且它支持不同的环境使用不同的环境变量

  • 使用.env文件来加载环境变量

  • 需要注意的是,它是有缓存的,如果变量更改了记得参考文档清理cache

  • 如果使用的是typescript,最好参考文档使用Option 2: specify types manually

react-native-drop-shadow

  • 拖动的时候的阴影

react-native-elements

  • element 的UI套件/UI框架

react-native-fs

  • 文件操作,下载文件,保存文件

react-native-iap

  • 用于google play和apple store的内购组件
  • Android平台能够通过getProducts获取产品列表,但是购买的时候却报错That item is unavailable: 具体原因还未知,在github提交了discussion,但目前没有回复。最后不知道怎么就解决了,尝试过这些方法:
    1. 上传一个signed release到internal testing和closed testing,但是第一次上传审核时间有点久,且审核通过后可能也要等几小时才可以
    2. Google Play Console -> Setup -> API access: 打开了Play Android Developer API,应该和这个无关
    3. License testing得添加设备登录的google账号
    4. App -> Setup -> Advanced settings -> App availability设置为Published
    5. App -> Setup -> Advanced settings -> Managed Google Play设置为Turn on下面的留空就行

react-native-paper

  • material-ui在react-native平台的替代品,同样遵循material design,但是最后不推荐,集成的本来就不多,还不大好用
  • 在使用Menu.Item的时候,如果要自定义menu和整个container的高度,需要设置minHeight和maxHeight才行,不知道为啥container会默认设置为100,源码里没看到哪个地方有设置
  • ActivityIndicator就是一个loading图标,非常好用

react-native-picker

  • 滚动时间或者select选择器

react-native-qr-decode-image-camera

  • 至少从图片里面解析二维码只有这个好用点

react-native-share

  • 弹出原生的分享组件,例如分享airdrop,保存到文件夹

react-native-swipeable-list

  • 触摸滚动组件,但是已经几年没维护了,且可以直接用原生的VirtualizedList替代

react-native-text-input-mask

  • 比如电话号码输入的mask模式
  • 如果出现TypeError: null is not an object (evaluating ‘RNTextInputMask’)in v3.0.0,需要添加这行配置到podfile文件: pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text', :modular_headers => true

swiper

  • 轮播图片
  • 非常强大,各种框架几乎都支持

@testing-library/react-native

  • 测试框架

性能优化

最重要的是将需要变化的状态细化到单独的组件,这样状态变化时就不会影响到其他不需要的地方

Touchable系列组件不能很好的响应

  • 通过requestAnimationFrame,可以让组件的透明度改变效果很快切换回来,而不会卡在那儿
1
2
3
4
requestAnimationFrame(() => {
this.doExpensiveAction();
});
}

开发原生相关问题

在真实设备上调试以及打包到真实设备

在真实设备上调试,只需要在XcodeRun到你自己连接的设备即可,这时候安装在手机上面的,是和电脑上面模拟器出来的一模一样,也能进行调试,但是断开usb后应用不能使用。如果要将应用直接整体打包到设备上面,看看真实使用的效果,可以按照这个教程进行设置https://facebook.github.io/react-native/docs/running-on-device.html,主要就是修改AppDelegate.m中的jsCodeLocation的值,将其改变成如下状态即可。

1
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

APP图标设置

参考Xcode中的图标设置,也只能在xcode中设置,即直接将图标拖如Images.xcassets

原生库

开发者会将很多原生库打包成一些静态库,或者由js直接封装好了的静态库。一般比较好的静态库都能够使用命令自动链接:react-native link 某已安装的具体库名,如果手动链接可以参考文档linking-libraries-ios

TroubleShooting

  • “:CFBundleIdentifier” Does Not Exist: 可能是因为你的代码依赖的是老的react native或者node版本或者xcode版本,可以执行以下命令升级依赖:react nativeupgrade

  • undefined is not an object evaluating React.PropTypes.string: 仍然是版本的问题,新版的已经将React.PropTypes移到单独的库了(prop-types)。需要注意的是React.PropTypes.func更改成了PropTypes.function了,其他的名字没有改,只是位置变了。

  • undefined is not an object(evalauating ‘WeChat.registerApp’): 引入react-native-wechat之后手动去link

  • No bundle url present: 启动的时候报错,有以下几种解决方案:

    • 全部关了以后,看看8081端口是否被占用,然后重新react-native run-ios
    • 上面方法多次尝试不行以后直接删除node_modules目录,重新安装依赖
  • isMounted(…) is deprecated warning: 目前来看,并没有什么解决方案。

  • 闪退: 有如下几种情况

  • _this._registerevents is not a function: 升级的时候没有顺便升级react-native-cli

  • cross-env: command not found: npm install cross-env

  • unable to load script from assets index.android.bundle: 这样做能够解决(来自于Stackoverflow):

    1
    2
    3
    4
    5
    6
    mkdir android/app/src/main/assets
    react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res
    react-native run-android

    # 可以将上面的命令放到package.json的scripts中去,这样以后直接npm run android-linux即可
    "android-linux": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res && react-native run-android"
  • **SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.**原因是没有定义android sdk的位置,首先下载android sdk或者安装android studio(会自动下载sdk),最后将地址写在local.properties文件或者直接设置为环境变量ANDROID_HOME

  • **com.android.builder.testing.api.DeviceException: No connected devices! **得去android studio把安卓模拟器打开

  • react-native run-android命令提示Android project not found. Maybe run react-native android first,但是执行react-native android却说命令没找到: 首先看当前目录有没有android文件夹,如果没有,那么使用react-native eject命令生成,如果有,那么就用android studio来运行一次,看看是不是有哪些基础环境没有安装

  • Invalid YGDirection ‘row’ should be one of: (inherit, ltr, rtl): 需要将<Flex direction="row"修改为<Flex flexDirection="row"

  • Print: Entry, ":CFBundleIdentifier", Does Not Exist 解决方法如下

    1
    2
    3
    4
    # 首先关闭XCode
    cd node_modules/react-native/third-party/glog-{X}.{X}.{X}/
    ./configure
    # 然后重新打开xcdoe即可
  • Text strings must be rendered within a component: 首先最基本的,文字必须在text组件里面,但这还是比较容易排查,而不好排查的情况一般是我们在做判断的时候没有使用布尔值,例如

    1
    2
    {icon && {icon}} // 这样会报错
    {!!icon && {icon}} // 将对象转换为布尔值即可
  • 输入框键盘挡住了部分视图: 这时候需要使用KeyboardAvoidingView来包装一下view,该组件可以自动根据键盘的高度,调整自身的height或底部的padding来避免遮挡,有时候也需要再配合ScrollView来使用,注意它可以不需要在整个页面外层包装,可以只包裹住form那部分即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import { useHeaderHeight } from '@react-navigation/elements'
    const height = useHeaderHeight()

    <KeyboardAvoidingView
    behavior={Platform.OS == "ios" ? "padding" : "height"}
    style={styles.container}
    keyboardVerticalOffset={height + 47} // 如果发现高度差那么一点可以这样设置
    >
    ...
    </KeyboardAvoidingView>

    <!--如果有时候KeyboardAvoingView不起作用,可以尝试https://www.npmjs.com/package/react-native-keyboard-aware-scroll-view,例如用react-native-google-places-autocomplete的时候-->
    <KeyboardAwareScrollView extraScrollHeight={75}>
    <GooglePlacesAutocomplete />
    </KeyboardAwareScrollView>
  • ARCHS[@]: unbound variable in Xcode 12或者YogaKit.modulemap not found: 需要把Build Settings -> Architectures -> Excluded Architecture设置成这样(来自Stackoverflow):

  • You must have a keystore.properties file in the /android/ folder or set the environments variables: Android目录下新建文件keystore.properities,内容如下即可:

    1
    2
    3
    4
    STORE_FILE=app.keystore
    KEY_ALIAS=app_alias
    STORE_PASSWORD=your_password
    KEY_PASSWORD=your_password
  • Android Studio build签名APK的时候报错index.js not found:可能是因为使用了typescript,文件现在是index.tsx,可以在build.gradle文件中指定entryFile:

    1
    2
    3
    4
    project.ext.react = [
    enableHermes: false, // clean and rebuild if changing
    entryFile: "index.tsx" // 指定为tsx文件
    ]
  • Android Studio报错:ERROR: Could not find method compile() for arguments: 可能是依赖的包在调用老的java的api,找到错误日志中的文件,将compile 'xxx'修改为implementation 'xxx'

  • Android Studio真机测试报错: Unable to load script. Make sure you’re either running a Metro server (run ‘react-natvie start’) or that your bundle ‘index.android.bundle’ is packaged correctly for release. 如果metro没打开就start,如果打开了,可以尝试执行这个命令: adb reverse tcp:8081 tcp:8081

  • **Could not resolve project :react-native-camera.**这是个已经没有维护的库了,参考doc,在android/app/build.gradle中添加missingDimensionStrategy 'react-native-camera', 'general'即可

  • xcrun: error: SDK “iphoneos” cannot be located: 尝试执行sudo xcode-select --switch /Applications/Xcode.app

  • Command PhaseScriptExecution failed with a nonzero exit code: 如果无法查看错误详情,可以尝试运行Archive,可能会显示错误详情,可能就是下面这个问题,node路径没有找到

  • React-Native env: node: No such file or directory: 尝试执行sudo ln -s "$(which node)" /usr/local/bin/node

  • **No simulator found with name “iPhone 13”**运行时可以指定模拟器的名称: yarn ios --simulator="iPhone 14"

    扩展阅读
  • 浅谈前端移动开发(Ionic与React Native)

  • 30天React Native学习

splash是一个轻量级的可执行脚本的server,并且提供了友好的API,而且能直接用docker进行部署,使用起来十分方便,对于那种必须通过js才能找到内容的爬虫来说简直是如虎添翼。

安装splash

最简单的方式,使用docker安装

1
2
docker pull scrapinghub/splash
docker run --name splash -p 5023:5023 -p 8050:8050 -p 8051:8051 -d scrapinghub/splash # 即可完成部署

其中,5023表示http8050表示https8051则是telnet

splash的配置

配置文件在/app/splash/defaults.py,如果是使用docker,那么直接修改该文件即可

1
2
# 在docker内部直接修改该文件/app/splash/defaults.py
PLUGINS_ENABLED = False # 是否开启flash的执行,默认是关闭了的

splash的API

splash的API是根据其HTTP的url来定义的,前缀都是docker的域名+ip。

render.html

例如http://127.0.0.1:8050/render.html?timeout=600&wait=10&proxy=socks5://192.168.0.6:1086&url=http://haofly.net

1
2
3
4
5
# 参数说明
url: 要请求的url
timeout: js执行超时时间,默认是30s
wait: 等待js执行完成的时间,默认是0,最大是10
proxy: 设置代理

render.har

获取所有的har数据,即请求该地址的时候该网页所有的请求以及headerbody信息。

好久没有认真的看雨了。

今晚下班回家,雨很大,即使撑着我的淘宝爆款超大雨伞也被打湿了裤腿,2017年第一次有了大雨滂沱的感觉,但是却突然发现对雨,我早已没有当初的那种感觉了。

犹记得那年我们都还很年少,闲庭屋外,邀几个小伙伴对雨而坐,看着公路上的汽车飞驰而过,溅起的水花是那样的干净澄澈。那时候,我们喜欢称这种雨为毛毛雨,因为雨很大很清澈的缘故,雨滴从几万米高空倾斜而下,与地面撞击后又反弹一定高度,大概十厘米高吧,看起来就像很多很多的白毛在地上跳跃。那时候天上是有真正的乌云的。下雨前,乌云密布,随着雨渐渐地减少,乌云也慢慢散去,最后云开雾散,要么天朗气清,要么彩虹悬挂,而绝不会像现在这样,无论雨来还是雨走,天空都是灰蒙蒙的一片,仿佛对地下的人们毫无感情。

小时候,我家后面有另一户人家,而我的窗外正好能看见他们相对较矮的老式瓦片屋檐。每次下雨或者有了小孩子特有心事的时候,就会在晚上关上灯,静静地听。其实,有心事的时候,你是听不进去雨的,因为雨滴声不是时钟那种滴答滴答的声音,而是滴滴滴滴……但是因为雨持续不断地跌落在瓦上,心扉仿佛也一直被雨滴敲打着,使你也无法安静地想自己的事情,只能任由那雨继续敲打我的心扉。就这样,我不开心门,她就不停息。然后,渐渐地进入了儿时的梦想。

可是,雨总会停,我们也终于长大了。

重庆的春天其实很短的,一般都是春夏秋冬随机播放几十天后,便匆匆地迎来了漫长的夏季。可是今年,重庆的雨仿佛特别多,还赖着不走,我也才有了这番心境。现在的心是静不下来的。雨天,路过的车飞啸而过,而你却只能慢慢走回家,那种感觉,真希望自己也能尽早有辆车,以后应该可以不用再淋雨了吧。每次下雨都很烦躁,这雨一直下,什么时候是个头呀,盼望着雨一停就出去玩儿,当然,我心里明明知道,即使不下雨我也只会宅在家里。雨不是原来的雨,人还是原来的人儿吗?

推荐小时候特别喜欢的一首歌《三月里的小雨》,现在听来,歌词其实挺有韵味的。

三月里的小雨,淅沥沥沥 沥沥 淅沥沥沥下个不停,
山谷里的小溪,哗啦啦啦 啦啦 哗啦啦啦流不停,
小雨为谁飘,小溪为谁流,带著满怀的凄清。
三月里的小雨,淅沥沥沥 沥沥 淅沥沥沥下个不停,
山谷里的小溪,哗啦啦啦 啦啦 哗啦啦啦流不停,
小雨陪伴我,小溪听我诉,可知我满怀的寂寞。
请问小溪,谁带我追寻,追寻那一颗爱我的心。

三月里的小雨,淅沥沥沥 沥沥 淅沥沥沥下个不停,
山谷里的小溪,哗啦啦啦 啦啦 哗啦啦啦流不停,
小雨陪伴我,小溪听我诉,可知我满怀的寂寞。
请问小溪,谁带我追寻,追寻那一颗爱我的心。
追寻那一颗爱我的心
追寻那一颗爱我的心

这是一本去年经常出现在我视线里面的一本书,被很多大V推荐过。首先,不得不说,书中的观点确实非常独到而又富有理论依据。用诸多的例子告诉了我们,一个人的成功离不开他所处的环境、家庭教育、机遇运气,甚至民族文化,当然也免不了10000小时的努力。这也正印证了我们的一句古话:天时地利人和。

单纯从本书的文笔上看,感觉同样没有多大趣味,对于普通的读者,几乎没有仔细读下去的欲望。不知道是此书本身的问题还是翻译的问题。译者的名字我是没听过,也没发现他有什么其他的作品。当然也不能就此下结论,即使是逐字翻译的,我也觉得此书的文笔依然不符合我的口味,每个例子都讲得挺详细,但是详细中给了人啰唆的感觉。当然,本来字数就不多,在不啰唆,可能就真没几页了😂。

我小时候一直很崇拜比尔盖茨,一个大学辍学的人也能创造这样一个IT帝国,那是多么地了不起的事业呀。我曾经也幻想,不上大学也一样能成功。直到年龄越来越大,离那个不切实际的梦越来越远的时候,我才意识到,我和他之间差了多少。家庭因素、时代因素,各种各样的因素我都比不上大他,甚至那一万小时的努力我也比不上他。他虽然辍学,但人家是什么学校,我又是什么学校呢。所以比尔盖茨,现在我只能像对待偶像那样看他,永远也不能望其项背。

算一下就知道,我的努力还远远不够。10000小时是什么概念?每天编程6小时,需要花大概5年;即使每天编程24小时,也要花一年多的时间。这还只是平均数,放假过节,谁没有个休息日呢。所以碌碌无为的普通人,连10000小时都做不到,还能跟人家比什么。拼爹?别说笑了,会认真看这本书的人,有几个人有实力拼爹?

说实话,这本书对我们的思想上的帮助非常大,极大地开阔了我们的眼界,但是对我们现实中的帮助缺寥寥无几。机遇很重要,但它终归是可遇不可求的。文化传承、时代背景、社会环境,也不是你我能够改变的。我们能做的依然只有那10000小时的努力,证视自己所处的环境,把握好每一个机遇,继续在我们这个时代奋斗着。

我始终相信努力奋斗的意义,我也始终相信越努力越幸运。

摘录

  • 所谓成功就是“优势积累”的结果
  • 成功就是坚持不懈,就是顽强不屈,就是别人花30秒钟就放弃的事你却花22分钟去思考的坚定信念。
  • 成长就是要持续不断地破坏现有平衡。
  • 为什么很多人不读书?因为他们从小到大一辈子从未感受过学习的力量……不是读书改变不了命运,是读了那些没用的书改变不了命运……读书就是隔时空与作者交流思想。

新家装修,需要组装两台电脑,一台低配NAS主机,一台高配游戏主机。等到新家装修完成,大概就能写完这篇文章啦。

硬盘

选购指导

对于我来说,硬盘只有容量和类型的区别,品牌之间的差距完全可以忽略不计。

机械硬盘(传统硬盘)

如果仅仅是做NAS用,那完全没必要上SSD,因为NAS里面的数据读写频率并不高,机械硬盘的稳定性离固态硬盘的稳定性相差并不大,所以综合考虑,机械硬盘是十分适合NAS的。目前我用的是一块2015年双十一买的7200转的希捷ST1000DM003硬盘,花了273元,现在价格是319元,果然硬盘涨价了呀。

功能分类

  • 桌面硬盘: 希捷尾数为DM001,WD蓝盘,黑盘系列,东芝P300系列等
  • 监控硬盘: 视频监控,要求持续不断地写入
  • NAS硬盘: 7*24小时无间断运行,静音,5400转以下极客。
  • 企业级硬盘: 7200转,

固态硬盘(SSD)

能极大地提高幸福感的东西。

  • M.2接口不一定就比SATA接口好,决定ssd性能的事主控芯片和NAND

移动硬盘

主板

选购指导

主板的选择一是要考虑机箱的大小,不同尺寸的主板对应不同尺寸的机箱,而机箱的大小一定要与家装相匹配。另一方面,主板还需要考虑扩展性与兼容性。比如我的NAS直接就集成了CPU和GPU,断了我扩展的后路,不过这正是我想要的,集成了就不用去选择CPU和GPU,强迫症的福音,而且集成过后完全不用考虑兼容问题。

主板规格

  • ATX:俗称“大板”,最流行最常见的一种主板,305mm x 244mm
  • MATX:“小板”,244mm x 244mm
  • ITX(Mini ITX): 170mm x 170mm,我选择的nas主板华擎j3455就是这个规格,考虑到不用加太多的扩展并且正好能利用到以前笔记本剩下的内存条

电源

  • 对于我那只有十几w的NAS主机来说,淘宝随便一个电源就能解决问题,不用考虑起稳定性,再差的电源也能支撑十几w的稳定运行。

机箱

  • 机箱的规格一定要和主板的规格匹配
  • 亚克力是一种不错的DIY机箱的材料
  • 电脑不用机箱也能跑

家庭影音

家庭影音分类

  • 5.1音箱: 由左前置音箱,中置音箱,右前置音箱,左环绕,右环绕和一个低音炮组成。左前置音箱,中置音箱,右前置音箱,左环绕,右环绕五只音箱播放的是完整音乐声道,低音炮,只负责150HZ以下的低音部分。各个声道的声音是完全独立的,各音箱的分工是左前置音箱,右前置音箱主要是播放影片中的背景音乐(各种音乐,枪炮声,各种效果声),中置音箱主要播放对白,让人感觉人说话是从电视或投影幕中出来,左环绕,右环绕主要是播放各种声效如,枪炮来自身后的声音,低音炮主要是播放枪炮,爆炸,风声等声音的朝中低音部分,即150HZ以下的声音。由于低音基本没有方向感,所以低音炮的低音是5声道中任意的。这样做就是为看电影的您营造出电影画面中的效果,举个例子,在《珍珠港》中飞机在荧幕上由左向右飞过,音箱发声的顺序是左前置——中置——右前置。这样给人的感觉就是一架飞机由左至右飞过。(摘录自http://blog.sina.com.cn/s/blog_64ddbfff0100h0p5.html)
  • 2.1音箱:这种音箱是电脑音箱中最多的,有两只高音小音箱和一个低音炮组成,两只高音音箱分别是左右2声道,低音炮的低音是不分左右共用的。d音箱小巧美观,易摆放,声音层次好,由于低音没有方向感,所以这种音箱看电影听音乐都非常不错。但是在购买的时候,最好购买低音喇叭较大的,这样低音效果更好。(摘录自http://blog.sina.com.cn/s/blog_64ddbfff0100h0p5.html)
  • 2.0音箱: 标准的立体声2.0音箱。其实就是2只音箱,没有单独的低音炮。这种音箱用于发烧音箱,监听音箱,舞台音箱等专业的录扩声设备都采用标准的立体声2声道音箱,但是作为电脑桌面音箱需要小巧,所以这种音箱摆放起来不好看,除专业和电脑发烧友以外很少使用。(摘录自http://blog.sina.com.cn/s/blog_64ddbfff0100h0p5.html)

终于看完编程之美的三部曲,其实他们三本书完全不是同一个类型同一个方向的著作,感觉完全是因为中文翻译的书名的原因才把他们放在一起。不过,对比前面两者,我觉得这本书才真正把哲学上的美向大家展示了出来,毕竟,将大数据进行可视化既是当今的流行趋势,又是对数据的直观展现,相比于冷冰冰的数据,可视化的图表才是真的让他们能美起来的东西。当然这也是我觉得这本书更有意思的主要原因。

《数据之美》这本书,给我们提供了丰富的例子来说明,数据可视化的深刻意义以及非常多的应用场景。我对数据挖掘是没有多大兴趣的,但是对爬虫的兴趣倒是很深。我一直保持一个自信:只要正常浏览器能看到的,那么我就能爬取到。所以,我写了很多爬虫。爬取汽车之家的车型车系,爬取房天下的房产数据,都是自娱自乐。也挺喜欢去解决爬虫的难点问题,我自己不知道爬取数据对自己有多大用,但我只是喜欢爬数据而已。

最后,推荐两个数据可视化的前端库,highcharts(可视化的先驱,功能可以说是最强大的)ECharts(百度出的可视化工具,功能强大,但是坑多,不是吹,是真的多),以及一些数据可视化的例子(http://www.datapointed.net/)

随着见闻的逐渐加深,接触或者了解过一些其他的优秀的文档编写工具,由于未深入研究过,所以,仅仅在这里进行简单的列举:

  • APIDOC: 支持大量编程语言的根据注释自动生成文档
  • ApiGen: PHP7的类文档自动生成工具
  • YApi: 极力推荐,开源工具,拥有其他项目的收费功能,并且也支持内网部署及二次开发
  • eolinker: 暂时未了解
  • showdoc: 暂未了解
  • mindoc: 暂未了解

swagger特点

swagger是我见过唯一还算将就的一个API文档制作与展示工具,其实最终都没让我找到一款完美的API文档编写工具。

swagger优点:

  • 一个文件就是一个文档
  • 只针对API,而不针对特定的语言的API,很多自动生成API的工具基本都是只针对特定的API的
  • 支持Json和yaml来编写API文档,并且支持导出为json、yaml、markdown等格式
  • 如果编写好了API了,可以自动生成相应的SDK,没错,可能你的API接口代码还没有开始写,它就能帮你制作相应的SDK了,而且支持几乎所有主流编程语言的SDK
  • 支持自动生成大量主流编程语言/框架的server端
  • 界面清晰,无论是editor的实时展示还是ui的展示都十分人性化,其他的API编写工具基本上都做不到这一点,如果自己仅仅用markdown来编写,又要纠结该如何展现,十分痛苦。
  • 官网有直接的demo,甚至都可以不用自己搞一套服务器

swagger缺点:

  • 貌似无法更改主题
  • 中英文的文档都比较少,其主要原因应该是官网的文档本身就不完善,只有针对不同模块儿的介绍,却没有针对具体用户的文档
  • yaml文件只能和API项目本身放在一起,这一点暂时还不知道有什么解决方案
阅读全文 »

这几个月我正在阅读的是编程之美系列书籍,《架构之美》是我看的第一部。全书只有前面两个部分吸引了我,后面的基本上是食之无味地略过。后来想想,此书成书于2009年,有些思想以及对编程的认识,在那个时候可能还是特别有吸引力的,但是拿到现在,可能并没有那么大的吸引力,一是因为这本书的后面部分讲得并不深入,另一个原因是新时代的语言满天飞,老式的语言对于我这种半吊子来说毫无兴趣。

书的前面部分主要讲了一些架构的基本概念和原则。比如,美丽的架构所展示的一些普遍的原则:

  • 一处一个事实:重复导致错误,所以应该避免
  • 自动传播:由一些构建工具支持
  • 架构包含构建:架构不仅包含运行时系统,而且必须包含它的构建方式
  • 最少量机制:实现某个功能的最佳方式要视情况而定,但是美丽的架构不会追求“最佳”。
  • 构建引擎
  • 增长的阶
  • 抵制熵增

以及相应的更完整的解释:

  • 功能性(Functionality):产品向他的用户提供哪些功能
  • 可变性(Changeability):软件将来可能需要哪些改变?哪些改变不太可能发生,不需要特别容易进行这些改变?
  • 性能(Performance):产品将达到什么性能?
  • 容量(Capacity):多少用户将并发使用该系统?该系统将为用户保存多少数据?
  • 生态系统(Ecosystem): 该系统将与其他系统进行哪些交互
  • 模块化(Modularity):
  • 可构建行(Buildability): 如何将软件构建为一组组建,并能够独立实现和验证这些组件?哪些组件应该复用其他的产品,哪些应该从外部供应商处获得
  • 产品化(Producibiity): 如果产品将以几种变体的形式存在,如何开发一个产品线,并利用这些变体的共性?产品线中的产品以怎样的步骤开发等
  • 安全心(Security)

概念性的东西其实到处都有,但是在第一部分里面,即使是讲述概念方面,作者的表达方式也是非常让人有读下去的欲望的。于是顺着作者的思路就来到了一个伟大软件架构的诞生的历程,不过那几个软件奇葩的名字还真是让人费解。好在作者用了最有效最真实的方法来讲述一个软件架构如何做到完美的。要想往完美的架构迈进,首先要做的就是承认,世界上没有完美的架构,只有在不断演化中,不断适应需求中,架构才能越来越完美。其实架构本身就已经很美了,每次我看到同事画的或是自己画的架构图,都觉得真美呀,特别是当自己画的架构图能够一下子让大家都看懂的时候。正如我在实际工作中所体验的一样,本书也认为架构的输出图是最重要的,有了图,我们的工程师才知道该做什么,才知道为什么要那样做。由于保密的问题,我肯定不会把公司内部的架构图放在这里,但是相信我,我们工程师画的每一张架构图,都是特别美的。

以前的我会认为编程是一件十分简单的事情,因为无论什么语言,只需要花两三天看一下基本的语法就能用那种语言写一个东西出来,但是在实际的工作中,我才明白,编程最重要的绝对不是编程语言,编程语言反而是最次要的,最重要的是如何根据当前的需求以及未来可能出现的需求而设计出的“最完美的架构”。

语录:

软件的架构其实是和公司的组织结构及开发流程相互影响的。当然大多数情况下是软件的架构是被动者。但好的软件架构设计原则反作用于组织机构及开发流程也不是不可能的。

没有完美的架构。架构师就是力求做一个务实的“平衡美人”。不能一边坐拥着间接、长远才见效、容易视而不见的幕后优点,一边又对为了实现前者随之带来的小小应付成本挑三拣四,这样很容易捡了芝麻丢了瓜。。。

好的架构就是要分离关注点,也即“庖丁解牛,分而治之”。降低耦合性,这样复杂性也随着降低了,让参与系统各个方面的开发测试人员只需了解自己需要了解的模块,不需要了解整个系统,就能并行地进行工作了。只有这样才能开发出超越了单个人智慧所能理解的复杂软件生态系统平台。对于复杂系统的大部分参与人员:“知其然,也要知所以然”未必适用。

构架在最初构想的时候,可以脱离实际,思考出解决问题的最佳途径,但是在实施过程中,必须要考虑细节。

架构是一个过程,而非一个结果。

但是,你仍然可以不必过多担心功能就开始设计架构。你关注的是需要满足的品质。

Fred Brooks说,概念完整性是架构最重要的特征:“最好是让系统反映一组设计思想,而不是让系统包含许多好的思想,而这些思想却彼此独立而不协调”(1995)

注意:软件架构不是一成不变的。需要时就改变它。要想做到可以修改,架构就必须保持简单

像一座建筑或一个城市的物理架构一样,系统的架构必须适应环境,利用该架构创建的工件将存在于该环境之中。

在每一种情况下,我们都会先探索所有可能性,然后再做决定。我们会在“最后可能的时刻”做出决定,即不做决定的代价超过了实现该特征的代价。尽管如果一开始就用Spring,有些事情我们可能会做得不一样,但在后来加入它也没有让我们受苦。在早期的迭代中,我们关注的是发现应用想成为什么样子,而不是Spring希望我们如何构建应用。

如果,在采取了所有让任务能够由单人处理的方法之后,架构任务仍然巨大而复杂,不能由一人来完成,那么产品肯定是太复杂了,以致不实用且不应构建。换言之,单个用户必须能够理解计算机的架构。如果计划的架构不能由一个人设计,那它也不能被一个人理解。(1997)

例如,如果我们请你来设计一个“基于Web的应用”,你首先问我们页面布局和导航树,还是问下面这些问题: ·谁提供应用主机托管?托管的环境有什么技术限制吗? ·你想运行在Windows服务器上还是在LAMP栈上? ·你想支持多少并发用户? ·应用需要怎样的安全性?有需要保护的数据吗?应用将运行在公网上还是在私有的内部网上? ·你能为这些答案排列优先级吗?例如,用户数是否比响应时间更重要?

软件架构师的首要关注点不是系统的功能。

架构的最主要产出是什么?我的答案是:图。这里面有两层含义:一层含义是如同建筑师描绘的蓝图一样,用于引导实施者;另一层含义是架构师头脑中清晰的目标系统。如果架构师头脑中没有系统清晰的图像,他是没有办法把它画出来的。

看完《架构之美》过后就开始看《安全之美》,感觉大量的章节读起来的感觉都差不多,并没有深入的体会也没有感觉对我有什么启发。我想,主要的原因可能是我大学本来就是学习的计算机大类里面的信息安全专业,书里面的大部分内容以及相关推理和讨论,学校的教材里面就讲过。当然我推测,学校的教材可能也是借鉴了外国的著作,也有可能是我们学校所使用的教材本来就是高手编写的。

当然,绝对不能说这本书写得差,只能说此书在我现在的阶段所能给我的帮助太少了,如果我刚刚接触信息安全这方面,可能会特别感兴趣,也会学习到很多。不过,确实有一点,安全确实很美,但是这本书却一直没有像预期的那样透过哲学或是其他什么方式突出安全的”美“。后来,我去看了豆瓣对此书的评价,评分只有6.7,果然比《架构之美》的7.1要少。而且评价里面几乎都是差评,即使有好评,也仅仅是读者对安全的评价,并没有对此书做过多的评价。只希望最后一部《数据之美》能不再让我失望了。

我从小就是一个机械迷,喜欢木匠,喜欢硬件开发,喜欢各种DIY,有了自己的房子,我就能搭建自己的小小工作间了。

电器

电机

  • 舵机: 里面有一个控制板和一个普通电机以及减速齿轮。可以精准控制旋转角度,但是只能180度旋转。常用于机器人的手臂旋转等。
  • 减速电机: 和直流电机差不多,但是因为能减速所以扭矩非常大。
  • 直流电机: 普通的一直转的电机,扭矩比较小。
  • 步进电机: 能够控制旋转角度,扭矩属于中等。淘宝链接: 混合式57步进电机,扭矩2.3Nm,高75.5mm

  • 锂电钻: 相比于其他的电钻,主要就是携带方便,小巧玲珑,缺点是功率小,要想用来钻墙基本是不可能的。手上有一个12V不能变速的锂电钻,小幅度提升幸福感,电器的螺丝基本上可以,但是遇到需要强有力的螺丝的时候是凝不紧的,还得用手。试过用钻头钻木材,比较慢;而且夹持范围太小,1cm的钻头都夹不了。
  • 冲击钻: 和电锤原理一样,都是在旋转的时候做小幅度活塞运动。
  • 电锤: 冲击钻打不动的就用电锤了。
  • 石工钻头: 通体银白色,主要用于砖墙。
  • 木工钻头: 头上非常尖锐,主要用于木材。
  • 金工钻头(麻花钻头): 通体黑色,主要用于金属。

切磨

切磨当然是用切磨机,但是有时候也可以用电钻代替,有连接杆可以连接,但是用电钻的话并不方便实用。

  • 羊毛轮(羊毛抛光轮): 专用与抛光或修补擦伤的材料,如玻璃、陶瓷、石材、金属、塑料等
  • 切割片
  • 百叶轮:用来磨的

线

电流只与导线截面积有关。0.2平方的线是1A,0.3平方的线是1.8A,0.5平方的线可以通过2.5A/220V/550W,0.75平方的线是3.75A。

  • 杜邦线: 用于实验板的引脚扩展,可以非常牢靠地和插针连接,无需焊接,可以快速进行电路试验。
  • OK线:比普通导线细,一般用于电路板飞线,PCB跳线等,一般是30号规格,最大承受0.5A电流。价格都非常便宜。

继电器

一种电子控制器件,用较小的电流去控制较大电流的一种“自动开关”,在电路中起着自动调节、安全保护、转换电路等作用。当然,其实也能用弱电控制强电。继电器连线示意图:

继电器端口示意图

注意事项:

  • 继电器的VCC(接直流正极)与GND(接直流负极)是用来接模块的供电,必须是直流电。
  • IN端是模块触发端,当有触发信号时,继电器的输出端开关会闭合,就会通电。
  • 高电平触发(PNP触发): 正极触发,即在触发端与电源负极之间电压达到触发条件的电压时,继电器闭合。(例如,当IN端有3-12V时,继电器闭合,当IN端有0-0.5V时,继电器断开)
  • 低电平触发(NPN触发): 负极触发,即在触发端与电源负极之间电压为0V或接近0V时,继电器闭合。(例如,当IN端由0-4.5V时,继电器闭合,当IN端有大于5.5V时,继电器断开)

非电器

木料

铁料

钉子

  • 水泥钉

  • 膨胀螺丝(膨胀螺栓): 固定式灯具,如无特殊要求,墙壁开孔一般均为6毫米。

    螺栓规格(毫米) 钻孔尺寸 (毫米) 受力性能 (公斤)
    直径 深度 允许拉力 允许剪力
    M6 10.5 40 240 180
    M8 12.5 50 440 330
    M10 14.5 60 700 520
    M12 19 75 1030 740
    M16 23 100 1940 1440