目录
前言
前面提到了数据库的构建流程、各种通用类的创建和一些细节,接下来将继续介绍各种通用组件的构建,其中包括:顶栏组件 Header.ets、提醒弹窗组件 Dialog.ets、结算弹窗组件 JieSuanDialog.ets等。
一、关键技术
- 数据库操作(包括增、删、改、查)。
- @State、@Link、@Prop、@Provide、@Consume、@Observed、@ObjectLink等装饰器的使用。
- Tabs 组件的使用。
- List 组件的使用。
- Panel组件的使用。
- 通过systemDateTime库获取系统当前时间。
- @Extend修饰器全局通用样式的使用。
- @Styles修饰器的使用。
二、实验步骤
1.顶栏组件 Header.ets
代码如下:
@Component
export struct Header {
build() {
Row(){
Text('松达的茶')
.fontColor('white')
.fontSize(30)
.padding({left: 15})
}
.width('100%')
.height('220px')
.backgroundColor('#c49a81');
}
}
2.提醒弹窗组件 Dialog.ets
作为一个通用的公共组件,其弹窗内容、确定按钮函数以及取消按钮函数都需要在调用时传参。
代码如下:
import systemDateTime from '@ohos.systemDateTime'
import dataCtrl from '../dataModel/DataCtrl'
import { Tea } from '../viewModel/Tea'
import { User } from '../viewModel/User'
@CustomDialog
@Preview
export struct Dialog {
controller: CustomDialogController
message: string
onYes: () => void
onNo: () => void
build() {
Column({space: 20}){
Text(this.message)
Row(){
Button('确定')
.onClick(() => {
this.onYes()
})
.type(ButtonType.Normal)
.borderRadius(15)
.backgroundColor('#d5be8e')
Button('取消')
.onClick(() => {
this.onNo()
})
.type(ButtonType.Normal)
.borderRadius(15)
.backgroundColor('#d5be8e')
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
}
.width('100%')
.padding(30)
}
}
3.结算弹窗组件 JieSuanDialog.ets
代码如下:
import systemDateTime from '@ohos.systemDateTime'
import dataCtrl from '../dataModel/DataCtrl'
import { Tea } from '../viewModel/Tea'
import { User } from '../viewModel/User'
@CustomDialog
export struct jieSuanDialog {
controller: CustomDialogController
// 饮料费、服务费
@Consume sumF: number
@Consume sumF_: number
@Link teas: Tea[]
// 桌号
@Prop Btno: number
// 人数
@Prop Bsum: number
// 外带
@Prop Btype: boolean
build() {
Column(){
Text(`饮料费:¥${this.sumF}`)
.width('100%')
.textAlign(TextAlign.Start)
Text(`服务费:¥${this.sumF_}`)
.width('100%')
.textAlign(TextAlign.Start)
Text(`总价:¥${this.sumF + this.sumF_}`)
.width('100%')
.textAlign(TextAlign.Start)
Text('请扫描以下二维码进行支付:')
.width('100%')
.textAlign(TextAlign.Start)
Image($r('app.media.shouKuan'))
.margin(20)
.width('70%')
Row(){
Button('完成支付')
.backgroundColor('#d6b98d')
.borderRadius(15)
.onClick(() => {
// 获取当前时间
systemDateTime.getDate(async (err,data) => {
if (err) {
console.log('08808', '获取当前时间错误!')
return
}
const nowYear = data.getFullYear().toString();
const nowMonth = (data.getMonth() + 1).toString().padStart(2, '0'); // 填充前导零
const nowDay = data.getDate().toString().padStart(2, '0')
const nowHour = data.getHours().toString().padStart(2, '0')
const nowMi = data.getMinutes().toString().padStart(2, '0')
const nowSec = data.getSeconds().toString().padStart(2, '0')
// 组装时间
let Btime: string = `${nowYear}年${nowMonth}月${nowDay}日 ${nowHour}:${nowMi}:${nowSec}`
// 组装编号:时间+账号
let Bno: string = `${nowYear}${nowMonth}${nowDay}${nowHour}${nowMi}${nowSec}${User.Uno}`
// 插入数据
await dataCtrl.insertBought(Bno,Btime,(this.Btype == true ? '外带' : '堂食'),this.sumF + this.sumF_,User.Uno,this.Btno,this.Bsum)
console.log('08808','插入订单数据')
console.log('08808',this.sumF + this.sumF_)
dataCtrl.deleteBuyCar()
this.teas = []
this.sumF = 0
this.sumF_ = 0
this.controller.close()
})
})
.type(ButtonType.Normal)
.fontColor(Color.White)
Button('取消支付')
.backgroundColor('#d6b98d')
.borderRadius(15)
.onClick(() => {
this.controller.close()
})
.type(ButtonType.Normal)
.fontColor(Color.White)
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
}
.width('100%')
.padding(10)
}
}
4.创建启动页 MainPage.ets
import router from '@ohos.router'
import window from '@ohos.window'
@Entry
@Component
struct MainPage {
aboutToAppear(){
setTimeout(
() => {
router.pushUrl(
{
url: 'pages/LogIn'
},
router.RouterMode.Single,
err => {
if(err){
console.log('08808','登录页跳转失败')
}
}
)
},
2000
)
}
build() {
Column(){
Image($r('app.media.logo_log_in'))
.sharedTransition(`log_image`, { duration: 800, curve: Curve.Linear, delay: 100 })
.width(270)
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height('100%')
.backgroundColor('#c49a81')
}
}
5.创建登录页 LogIn.ets
这里的主要细节是登录成功后直接将用户信息(包括用户名、昵称、密码)存入静态变量类StaticValue,方便以后调用。
import router from '@ohos.router'
import promptAction from '@ohos.promptAction'
import dataCtrl from '../dataModel/DataCtrl'
import { Header } from '../view/Header'
import { User } from '../viewModel/User'
@Entry
@Component
struct Index {
@State Uno: string = ''
@State Upassword: string = ''
build() {
Column(){
// 顶栏
Header()
// logo
LogoModel()
// 登录注册
LogInModel({Uno: $Uno,Upassword: $Upassword})
}
.width('100%')
.height('100%')
.backgroundColor('#fafafa')
}
}
// 登录注册模块
@Component
struct LogInModel {
@Link Uno: string
@Link Upassword: string
build() {
Column({space: 20}){
TextInput({placeholder: '请输入用户名'})
.onChange(message => {
this.Uno = message
})
.width('80%')
.borderRadius(0)
.backgroundColor('null')
.border({color: Color.Gray,style: BorderStyle.Solid,width: {
bottom: 2
}})
.backgroundColor('#00000000')
TextInput({placeholder: '请输入密码'})
.type(InputType.Password)
.onChange(message => {
this.Upassword = message
})
.width('80%')
.borderRadius(0)
.backgroundColor('null')
.border({color: Color.Gray,style: BorderStyle.Solid,width: {
bottom: 2
}})
.backgroundColor('#00000000')
// 登录注册按钮
Button('登录',{type: ButtonType.Normal})
.onClick(async () => {
if(await dataCtrl.selectUser(this.Uno,this.Upassword)) {
// 密码正确后将用户数据填入
User.Uno = this.Uno
User.Upassword = this.Upassword
User.Uname = await dataCtrl.selectUserName(this.Uno)
// 跳转
router.replaceUrl(
{
url: 'pages/HomePage',
},
router.RouterMode.Single,
err => {
if (err) {
console.log('testLog', '主页面跳转错误')
}
}
)
}
else {
promptAction.showToast({
message: '账号或密码错误!',
duration: 1500
})
}
})
.margin({top: 20})
.width('80%')
.height('15%')
.backgroundColor('#c49a81')
.fontColor(Color.White)
.fontSize(20)
Button('没有账号?点我注册',{type: ButtonType.Normal})
.onClick(() => {
router.pushUrl(
{
url: 'pages/SignUp'
},
router.RouterMode.Single,
err => {
if(err){
console.log('注册页面跳转失败')
}
}
)
})
.height('5%')
.padding(0)
.backgroundColor('#00000000')
.border({color: Color.Gray,width: {
bottom: 1
}})
.fontColor(Color.Gray)
.fontSize(15)
}
.width('100%')
.height('40%')
}
}
// logo图片
@Component
struct LogoModel {
build() {
Row(){
Image($r('app.media.logo_log_in'))
.sharedTransition(`log_image`, { duration: 800, curve: Curve.Linear, delay: 100 })
.height('100%')
}
.width('100%')
.height('25%')
.justifyContent(FlexAlign.Center)
.margin({top: 40,bottom: 40})
}
}
6.创建注册页 SignUp.ets
用于用户注册,注册成功后跳转到登录页进行登录。
需要注意各种约束,例如输入不能为空、输入不能过长等等,以及数据库查询当前账号是否已被注册。
import router from '@ohos.router'
import promptAction from '@ohos.promptAction'
import { Header } from '../view/Header'
import dataCtrl from '../dataModel/DataCtrl'
@Entry
@Component
struct SignUp {
@State Uno: string = ''
@State Uname: string = ''
@State Upassword: string = ''
@State reUpassword: string = ''
build() {
Column(){
// 顶栏
Header()
// 头像
TouXiangModel()
// 输入框及按钮
InputModel({Uno: $Uno,Uname: $Uname,Upassword: $Upassword,reUpassword: $reUpassword});
}
.width('100%')
.height('100%')
.backgroundColor('#fafafa')
}
}
// 头像
@Component
struct TouXiangModel {
build() {
Row(){
Image($r("app.media.tou_xiang"))
.height('100%')
}
.width('100%')
.height('100')
.justifyContent(FlexAlign.Center)
.margin(70)
}
}
// 输入框及按钮
@Component
struct InputModel {
@Link Uno: string
@Link Uname: string
@Link Upassword: string
@Link reUpassword: string
build() {
Column({space: 20}){
TextInput({placeholder: '请输入用户名(小于等于15位)'})
.onChange((message) => {
this.Uno = message
})
.width('90%')
.height(50)
TextInput({placeholder: '请输入昵称'})
.onChange((message) => {
this.Uname = message
})
.width('90%')
.height(50)
TextInput({placeholder: '请输入密码(小于等于15位)'})
.type(InputType.Password)
.onChange((message) => {
this.Upassword = message
})
.width('90%')
.height(50)
TextInput({placeholder: '请再次输入密码'})
.type(InputType.Password)
.onChange((message) => {
this.reUpassword = message
})
.width('90%')
.height(50)
Row(){
Button('注册')
.onClick(async () => {
if(this.reUpassword != this.Upassword){
promptAction.showToast({
message: '密码输入不一致!',
duration: 1500
})
}
else if(this.Uno == '' || this.Uname == '' || this.Upassword == ''){
promptAction.showToast({
message: '信息不可为空!',
duration: 1500
})
}
else if(!await dataCtrl.selectUser_(this.Uno)){
promptAction.showToast({
message: '此账号已存在,请修改!',
duration: 1500
})
}
else if(this.Uno.length > 15 || this.Upassword.length > 15){
promptAction.showToast({
message: '账号或密码不可大于15位,请修改!',
duration: 1500
})
}
else {
dataCtrl.insertUser(this.Uno,this.Upassword,this.Uname)
promptAction.showToast({
message: '注册成功!',
duration: 1500
})
router.back()
}
})
.width(100)
.backgroundColor('#c49a81')
Button('取消')
.onClick(() => {
router.back()
})
.width(100)
.backgroundColor('#c49a81')
}
.width('100%')
.margin({top: 20})
.justifyContent(FlexAlign.SpaceEvenly)
}
.width('100%')
.layoutWeight(1)
}
}
三、遇到的问题
问题1:对Button的样式使用@Styles封装时提醒.type非公共样式,故使用@Extend(Button),但是依旧报红。
解决方案:@Extend只能放在全局中使用。
问题2:在模拟器上运行时显示白屏。
解决方案:由于修改了Index.ets的名字,需要在EntryAbility文件里将Index改为修改后的名字。
ctrl + shift + f 全局搜索windowStage.loadConten,将第一条的pages/...修改即可。
总结
以上就是本章的主要内容,包括了顶栏组件 Header.ets、提醒弹窗组件 Dialog.ets、结算弹窗组件 JieSuanDialog.ets、登录注册等。