项目简介
以下代码实现了小米商城的仿造编写,可以实现用户登录和注册,以及小米系列商品的展示和个人信息的展示。app尚不完全后续会加入更多功能。编程软件DevEco Studio
工程目录
└─main
├─ets
│ ├─common
│ │ ├─constants
│ │ └─utils
│ ├─entryability
│ ├─entrybackupability
│ ├─model
│ ├─pages
│ ├─view
│ └─viewmodel
└─resources
├─base
│ ├─element
│ ├─media
│ └─profile
├─en_US
│ └─element
└─zh_CN
└─element
代码实现
以下为主要代码。
以下代码利用HUKS实现密钥管理操作。
import { huks } from '@kit.UniversalKeystoreKit';
import CommonConstants from '../common/constants/CommonConstants';
import Logger from '../common/utils/Logger';
import { BusinessError } from '@kit.BasicServicesKit';
import { util } from '@kit.ArkTS';
class HuksModel {
/**
* Key vector.
*/
private IV: string = '0000000000000000';
/**
* Data size.
*/
private static readonly MAX_LENGTH: number = 100*1024 / 2;
generateKeyItem(keyAlias: string) {
if (!keyAlias || keyAlias.length === 0) {
return;
}
let properties = this.getProperties();
let option: huks.HuksOptions = {
properties: properties
};
huks.generateKeyItem(keyAlias, option).then(() => {
Logger.info(CommonConstants.TAG, 'generateKeyItem success');
}).catch((error: BusinessError) => {
Logger.error(CommonConstants.TAG, `generateKeyItem failed, cause ${error.code} ${error.message}`);
})
}
/**
* Get default properties.
*/
private getProperties() {
let properties: Array<huks.HuksParam> = [];
properties[0] = {
tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
value: huks.HuksKeyAlg.HUKS_ALG_AES
};
properties[1] = {
tag: huks.HuksTag.HUKS_TAG_PURPOSE,
value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT
};
properties[2] = {
tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128
};
properties[3] = {
tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
value: huks.HuksCipherMode.HUKS_MODE_CBC
};
properties[4] = {
tag: huks.HuksTag.HUKS_TAG_PADDING,
value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7
};
return properties;
}
/**
* huks handing process
*
* @param keyAlias keyAlias key alias
* @param option huks required operation parameters
*/
async huksProcess(keyAlias: string, option: huks.HuksOptions): Promise<Uint8Array> {
if (!keyAlias || !option || keyAlias.length === 0) {
return new Uint8Array([]);
}
let result: Uint8Array = new Uint8Array();
let handle: number = 0;
await huks.initSession(keyAlias, option).then((sessionHandle) => {
handle = sessionHandle.handle;
}).catch((error: BusinessError) => {
Logger.error(CommonConstants.TAG, `updateSession failed, cause ${error.code} ${error.message}`);
})
if (option.inData && option.inData.length > HuksModel.MAX_LENGTH) {
await huks.updateSession(handle, option).then((value: huks.HuksReturnResult) => {
if (value.outData) {
result = value.outData;
}
}).catch((error: BusinessError) => {
Logger.error(CommonConstants.TAG, `updateSession failed, cause ${error.code} ${error.message}`);
})
}
await huks.finishSession(handle, option).then((value: huks.HuksReturnResult) => {
if (value.outData) {
result = new Uint8Array(Array.from(result).concat(Array.from(value.outData)));
}
}).catch((error: BusinessError) => {
Logger.error(CommonConstants.TAG, `finishSession failed, cause ${error.code} ${error.message}`);
})
return new Uint8Array(result);
}
/**
* Encrypt option.
*
* @param keyAlias key alias.
* @param data Data to be encrypted.
*/
async encrypt(keyAlias: string, data: string) {
if (!keyAlias || keyAlias.length === 0 || !data || data.length === 0) {
return;
}
let encryptData: Uint8Array = new Uint8Array();
let properties = this.getProperties();
properties[1].value = huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT;
properties.push({
tag: huks.HuksTag.HUKS_TAG_IV,
value: this.StringToUint8Array(this.IV)
} as huks.HuksParam);
let options: huks.HuksOptions = {
properties: properties,
inData: this.StringToUint8Array(data)
};
await this.huksProcess(keyAlias, options).then((result) => {
encryptData = result;
}).catch((error: BusinessError) => {
Logger.error(CommonConstants.TAG, `finishSession failed, cause ${error.code} ${error.message}`);
})
return encryptData;
}
/**
* Decrypt option.
*
* @param keyAlias key alias.
* @param data Data to be decrypted.
*/
async decrypt(keyAlias: string, data: Array<number>) {
if (!keyAlias || keyAlias.length === 0 || !data) {
return;
}
let decryptData: Uint8Array = new Uint8Array();
let properties = this.getProperties();
properties[1].value = huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT;
properties.push({
tag: huks.HuksTag.HUKS_TAG_IV,
value: this.StringToUint8Array(this.IV)
} as huks.HuksParam);
let options: huks.HuksOptions = {
properties: properties,
inData: new Uint8Array(data)
};
await this.huksProcess(keyAlias, options).then((result) => {
decryptData = result;
}).catch((error: BusinessError) => {
Logger.error(CommonConstants.TAG, `finishSession failed, cause ${error.code} ${error.message}`);
})
let result = this.Uint8ArrayToString(decryptData);
return result;
}
/**
* Converting Strings to Arrays
*
* @param str string
*/
StringToUint8Array(str: string) {
let textEncoder = util.TextEncoder.create('utf-8');
return textEncoder.encodeInto(str);
}
/**
* Converting Arrays to Strings
*
* @param fileData arrays
*/
Uint8ArrayToString(data: Uint8Array) {
let textDecoder = util.TextDecoder.create('utf-8');
return textDecoder.decodeWithStream(data);
}
/**
* check whether a key exists
*
* @param keyAlias
*/
isKeyItemExist(keyAlias: string) {
let emptyOptions: huks.HuksOptions = {
properties: []
};
return huks.isKeyItemExist(keyAlias, emptyOptions);
}
}
export default new HuksModel();
以下代码实现用户登录
import CommonConstants from '../common/constants/CommonConstants';
import { router, window } from '@kit.ArkUI';
import PreferenceModel from '../model/PreferenceModel';
import PromptUtil from '../common/utils/PromptUtil';
import { util } from '@kit.ArkTS';
import HuksModel from '../model/HuksModel';
import { BusinessError } from '@kit.BasicServicesKit';
import UserAuthModel from '../model/xiaomi-on-line-shop';
import Logger from '../common/utils/Logger';
import { RegisterPage } from '../view/RegisterPage';
@Extend(TextInput)
function inputStyle() {
.placeholderColor($r('app.color.placeholder_color'))
.height($r('app.float.login_input_height'))
.fontSize($r('app.float.big_text_size'))
.backgroundColor(Color.White)
.width(CommonConstants.FULL_PARENT)
.padding({ left: CommonConstants.INPUT_PADDING_LEFT })
.margin({ top: $r('app.float.input_margin_top') })
}
@Extend(Line)
function lineStyle() {
.width(CommonConstants.FULL_PARENT)
.height($r('app.float.line_height'))
.backgroundColor($r('app.color.line_color'))
}
@Extend(Text)
function blueTextStyle() {
.fontColor($r('app.color.login_blue_color'))
.fontSize($r('app.float.small_text_size'))
.fontWeight(FontWeight.Medium)
}
/**
* Login Page.
*/
@Entry
@Component
struct LoginPage {
@State account: string = '';
@State password: string = '';
@Provide('isFace') isFace: boolean = false;
@Provide('isFingerprint') isFingerprint: boolean = false;
@State isLogin: boolean = false;
@Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack();
@StorageLink('userLogin') userLogin: boolean = false;
private keyAlias: string = CommonConstants.LOGIN_KEYS;
onPageShow() {
window.getLastWindow(getContext(this)).then((windowStage: window.Window) => {
windowStage.setWindowPrivacyMode(true);
});
this.isFace = PreferenceModel.getPreference(CommonConstants.IS_SHOW_FACE, false) as boolean;
this.isFingerprint = PreferenceModel.getPreference(CommonConstants.IS_SHOW_FINGERPRINT, false) as boolean;
}
onPageHide(): void {
window.getLastWindow(getContext(this)).then((windowStage: window.Window) => {
windowStage.setWindowPrivacyMode(false);
});
}
@Builder
PagesMap(name: string) {
if (name === 'register') {
RegisterPage()
}
}
/**
* Check whether the login button can be clicked
*/
isLoginAvailable() {
this.isLogin = false;
if (this.account.length > 0 && this.password.length > 0) {
this.isLogin = true;
}
}
/**
* Process the login process
*/
async login() {
if (this.account === '' || this.password === '') {
PromptUtil.promptMessage($r('app.string.input_empty_tips'), CommonConstants.PROMPT_DURATION);
return;
}
let userName = PreferenceModel.getPreference(CommonConstants.USER_NAME, '') as string;
Logger.info('username' + userName)
if (this.account !== userName) {
PromptUtil.promptMessage($r('app.string.message_login_prompt'), CommonConstants.PROMPT_DURATION);
return;
}
let cryptoPassword = PreferenceModel.getPreference(CommonConstants.CRYPTO_PASSWORD, '') as string;
let base64Helper = new util.Base64Helper();
let result = base64Helper.decodeSync(cryptoPassword);
Logger.info('username' + JSON.stringify(result))
await HuksModel.decrypt(this.keyAlias, Array.from(result)).then((cryptoData?: string) => {
Logger.info('username' + cryptoData + ' ' + this.password)
if (cryptoData && cryptoData === this.password) {
this.userLogin = true;
router.replaceUrl({
url: 'pages/MainPage'
});
} else {
PromptUtil.promptMessage($r('app.string.message_login_prompt'), CommonConstants.PROMPT_DURATION);
}
}).catch((error: BusinessError) => {
Logger.error(`huks decode failed cause ${error.code} ${error.message}`);
PromptUtil.promptMessage($r('app.string.message_login_prompt'), CommonConstants.PROMPT_DURATION);
})
}
/**
* Operations After a User Is Successfully Authenticated.
*
* @param Whether the user authentication is successful.
*/
userAuthResult: (isSuccess: boolean) => void = (isSuccess: boolean) => {
if (isSuccess) {
this.userLogin = true;
router.replaceUrl({
url: 'pages/MainPage'
});
}
}
build() {
Navigation(this.pageInfos) {
Column() {
Image($r("app.media.app_icon"))
.width($r('app.float.logo_image_size'))
.height($r('app.float.logo_image_size'))
.margin({
top: $r('app.float.logo_margin_top'),
bottom: $r('app.float.logo_margin_bottom')
})
Text($r('app.string.login_page'))
.fontSize($r('app.float.title_text_size'))
.fontWeight(FontWeight.Medium)
.fontColor($r('app.color.title_text_color'))
Text($r('app.string.login_more'))
.fontSize($r('app.float.normal_text_size'))
.fontColor($r('app.color.login_text_color'))
.margin({
bottom: $r('app.float.login_bottom'),
top: $r('app.float.login_top')
})
Column() {
TextInput({ placeholder: $r('app.string.account') })
.maxLength(CommonConstants.INPUT_ACCOUNT_LENGTH)
.type(InputType.USER_NAME)
.inputStyle()
.onChange((value: string) => {
this.account = value;
this.isLoginAvailable();
})
Line().lineStyle()
TextInput({ placeholder: $r('app.string.password') })
.maxLength(CommonConstants.INPUT_PASSWORD_LENGTH)
.type(InputType.Password)
.inputStyle()
.onChange((value: string) => {
this.password = value;
this.isLoginAvailable();
})
}
.backgroundColor(Color.White)
.borderRadius($r('app.float.input_border_radius'))
.padding({
top: $r('app.float.input_padding_top'),
bottom: $r('app.float.input_padding_top'),
left: $r('app.float.input_padding_left'),
right: $r('app.float.input_padding_left')
})
Row() {
Text($r('app.string.message_login')).blueTextStyle()
Text($r('app.string.forgot_password')).blueTextStyle()
}
.justifyContent(FlexAlign.SpaceBetween)
.width(CommonConstants.FULL_PARENT)
.padding({
top: $r('app.float.forgot_margin_top'),
left: $r('app.float.forgot_margin_left'),
right: $r('app.float.forgot_margin_right')
})
Button($r('app.string.login'), { type: ButtonType.Capsule })
.width(CommonConstants.BUTTON_WIDTH)
.height($r('app.float.login_button_height'))
.fontSize($r('app.float.normal_text_size'))
.fontWeight(FontWeight.Medium)
.backgroundColor(this.isLogin ? $r('app.color.login_button_color') : $r('app.color.button_color_unavailable'))
.margin({
top: $r('app.float.button_top'),
bottom: $r('app.float.button_bottom')
})
.enabled(this.isLogin)
.onClick(() => {
this.login();
})
Text($r('app.string.register_account'))
.fontColor($r('app.color.login_blue_color'))
.fontSize($r('app.float.normal_text_size'))
.fontWeight(FontWeight.Medium)
.onClick(() => {
this.pageInfos.pushPathByName('register', null);
})
Blank()
if (this.isFace || this.isFingerprint) {
Text($r('app.string.other_login_method'))
.fontColor($r('app.color.other_login_color'))
.fontSize($r('app.float.little_text_size'))
.fontWeight(FontWeight.Medium)
.margin({
top: $r('app.float.other_margin_top'),
bottom: $r('app.float.other_margin_bottom')
})
Row({ space: CommonConstants.LOGIN_METHODS_SPACE }) {
if (this.isFace) {
Button({ type: ButtonType.Circle, stateEffect: true }) {
Image($r('app.media.face'))
}
.height($r('app.float.other_image_size'))
.width($r('app.float.other_image_size'))
.backgroundColor($r('app.color.background'))
.onClick(() => {
UserAuthModel.getFaceAuth(this.userAuthResult);
UserAuthModel.start();
})
}
if (this.isFingerprint) {
Button({ type: ButtonType.Circle, stateEffect: true }) {
Image($r('app.media.touchid'))
}
.height($r('app.float.other_image_size'))
.width($r('app.float.other_image_size'))
.backgroundColor($r('app.color.background'))
.onClick(() => {
UserAuthModel.getFingerprintAuth(this.userAuthResult);
UserAuthModel.start();
})
}
}
}
}
.backgroundColor($r('app.color.background'))
.height(CommonConstants.FULL_PARENT)
.width(CommonConstants.FULL_PARENT)
.padding({
left: $r('app.float.page_padding_hor'),
right: $r('app.float.page_padding_hor'),
bottom: $r('app.float.login_page_bottom')
})
}
.navDestination(this.PagesMap)
.hideTitleBar(true)
.hideToolBar(true)
.mode(NavigationMode.Stack)
.backgroundColor($r('app.color.background'))
}
}
以下代码实现注册功能。
import CommonConstants from '../common/constants/CommonConstants';
import PromptUtil from '../common/utils/PromptUtil';
import HuksModel from '../model/HuksModel';
import { BusinessError } from '@kit.BasicServicesKit';
import Logger from '../common/utils/Logger';
import { util } from '@kit.ArkTS';
import PreferenceModel from '../model/PreferenceModel';
import UserAuthModel from '../model/xiaomi-on-line-shop';
@Extend(TextInput)
function inputStyle() {
.placeholderColor($r('app.color.placeholder_color'))
.height($r('app.float.login_input_height'))
.fontSize($r('app.float.big_text_size'))
.backgroundColor(Color.White)
.width(CommonConstants.FULL_PARENT)
.padding({ left: CommonConstants.INPUT_PADDING_LEFT })
.margin({ top: $r('app.float.input_margin_top') })
}
@Extend(Line)
function lineStyle() {
.width(CommonConstants.FULL_PARENT)
.height($r('app.float.line_height'))
.backgroundColor($r('app.color.line_color'))
}
@Component
export struct RegisterPage {
@State isShowFace: boolean = false;
@State isShowFingerprint: boolean = false;
@State isRegisterAvailable: boolean = false;
@Consume('pageInfos') pageInfos: NavPathStack;
private name: string = '';
private passWord: string = '';
private confirmPassWord: string = '';
@Consume('isFace') isFace : boolean;
@Consume('isFingerprint') isFingerprint: boolean;
private keyAlias: string = CommonConstants.LOGIN_KEYS;
/**
* Check whether the registration button can be clicked.
*/
isRegister() {
this.isRegisterAvailable = false;
if (this.name.length > 0 && this.passWord.length > 0 && this.confirmPassWord.length > 0) {
this.isRegisterAvailable = true;
}
}
/**
* Process the registration process.
*/
async register() {
if (!this.name) {
PromptUtil.promptMessage($r('app.string.message_user_name'), CommonConstants.PROMPT_DURATION);
return;
}
if (!this.passWord || this.passWord !== this.confirmPassWord) {
PromptUtil.promptMessage($r('app.string.message_password_prompt'), CommonConstants.PROMPT_DURATION);
return;
}
let isExist = false;
await HuksModel.isKeyItemExist(this.keyAlias)
.then((value: boolean) => {
isExist = value;
})
.catch((error: BusinessError) => {
Logger.error(CommonConstants.TAG, `huks keys not generate cause ${error.code} ${error.message}`);
})
if (!isExist) {
PromptUtil.promptMessage($r('app.string.message_application_prompt'), CommonConstants.PROMPT_DURATION);
return;
}
await HuksModel.encrypt(this.keyAlias, this.passWord).then((value?: Uint8Array) => {
if (value) {
let base64Helper = new util.Base64Helper();
let password = base64Helper.encodeToStringSync(value);
PreferenceModel.putPreference(CommonConstants.CRYPTO_PASSWORD, password);
PreferenceModel.putPreference(CommonConstants.USER_NAME, this.name);
PreferenceModel.putPreference(CommonConstants.IS_SHOW_FACE, this.isFace);
PreferenceModel.putPreference(CommonConstants.IS_SHOW_FINGERPRINT, this.isFingerprint);
this.pageInfos.pop();
}
})
}
build() {
NavDestination() {
Row() {
Column() {
Image($r("app.media.app_icon"))
.width($r('app.float.logo_image_size'))
.height($r('app.float.logo_image_size'))
.margin({
top: $r('app.float.logo_margin_top'),
bottom: $r('app.float.logo_margin_bottom')
})
Text($r('app.string.register_page'))
.fontSize($r('app.float.title_text_size'))
.fontWeight(FontWeight.Medium)
.fontColor($r('app.color.title_text_color'))
Column() {
TextInput({ placeholder: $r('app.string.register_name')})
.maxLength(CommonConstants.INPUT_ACCOUNT_LENGTH)
.type(InputType.USER_NAME)
.inputStyle()
.onChange((value: string) => {
this.name = value;
this.isRegister();
})
Line().lineStyle()
TextInput({ placeholder: $r('app.string.register_password')})
.maxLength(CommonConstants.INPUT_PASSWORD_LENGTH)
.type(InputType.NEW_PASSWORD)
.inputStyle()
.onChange((value: string) => {
this.passWord = value;
this.isRegister();
})
Line().lineStyle()
TextInput({ placeholder: $r('app.string.register_confirm_password')})
.maxLength(CommonConstants.INPUT_PASSWORD_LENGTH)
.type(InputType.NEW_PASSWORD)
.inputStyle()
.onChange((value: string) => {
this.confirmPassWord = value;
this.isRegister();
})
}
.backgroundColor(Color.White)
.borderRadius($r('app.float.input_border_radius'))
.padding({
top: $r('app.float.input_padding_top'),
bottom: $r('app.float.input_padding_top'),
left: $r('app.float.input_padding_left'),
right: $r('app.float.input_padding_left')
})
.margin({
top: $r('app.float.register_margin_top')
})
if (this.isShowFace) {
Row() {
Checkbox()
.selectedColor($r('app.color.register_checkbox'))
.onChange((value: boolean) => {
this.isFace = value;
})
Text($r('app.string.register_face_checkbox'))
.fontSize($r('app.float.small_text_size'))
.fontWeight(FontWeight.Medium)
.fontColor($r('app.color.register_text_color'))
}
.width(CommonConstants.FULL_PARENT)
.margin({
top: $r('app.float.face_margin_top'),
left: $r('app.float.face_margin_left')
})
}
if (this.isShowFingerprint) {
Row() {
Checkbox()
.selectedColor($r('app.color.register_checkbox'))
.onChange((value: boolean) => {
this.isFingerprint = value;
})
Text($r('app.string.register_fingerprint_checkbox'))
.fontSize($r('app.float.small_text_size'))
.fontWeight(FontWeight.Medium)
.fontColor($r('app.color.register_text_color'))
}
.width(CommonConstants.FULL_PARENT)
.margin({
top: $r('app.float.fingerprint_margin_top'),
left: $r('app.float.face_margin_left')
})
}
Button($r('app.string.register_button'), { type: ButtonType.Capsule })
.width(CommonConstants.BUTTON_WIDTH)
.height($r('app.float.login_button_height'))
.fontSize($r('app.float.normal_text_size'))
.fontWeight(FontWeight.Medium)
.backgroundColor(
this.isRegisterAvailable ? $r('app.color.login_button_color') : $r('app.color.button_color_unavailable')
)
.margin({
top: $r('app.float.register_button_top'),
bottom: $r('app.float.button_bottom')
})
.enabled(this.isRegisterAvailable)
.onClick(async () => {
await this.register();
})
}
.backgroundColor($r('app.color.background'))
.height(CommonConstants.FULL_PARENT)
.width(CommonConstants.FULL_PARENT)
.padding({
left: $r('app.float.page_padding_hor'),
right: $r('app.float.page_padding_hor'),
bottom: $r('app.float.login_page_bottom')
})
}
.height(CommonConstants.FULL_PARENT)
}
.hideTitleBar(true)
.onAppear(() => {
HuksModel.isKeyItemExist(this.keyAlias)
.then((isExist) => {
if (!isExist) {
HuksModel.generateKeyItem(this.keyAlias);
}
})
.catch((error: BusinessError) => {
Logger.error(CommonConstants.TAG, `huks keys not generate ${error.code} ${error.message}`);
HuksModel.generateKeyItem(this.keyAlias);
})
this.isShowFace = UserAuthModel.isFaceAvailable();
this.isShowFingerprint = UserAuthModel.isFingerprintAvailable();
this.isFace = false;
this.isFingerprint = false;
})
}
}
商城主页面代码。
/**
* Home tab content.
*/
import CommonConstants from '../common/constants/CommonConstants';
import ItemData from '../model/ItemDataModel';
import mainViewModel from '../viewmodel/MainViewModel';
@Component
export default struct Home {
private swiperController: SwiperController = new SwiperController();
build() {
Scroll() {
Column({ space: CommonConstants.COMMON_SPACE }) {
Swiper(this.swiperController) {
ForEach(mainViewModel.getSwiperImages(), (img: Resource) => {
Image(img).borderRadius($r('app.float.home_swiper_radius'))
})
}
.margin({ top:$r('app.float.home_swiper_margin') })
.autoPlay(true)
Grid() {
ForEach(mainViewModel.getFirstGridData(), (item: ItemData) => {
GridItem() {
Column() {
Image(item.img)
.width($r('app.float.home_cell_size'))
.height($r('app.float.home_cell_size'))
Text(item.title)
.fontSize($r('app.float.little_text_size'))
.margin({ top: $r('app.float.home_cell_margin') })
}
}
}, (item: ItemData, index: number) => index + JSON.stringify(item))
}
.columnsTemplate(CommonConstants.HOME_COLUMNS_TEMPLATE)
.rowsTemplate(CommonConstants.HOME_ROWS_TEMPLATE)
.columnsGap($r('app.float.home_grid_gap'))
.rowsGap($r('app.float.home_row_gap'))
.padding({
top: $r('app.float.home_grid_padding'),
bottom: $r('app.float.home_grid_padding')
})
.height($r('app.float.home_grid_height'))
.backgroundColor(Color.White)
.borderRadius($r('app.float.home_border_radius'))
Text($r('app.string.home_list'))
.fontSize($r('app.float.normal_text_size'))
.fontWeight(FontWeight.Medium)
.width(CommonConstants.FULL_PARENT)
.margin({ top : $r('app.float.home_text_margin') })
Grid() {
ForEach(mainViewModel.getSecondGridData(), (secondItem: ItemData) => {
GridItem() {
Column() {
Text(secondItem.title)
.fontSize($r('app.float.normal_text_size'))
.fontWeight(FontWeight.Medium)
Text(secondItem.others)
.margin({ top: $r('app.float.home_list_margin') })
.fontSize($r('app.float.little_text_size'))
.fontColor($r('app.color.home_grid_font'))
}
.alignItems(HorizontalAlign.Start)
}
.padding({
top: $r('app.float.home_list_padding'),
left: $r('app.float.home_list_padding')
})
.borderRadius($r('app.float.home_image_radius'))
.align(Alignment.TopStart)
.backgroundImage(secondItem.img)
.backgroundImageSize(ImageSize.Cover)
.width(CommonConstants.FULL_PARENT)
.height(CommonConstants.FULL_PARENT)
}, (secondItem: ItemData, index: number) => index + JSON.stringify(secondItem))
}
.width(CommonConstants.FULL_PARENT)
.height($r('app.float.home_second_height'))
.columnsTemplate(CommonConstants.SECOND_COLUMNS_TEMPLATE)
.rowsTemplate(CommonConstants.SECOND_ROWS_TEMPLATE)
.columnsGap($r('app.float.home_grid_gap'))
.rowsGap($r('app.float.home_row_gap'))
.margin({ bottom: $r('app.float.setting_button_bottom')})
}
}
.height(CommonConstants.FULL_PARENT)
}
}
运行截图
图3-1是软件桌面显示。
图3-1
图3-2是商城登录页面。
图3-2
图3-3是商城账号注册页面。
图3-3
图3-4是商品主页面。
图3-4
图3-5是个人信息页面。
图3-5
标签:string,color,app,float,CommonConstants,HarmonyOS,小米,top,仿造 From: https://blog.csdn.net/2401_85573077/article/details/144564463