1. 程式人生 > 其它 >零基礎塗鴉智慧面板SDK開發記錄(二)

零基礎塗鴉智慧面板SDK開發記錄(二)

前言

大概花了三天時間看了下相關知識,在這先吧能看懂的跟大家聊一聊。
這是我在github上找的demo https://github.com/TuyaInc/tuya-panel-kit-template
以其中的examples\lampClassic為例子。

分析

接上篇分析main.js可以分析出啟動頁(首頁),下列為首頁程式碼

import HomeBottomView from './bottom';
import Lamp from '../lamp';

const HomeScene = () => (
  <View style={styles.container}>
    <Lamp />
    <HomeBottomView />
  </View> 
);
const styles 
= StyleSheet.create({ container: { flex: 1, }, }); export default HomeScene;

從上分析得由燈和底部按鈕組成。我們現在進入lamp目錄。以下是我瞭解的

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { View, StyleSheet, Image, TouchableWithoutFeedback } from 
'react-native'; import { Utils, TYText } from 'tuya-panel-kit'; import { updateDp } from '../../redux/actions/common'; import { updateCloud } from '../../redux/actions/cloud'; import Config from '../../config'; import Strings from '../../i18n'; import LampInstance from '../../utils/LampInstance'; import { WORKMODE } from
'../../utils/constant'; import { syncThrottle, handleFifthSceneColor } from '../../utils'; import Color from '../../utils/color'; import HuePicker from '../../components/HuePicker'; import resource from '../../res'; const { convertX: cx } = Utils.RatioUtils; //React Native自行參考https://www.react-native.cn/docs/getting-started class Lamp extends Component { //先得知道React的State和Props是啥玩意 //propTypes:用來檢測props資料型別的變數,包括基本型別的的字串,布林值,數字,以及引用型別的物件,陣列,函式,甚至還有ES6新增的符號型別 //isRequired表示必傳引數 static propTypes = { power: PropTypes.bool.isRequired, workMode: PropTypes.string.isRequired, brightness: PropTypes.number.isRequired, kelvin: PropTypes.number.isRequired, colour: PropTypes.string.isRequired, sceneValue: PropTypes.string.isRequired, selectSceneColorIndex: PropTypes.number.isRequired, isEditSceneColor: PropTypes.bool.isRequired, isEditMode: PropTypes.bool.isRequired, updateDp: PropTypes.func.isRequired, selectSceneId: PropTypes.number.isRequired, scenes: PropTypes.array.isRequired, updateCloud: PropTypes.func.isRequired, }; constructor(props) { super(props); //來自utils目錄猜測是調節燈光 LampInstance.setInstance(this); //這玩意看不懂的參考這https://www.runoob.com/react/react-props.html(State 和 Props) this.state = this.initData(this.props); } // 生命週期的方法有: // componentWillMount 在渲染前呼叫,在客戶端也在服務端。 // componentDidMount : 在第一次渲染後呼叫,只在客戶端。之後元件已經生成了對應的DOM結構,可以通過this.getDOMNode()來進行訪問。 // 如果你想和其他JavaScript框架一起使用,可以在這個方法中呼叫setTimeout, setInterval或者傳送AJAX請求等操作(防止非同步操作阻塞UI)。 // componentWillReceiveProps 在元件接收到一個新的 prop (更新後)時被呼叫。這個方法在初始化render時不會被呼叫。 // shouldComponentUpdate 返回一個布林值。在元件接收到新的props或者state時被呼叫。在初始化時或者使用forceUpdate時不被呼叫。 // 可以在你確認不需要更新元件時使用。 // componentWillUpdate在元件接收到新的props或者state但還沒有render時被呼叫。在初始化時不會被呼叫。 // componentDidUpdate 在元件完成更新後立即呼叫。在初始化時不會被呼叫。 // componentWillUnmount在元件從 DOM 中移除之前立刻被呼叫。 componentWillReceiveProps(nextProps) { this.setState({ //在react中,會看到{...this.props}的程式碼,不知道是什麼意思,現在記錄一下。 //{...this.props}是props所提供的語法糖,可以將父元件的所有屬性複製給子元件 ...this.initData(nextProps), }); } setLightColor(color, brightness) { // 燈亮度效果由於1%-100%顯示比較差,對應顯示8%-100%範圍 this.shadowRef.setNativeProps({ style: { opacity: this.formatOpacity(brightness) }, }); this.ligthRef.setNativeProps({ style: { tintColor: color }, }); } // 燈亮度效果由於1%-100%顯示比較差,對應顯示8%-100%範圍 formatOpacity(brightness) { return 0.08 + ((brightness - 10) / (1000 - 10)) * (1 - 0.08); } initData(props) { const { workMode, brightness, kelvin, colour, sceneValue, isEditSceneColor, scenes, selectSceneId, selectSceneColorIndex, } = props; let currentColor = '#fff'; let currentBright = 1000; let hsv = [0, 0, 0]; switch (workMode) { case WORKMODE.WHITE: currentColor = Color.brightKelvin2rgb(1000, kelvin); currentBright = brightness; break; case WORKMODE.COLOUR: hsv = Color.decodeColourData(colour); currentColor = Color.hsv2hex(hsv[0], hsv[1], 1000); currentBright = hsv[2]; break; case WORKMODE.SCENE: { let hsvbk; if (isEditSceneColor) { const exist = scenes.find(item => item.sceneId === selectSceneId); if (exist) { const [, , , ...hsvbks] = Color.decodeSceneValue(exist.value); hsvbk = hsvbks[selectSceneColorIndex]; } } else { const [, , , ...hsvbks] = Color.decodeSceneValue(sceneValue); [hsvbk] = hsvbks; } if (!hsvbk) { hsvbk = [0, 0, 0, 0, 0]; } hsv = hsvbk; // 取第一組資料 const [h, s, v, b, k] = hsvbk; // 白光 if (b || k) { currentColor = Color.brightKelvin2rgb(1000, k); currentBright = b; } else { currentColor = Color.hsv2hex(h, s, 1000); currentBright = v; } break; } default: break; } // 標題 const modeTitle = Strings.getLang(`mode_${workMode}`); return { modeTitle, hsv, currentColor, currentBright, }; } handleChangePower = () => { const { power } = this.props; this.props.updateDp({ [Config.dpCodes.power]: !power, }); }; handleHueChange = syncThrottle( hue => { const { hsv } = this.state; const currentColor = Color.hsv2hex(hue, hsv[1], 1000); this.setLightColor(currentColor, hsv[2]); }, hue => { const { hsv } = this.state; const editHsv = [hue, hsv[1], hsv[2]]; const currentColor = Color.encodeColourControlData(...editHsv); this.props.updateDp({ [Config.dpCodes.controlData]: currentColor, }); } ); hangleHueChangeCompelete = hue => { this.handleHueChange.cancel(); const { isEditSceneColor, selectSceneId, scenes, selectSceneColorIndex } = this.props; const { hsv } = this.state; if (isEditSceneColor) { const exist = scenes.find(item => item.sceneId === selectSceneId); if (exist) { const [num, speed, mode, ...hsvbks] = Color.decodeSceneValue(exist.value); // 為了與v1版本一致,如果是第5個場景,則只顯示一個顏色,並根據使用者選擇了顏色處理成亮暗兩種顏色 const isFifth = num === 4; if (selectSceneColorIndex < hsvbks.length) { let newHsvbks = hsvbks; if (isFifth) { const [h, s, v] = hsvbks[0]; newHsvbks = handleFifthSceneColor(hue, s, v); } else { newHsvbks[selectSceneColorIndex][0] = hue; } const value = Color.encodeSceneValue([num, speed, mode, ...newHsvbks]); this.props.updateDp({ [Config.dpCodes.sceneData]: value, }); this.props.updateCloud(`scene_${+num}`, { sceneId: exist.sceneId, value }); } } } else { this.props.updateDp({ [Config.dpCodes.colourData]: Color.encodeColourData(hue, hsv[1], hsv[2]), }); } this.setState({ hsv: [hue, hsv[1], hsv[2]], }); }; //這塊是用來畫UI的,和觸發事件呼叫方法 render() { const { power, isEditMode, isEditSceneColor, workMode } = this.props; const { currentColor, currentBright, modeTitle } = this.state; const isShowHue = power && isEditMode && (workMode === WORKMODE.COLOUR || isEditSceneColor); const lampOnImage = resource.lightOn; const lampOffImage = resource.lightOff; return ( <View style={styles.container} accessibilityLabel="LampView"> {power && ( <TYText accessibilityLabel="Light_Mode_Name" style={[styles.title]}> {modeTitle} </TYText> )} <View style={styles.box}> <Image ref={ref => (this.shadowRef = ref)} source={resource.lightShadow} style={[ styles.lightShadow, { opacity: power ? this.formatOpacity(currentBright) : 0.2 }, ]} /> <TYText style={[styles.powerTip, { opacity: power ? 0 : 1 }]}> {Strings.getLang('power_tip')} </TYText> <HuePicker style={[styles.huePicker, { opacity: isShowHue ? 1 : 0 }]} hue={isShowHue ? this.state.hsv[0] : 0} touchThumbRadius={cx(25)} touchOffset={cx(8)} onChange={this.handleHueChange} onRelease={this.hangleHueChangeCompelete} onPress={this.hangleHueChangeCompelete} disabled={!isShowHue} /> <TouchableWithoutFeedback onPress={this.handleChangePower} accessibilityLabel="Light_Btn_Open" > <View style={styles.lightBtn}> <Image ref={ref => (this.ligthRef = ref)} source={power ? lampOnImage : lampOffImage} style={[ styles.light, { tintColor: power ? currentColor : 'rgba(255,255,255,0.4)' }, ]} /> </View> </TouchableWithoutFeedback> </View> </View> ); } } //React Native 中用來集中定義元件的樣式 const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, title: { width: '100%', position: 'absolute', top: cx(10), backgroundColor: 'transparent', fontSize: cx(14), textAlign: 'center', }, box: { width: cx(374), height: cx(374), alignItems: 'center', justifyContent: 'center', }, lightShadow: { width: cx(283), height: cx(284), }, lightBtn: { position: 'absolute', width: cx(120), height: cx(120), top: cx(127), left: cx(127), zIndex: 1, }, light: { width: cx(120), height: cx(120), }, powerTip: { position: 'absolute', width: '100%', bottom: cx(30), left: 0, textAlign: 'center', fontSize: cx(12), color: '#fff', backgroundColor: 'transparent', }, huePicker: { position: 'absolute', left: cx(49.5), top: cx(49.5), }, }); //React-Redux提供connect方法,用於從 UI 元件生成容器元件。connect的意思,就是將這兩種元件連起來。 export default connect( ({ dpState, cloudState }) => { const { dpCodes: { power: powerCode, workMode: workModeCode, bright: brightCode, kelvin: kelvinCode, colourData: colourDataCode, sceneData: sceneDataCode, }, } = Config; return { power: dpState[powerCode], workMode: dpState[workModeCode], brightness: Reflect.has(dpState, brightCode) ? dpState[brightCode] : 1000, kelvin: Reflect.has(dpState, kelvinCode) ? dpState[kelvinCode] : 1000, colour: dpState[colourDataCode], sceneValue: dpState[sceneDataCode], isEditMode: cloudState.isEditMode, isEditSceneColor: cloudState.isEditSceneColor, selectSceneColorIndex: cloudState.selectSceneColorIndex, selectSceneId: cloudState.selectSceneId, scenes: cloudState.scenes, }; }, dispatch => ({ updateDp: updateDp(dispatch), updateCloud: updateCloud(dispatch), }) )(Lamp);

大致知道了每個函式的用途,但實際使用還是無從下手。