arkTS开发鸿蒙OS个人商城案例【2024最新 新年限定开发案例QAQ】

news2024/11/26 16:35:13

龙年前述

源码获取>文章下方二维码,回复关键字“鸿蒙OS商场源码”

前言

arkTS是华为自己研发的一套前端语言,是在js和ts技术的基础上又进行了升级而成!

本篇文章会带领大家通过arkTS+node.js+mongoDB来完成一个鸿蒙OS版本的商城案例!

技术栈

1.arkTS

2.node.js

3.arkTS UI

4.express

5.mongoDB

技术栈讲解

arkTS

ArkTS是HarmonyOS应用开发语言。它在保持TypeScript(简称TS)基本语法风格的基础上,对TS的动态类型特性施加更严格的约束,引入静态类型。同时,提供了声明式UI、状态管理等相应的能力,让开发者可以以更简洁、更自然的方式开发高性能应用。

面向万物互联时代,华为提出一次开发多端部署、可分可合自由流转、统一生态原生智能三大应用与服务开发理念,针对多设备、多入口、服务可分可合等特性,提供多种能力协助开发者降低开发门槛,同时HarmonyOS与OpenHarmony统一生态。HarmonyOS基于JS/TS语言体系,构建了全新的声明式开发语言ArkTS。除了兼容JS/TS语言生态,ArkTS扩展了声明式UI语法和轻量化并发机制。

ArkTS是HarmonyOS主力应用开发语言。为便于熟悉Web前端的开发者快速上手,HarmonyOS在UI开发框架中,还提供了“兼容JS的类Web开发范式”。它通过模板、样式、逻辑三段式来构建相应的应用UI界面,并结合相应的运行时实现了优化的运行体验。

基本语法

装饰器: 用于装饰类、结构、方法以及变量,并赋予其特殊的含义。如上述示例中@Entry、@Component和@State都是装饰器,@Component表示自定义组件,@Entry表示该自定义组件为入口组件,@State表示组件中的状态变量,状态变量变化会触发UI刷新。

UI描述:以声明式的方式来描述UI的结构,例如build方法中的代码块。

自定义组件:可复用的UI单元,可组合其他组件,如上述被@Component装饰的struct Hello。

系统组件:ArkUI框架中默认内置的基础和容器组件,可直接被开发者调用,比如示例中的Column、Text、Divider、Button。

属性方法:组件可以通过链式调用配置多项属性,如fontSize、width、height、backgroundColor等。

事件方法:组件可以通过链式调用设置多个事件的响应逻辑,如跟随在Button后面的onClick。 [4]

声明式UI

创建组件

配置属性

配置事件

配置子组件 [5]

状态管理

状态变量:被状态装饰器装饰的变量,改变会引起UI的渲染更新。

常规变量:没有状态的变量,通常应用于辅助计算。它的改变永远不会引起UI的刷新。

数据源/同步源:状态变量的原始来源,可以同步给不同的状态数据。通常意义为父组件传给子组件的数据。

命名参数机制:父组件通过指定参数传递给子组件的状态变量,为父子传递同步参数的主要手段。示例:CompA: ({ aProp: this.aProp })。

从父组件初始化:父组件使用命名参数机制,将指定参数传递给子组件。本地初始化的默认值在有父组件传值的情况下,会被覆盖。

初始化子节点:组件中状态变量可以传递给子组件,初始化子组件对应的状态变量。示例同上。

本地初始化:变量声明的时候赋值,作为初始化的默认值。示例:@State count: number = 0。 [6]

渲染控制

ArkUI通过自定义组件的build函数和@builder装饰器中的声明式UI描述语句构建相应的UI。在声明式描述语句中开发者除了使用系统组件外,还可以使用渲染控制语句来辅助UI的构建,这些渲染控制语句包括控制组件是否显示的条件渲染语句,基于数组数据快速生成组件的循环渲染语句以及针对大数据量场景的数据懒加载语句

node.js

Node.js发布于2009年5月,由Ryan Dahl开发,是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O模型, [1]让JavaScript 运行在服务端的开发平台,它让JavaScript成为与PHP、Python、Perl、Ruby等服务端语言平起平坐的脚本语言。

Node.js对一些特殊用例进行优化,提供替代的API,使得V8在非浏览器环境下运行得更好,V8引擎执行Javascript的速度非常快,性能非常好,基于Chrome JavaScript运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。

2009年2月,Ryan Dahl在博客上宣布准备基于V8创建一个轻量级的Web服务器并提供一套库。

2009年5月,Ryan Dahl在GitHub上发布了最初版本的部分Node包,随后几个月里,有人开始使用Node开发应用。

2009年11月和2010年4月,两届JSConf大会都安排了Node.js的讲座。

2010年年底,Node获得云计算服务商Joyent资助,创始人Ryan Dahl加入Joyent全职负责Node的发展。

2011年7月,Node在微软的支持下发布Windows版本。

2016年,leftpad事件,Yarn诞生

2021年,发布最新版本Node.js 17 [3]

V8引擎本身使用了一些最新的编译技术。这使得用Javascript这类脚本语言编写出来的代码运行速度获得了极大提升,又节省了开发成本。对性能的苛求是Node的一个关键因素。 Javascript是一个事件驱动语言,Node利用了这个优点,编写出可扩展性高的服务器。Node采用了一个称为“事件循环(event loop)”的架构,使得编写可扩展性高的服务器变得既容易又安全。提高服务器性能的技巧有多种多样。Node选择了一种既能提高性能,又能减低开发复杂度的架构。这是一个非常重要的特性。并发编程通常很复杂且布满地雷。Node绕过了这些,但仍提供很好的性能。

Node采用一系列“非阻塞”库来支持事件循环的方式。本质上就是为文件系统、数据库之类的资源提供接口。向文件系统发送一个请求时,无需等待硬盘(寻址并检索文件),硬盘准备好的时候非阻塞接口会通知Node。该模型以可扩展的方式简化了对慢资源的访问, 直观,易懂。尤其是对于熟悉onmouseover、onclick等DOM事件的用户,更有一种似曾相识的感觉。

虽然让Javascript运行于服务器端不是Node的独特之处,但却是其一强大功能。不得不承认,浏览器环境限制了我们选择编程语言的自由。任何服务器与日益复杂的浏览器客户端应用程序间共享代码的愿望只能通过Javascript来实现。虽然还存在其他一些支持Javascript在服务器端 运行的平台,但因为上述特性,Node发展迅猛,成为事实上的平台。

在Node启动的很短时间内,社区就已经贡献了大量的扩展库(模块)。其中很多是连接数据库或是其他软件的驱动,但还有很多是凭他们的实力制作出来的非常有用的软件。

最后,不得不提到的是Node社区。虽然Node项目还非常年轻,但很少看到对一个项目如此狂热的社区。不管是新手,还是专家,大家都围绕着项目,使用并贡献自己的能力,致力于打造一个探索、支持、分享、听取建议的乐土。

具备书写JavaScript的IDE,普通的记事本也可以进行开发。在几年的时间里,Node.JS逐渐发展成一个成熟的开发平台,吸引了许多开发者。有许多大型高流量网站都采用Node.JS进行开发,此外,开发人员还可以使用它来开发一些快速移动Web框架。

除了Web应用外,NodeJS也被应用在许多方面,本文盘点了NodeJS在其它方面所开发的十大令人神奇的项目,这些项目涉及到应用程序监控、媒体流、远程控制、桌面和移动应用等等。

效果图

鸿蒙端项目架构

shouye.ets

import  axios  from '@ohos/axios'
import router from '@ohos.router'
@Component
export struct app_shouye{
  @State zhanghao: object = router.getParams()
  // 设置搜索框的提示内容
  private changeValue:string = ''
  @State selectedItemId : number = 0
  @State one:string = ''
  // 设置商品的渲染列表Object
  @State items: Array<Object> = [];
   aboutToAppear() {
     axios({
      method: "get",
      url: 'http://localhost:3000/shangpins/find_all',
    }).then(res => {
      console.info('result:' + JSON.stringify(res.data.data));
      this.items = res.data.data
    }).catch(error => {
      console.error(error);
    })
     console.log(JSON.stringify(this.items))
  }


  build(){
    Column(){
      // 搜索栏
      Search({ value: this.changeValue, placeholder: '请输入搜索的商品',})
        .searchButton('搜索')
        .width(300)
        .height(40)
        .backgroundColor('#F5F5F5')
        .placeholderColor(Color.Grey)
        .placeholderFont({ size: 14, weight: 400 })
        .textFont({ size: 14, weight: 400 })
        .onSubmit((value: string) => {
          router.pushUrl({
            url: 'pages/sousuo',
            params: {
              sousuoValue: this.changeValue,
            }
          })
        })
        .onChange((value: string) => {
          this.changeValue = value
          console.log(this.changeValue)
        })
        .margin(20)

        // 显示商品列表
        List({ space: 20, initialIndex: 0 }){
          ForEach(this.items, (item) => {
            ListItem() {
              Row(){
                Image(item.img)
                  .alt($r('app.media.icon'))// 使用alt,在网络图片加载成功前使用占位图
                  .width(150)
                  .height(180)
                Column({space:10}){
                  Text(item.name)
                    .fontWeight(800)
                    .margin(20)
                  Text(item.detail)
                  Text('¥:'+item.price)
                    .fontColor('red')
                    .fontWeight(FontWeight.Bold)
                    .fontSize(20)
                }
                .width(180)
              }.alignItems(VerticalAlign.Top)
            }
            .onClick(() => {
              this.selectedItemId = item._id;
              // 获取点击物品的id
              this.one = item._id
              console.log(JSON.stringify(this.one))
              router.pushUrl({
                url: 'pages/detail',
                params: {
                  id: this.one,
                  zhanghao:this.zhanghao?.['zhanghao']
                }
              })
            })
          })
        }
        .height('90%')
        .listDirection(Axis.Vertical) // 排列方向
        .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线
        .edgeEffect(EdgeEffect.Spring) // 滑动到边缘无效果
    }
    .width('98%')
    .height('100%')
  }

}

fenlei.ets

import  axios  from '@ohos/axios'
import router from '@ohos.router'
@Component
export struct app_shouye{
  @State zhanghao: object = router.getParams()
  // 设置搜索框的提示内容
  private changeValue:string = ''
  @State selectedItemId : number = 0
  @State one:string = ''
  // 设置商品的渲染列表Object
  @State items: Array<Object> = [];
   aboutToAppear() {
     axios({
      method: "get",
      url: 'http://localhost:3000/shangpins/find_all',
    }).then(res => {
      console.info('result:' + JSON.stringify(res.data.data));
      this.items = res.data.data
    }).catch(error => {
      console.error(error);
    })
     console.log(JSON.stringify(this.items))
  }


  build(){
    Column(){
      // 搜索栏
      Search({ value: this.changeValue, placeholder: '请输入搜索的商品',})
        .searchButton('搜索')
        .width(300)
        .height(40)
        .backgroundColor('#F5F5F5')
        .placeholderColor(Color.Grey)
        .placeholderFont({ size: 14, weight: 400 })
        .textFont({ size: 14, weight: 400 })
        .onSubmit((value: string) => {
          router.pushUrl({
            url: 'pages/sousuo',
            params: {
              sousuoValue: this.changeValue,
            }
          })
        })
        .onChange((value: string) => {
          this.changeValue = value
          console.log(this.changeValue)
        })
        .margin(20)

        // 显示商品列表
        List({ space: 20, initialIndex: 0 }){
          ForEach(this.items, (item) => {
            ListItem() {
              Row(){
                Image(item.img)
                  .alt($r('app.media.icon'))// 使用alt,在网络图片加载成功前使用占位图
                  .width(150)
                  .height(180)
                Column({space:10}){
                  Text(item.name)
                    .fontWeight(800)
                    .margin(20)
                  Text(item.detail)
                  Text('¥:'+item.price)
                    .fontColor('red')
                    .fontWeight(FontWeight.Bold)
                    .fontSize(20)
                }
                .width(180)
              }.alignItems(VerticalAlign.Top)
            }
            .onClick(() => {
              this.selectedItemId = item._id;
              // 获取点击物品的id
              this.one = item._id
              console.log(JSON.stringify(this.one))
              router.pushUrl({
                url: 'pages/detail',
                params: {
                  id: this.one,
                  zhanghao:this.zhanghao?.['zhanghao']
                }
              })
            })
          })
        }
        .height('90%')
        .listDirection(Axis.Vertical) // 排列方向
        .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线
        .edgeEffect(EdgeEffect.Spring) // 滑动到边缘无效果
    }
    .width('98%')
    .height('100%')
  }

}

gouwuche.ets

import router from '@ohos.router'
import  axios  from '@ohos/axios'
import { Header } from '../components/Toubu'
@Component
export struct gouwuche{
  @State zhanghao: object = router.getParams()
  // 设置商品的渲染列表Object
  @State items: Array<Object> = [];

  aboutToAppear() {
    axios({
      method: "post",
      url: 'http://localhost:3000/gouwuche/find',
      data:{
        username:this.zhanghao?.['zhanghao']
      }
    }).then(res => {
      console.info('result1111:' + JSON.stringify(res.data.data));
      this.items = res.data.data
    }).catch(error => {
      console.error(error);
    })
    console.log(JSON.stringify(this.items))
  }

  build(){
    //   标题部分
    Column(){
      // 自定义组件之间传参
      // Header({message:true})
      Image($r('app.media.shuaxin'))
        .width(30)
        .margin(20)
        .onClick(() =>{
          axios({
            method: "post",
            url: 'http://localhost:3000/gouwuche/find',
            data:{
              username:this.zhanghao?.['zhanghao']
            }
          }).then(res => {
            console.info('result1111:' + JSON.stringify(res.data.data));
            this.items = res.data.data
          }).catch(error => {
            console.error(error);
          })
        })
      // Text(this.zhanghao?.['zhanghao'])
      List({ space: 20, initialIndex: 0 }){
        ForEach(this.items, (item) => {
          ListItem() {
            Row(){
              Image(item.img)
                .alt($r('app.media.icon'))// 使用alt,在网络图片加载成功前使用占位图
                .width(150)
                .height(180)
              Column({space:10}){
                Text(item.name)
                  .fontWeight(800)
                  .margin(20)
                Text(item.detail)
                Text('¥:'+item.price)
                  .fontColor('red')
                  .fontWeight(FontWeight.Bold)
                  .fontSize(20)
              }
              .width(180)
            }.alignItems(VerticalAlign.Top)
          }
        })
      }
      .height('85%')
      .listDirection(Axis.Vertical) // 排列方向
      .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线
      .edgeEffect(EdgeEffect.Spring) // 滑动到边缘无效果

      Row({space:30}){
        Button('清除购物车', { type: ButtonType.Normal, stateEffect: true })
          .borderRadius(8)
          .backgroundColor(0x317aff)
          .width(150)
          .onClick(() => {
            console.log('ButtonType.Normal')
          })

        Button('立即付款', { type: ButtonType.Normal, stateEffect: true })
          .borderRadius(8)
          .backgroundColor(0x317aff)
          .width(150)
          .onClick(() => {
            console.log('ButtonType.Normal')
          })
      }
    }
    .width('100%')
    .height('100%')
  }
}

Toubu.ets

import router from '@ohos.router'
@Component
export struct Header{
  @State message: Boolean = false
  build(){
  //   标题部分
    Row({space:5}){
      Image($r('app.media.fanhui'))
        .width(20)
        .onClick(() =>{
          router.back()
        })
      Blank()
      Image($r('app.media.shuaxin'))
        .width(30)
        .onClick(() =>{
          router.back()
        })
    }
    .width('98%')
    .height(30)
  }
}

wode.ets

import router from '@ohos.router'
@Component
export struct app_wode{
  @State zhanghao: object = router.getParams()

  build(){
    //   标题部分
    Column(){
      Row(){
        Row({space:10}){
          Image($r('app.media.icon'))
            .width(50)
            .height(50)
          Text('昵称:'+ this.zhanghao?.['zhanghao'])
            .margin({left:20})
            .fontColor('#fff')
        }
        .margin({top:30,left:50})
      }
      .width('100%')
      .height(180)
      .backgroundImage('./components/img/app_wo_bj.jpg')
      .backgroundImageSize(ImageSize.Cover)


        Row({space:50}){
          Image($r('app.media.icon'))
            .width(50)
            .height(50)
          Text('购物记录')
            .fontSize(18)
        }
        .width('100%')
        .backgroundColor("#fff")
        .margin({top:20,bottom:20})
        .padding({left:20,right:20,top:10,bottom:10})
        .onClick(()=>{
          router.pushUrl({
            url: 'pages/GouwuJilu',
          })
          console.log('123')
        })

        Row({space:50}){
          Image($r('app.media.icon'))
            .width(50)
            .height(50)
          Text('修改信息')
            .fontSize(18)
        }
        .width('100%')
        .backgroundColor("#fff")
        .margin({bottom:20})
        .padding({left:20,right:20,top:10,bottom:10})
        .onClick(()=>{
          router.pushUrl({
            url: 'pages/XiugaiXinxi',
          })
          console.log('123')
        })

        Row({space:50}){
          Image($r('app.media.icon'))
            .width(50)
            .height(50)
          Text('退出登录')
            .fontSize(18)
        }
        .width('100%')
        .backgroundColor("#fff")
        .margin({bottom:20})
        .padding({left:20,right:20,top:10,bottom:10})
        .onClick(()=>{
          router.replace({
            url: 'pages/Index',
          })
          console.log('123')
        })
    }
    .alignItems(HorizontalAlign.Start)
    .width('100%')
    .height('100%')
    .backgroundColor('#f3f3f3')
  }
}

detail.ets

import { Header } from '../components/Toubu'
import router from '@ohos.router'
import  axios  from '@ohos/axios'
@Entry
@Component
struct Detail {
  @State shangpin_detail: object = router.getParams()
  @State items:Array<Object> = []

  build() {
    Row() {
      Column() {
        Header()
        Text(this.shangpin_detail?.['zhanghao'])
        Text(this.items[0]?.['name'])

        Flex({ wrap: FlexWrap.NoWrap }) { // 子组件单行布局
          Text('').width('20%')
          List({ space: 20, initialIndex: 0 }) {
            ForEach(this.items, (item) => {
              ListItem() {
                Column() {
                  Image(item.img)
                    .alt($r('app.media.icon')) // 使用alt,在网络图片加载成功前使用占位图
                    .width(300)
                    .height(300)
                  Text(item.name)
                    .fontWeight(800)
                    .margin(20)
                  Text('¥:' + item.price)
                    .fontColor('red')
                    .fontWeight(FontWeight.Bold)
                    .fontSize(20)
                  Text(item.detail)
                }
              }
            })
          }
          .height('85%')
          .listDirection(Axis.Vertical) // 排列方向
          .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线
          .edgeEffect(EdgeEffect.Spring) // 滑动到边缘无效果
          Text('').width('20%')
        }
      //   加入购物车,立即购买
        Row({space:30}){
          Button('加入购物车', { type: ButtonType.Normal, stateEffect: true })
            .borderRadius(8)
            .backgroundColor(0x317aff)
            .width(150)
            .onClick(() => {
              axios({
                method: "post",
                url: 'http://localhost:3000/gouwuche/publish/',
                data: {
                  username: this.shangpin_detail?.['zhanghao'],
                  name:this.items[0]?.['name'],
                  detail:this.items[0]?.['detail'],
                  img:this.items[0]?.['img'],
                  select_classify:this.items[0]?.['select_classify'],
                  price:this.items[0]?.['price']
                }
              }).then(res => {
                console.log(JSON.stringify(res.data.data));
                this.items = res.data.data
              }).catch(error => {
                console.error(error);
              });
              console.log('ButtonType.Normal')
            })

          Button('立即购买', { type: ButtonType.Normal, stateEffect: true })
            .borderRadius(8)
            .backgroundColor(0x317aff)
            .width(150)
            .onClick(() => {
              console.log('ButtonType.Normal')
            })
        }
      }
      .width('100%')
    }.height('100%')
  }

  onPageShow(){
    axios({
      method: "post",
      url: 'http://localhost:3000/shangpins/find_detail/',
      data: {
        _id: this.shangpin_detail?.['id']
      }
    }).then(res => {
      console.log(JSON.stringify(res.data.data));
      this.items = res.data.data
    }).catch(error => {
      console.error(error);
    });
  }
}

GouwuJilu.ets

import { Header } from '../components/Toubu'
@Entry
@Component
struct GouwuJilu {
  @State message: string = '购物记录'

  build() {
    Column() {
      Header()
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
    }
    .width('100%')
    .height('100%')
  }
}

Index.ets

import  axios  from '@ohos/axios'
import router from '@ohos.router'
@Entry
@Component
struct Index {
  // 上传数据
  @State zhanghao: string = ''
  @State mima: string = ''
  @State zhanghao_find:string =''
  @State mima_find:string =''
  build() {
      Column() {
        Text('龙年千帆启鸿蒙')
          .margin({top:70})
          .fontWeight(FontWeight.Bold)
          .fontSize(30)
        Image($r('app.media.icon'))
          .width(150)
          .margin({top:50,bottom:20})
        // 账号登录
        TextInput({placeholder:'账号'})
          .margin(20)
          .height(50)
          .onChange(value =>{
            console.log(value)
            this.zhanghao_find = value
          })
          .backgroundColor('#36D2')
        TextInput({placeholder:'密码'})
          .margin({left:20,right:20,bottom:25})
          .height(50)
          .onChange(value =>{
            console.log(value)
            this.mima_find = value
          })
          .backgroundColor('#36D2')
        Button('登录')
          .width(200)
          .onClick(()=>{
            axios({
              method: "get",
              url: 'http://localhost:3000/users/find/'+this.zhanghao_find+ '/' + this.mima_find,
            }).then(res => {
              // console.info('result:' + JSON.stringify(res.data));
              console.info('result:' + JSON.stringify(res.data));
                // 获取data数组中的第一个元素
                const firstData = res.data.data[0];
                // 获取zhanghao字段的值
                const zhanghaoValue = firstData.zhanghao;
                console.log('zhanghaoValue:', zhanghaoValue);
              // 获取data数组中的第一个元素
              // 获取zhanghao字段的值
                router.pushUrl({
                  url: 'pages/NewApp_one',
                  params: {
                    zhanghao: zhanghaoValue,
                  }
                })
            }).catch(error => {
              console.error(error);
            })
          })
        Row(){
          Text('注册')
            .margin({right:5})
            .onClick( () =>{
              {
                router.pushUrl({
                  url: 'pages/zhuce',
                })
              }
            })
          Text('|')
          Text('忘记密码')
            .margin({left:5})
            .onClick( () =>{
              {
                router.pushUrl({
                  url: 'pages/WangjiMima',
                })
              }
            })
        }.margin(20)
      }
      .width('100%')
    .height('100%')
  }
}

NewApp_one.ets

import { app_shouye } from '../components/shouye/shouye'
import { app_wode } from '../components/wode'
import { app_fenlei } from '../components/fenlei'
import { gouwuche } from '../components/gouwuche'
import router from '@ohos.router'

@Entry
@Component
struct NewApp_one {
  // 获取上一个页面传过来的该登录的用户名
  @State zhanghao: object = router.getParams()

  build() {
      Column() {
        Tabs({ barPosition: BarPosition.End }) {
          TabContent() {
              app_shouye({ zhanghao: this.zhanghao?.['zhanghao'] })
          }
          .tabBar((new BottomTabBarStyle($r('sys.media.ohos_app_icon'),'首页')))
          TabContent() {
            app_fenlei()
          }
          .tabBar((new BottomTabBarStyle($r('sys.media.ohos_app_icon'),'分类')))

          TabContent() {
            gouwuche({ zhanghao: this.zhanghao?.['zhanghao'] })
          }
          .tabBar((new BottomTabBarStyle($r('sys.media.ohos_app_icon'),'购物车')))

          TabContent() {
            app_wode({ zhanghao: this.zhanghao?.['zhanghao'] })
          }
          .tabBar((new BottomTabBarStyle($r('sys.media.ohos_app_icon'),'我的')))
        }
      }
      .width('100%')
    .height('100%')
  }
  onPageShow(){
    console.log('这是父组件显示页面生命周期函数')
  }
}

sousuo.ets

import router from '@ohos.router'
import  axios  from '@ohos/axios'
import { Header } from '../components/Toubu'
@Entry
@Component
struct Sousuo {
  @State sousuoValue: object = router.getParams()
  @State items:Array<Object> = []
  @State selectedItemId : number = 0
  @State one:string = ''
  private changeValue:string = this.sousuoValue?.['sousuoValue']
  build() {
      Column() {
        Header()
        Search({ value: this.changeValue, placeholder: '请输入搜索的商品',})
          .searchButton('搜索')
          .width(300)
          .height(40)
          .backgroundColor('#F5F5F5')
          .placeholderColor(Color.Grey)
          .placeholderFont({ size: 14, weight: 400 })
          .textFont({ size: 14, weight: 400 })
          // 点击搜索
          .onSubmit((value: string) => {
            axios({
              method: "post",
              url: 'http://localhost:3000/shangpins/products/',
              data: {
                changeValue: this.changeValue
              }
            }).then(res => {
              console.log(JSON.stringify(res.data.data));
              this.items = res.data.data
            }).catch(error => {
              console.error(error);
            });
          })
          // 输入搜索
          .onChange((value: string) => {
            this.changeValue = value
            console.log(this.changeValue)
            axios({
              method: "post",
              url: 'http://localhost:3000/shangpins/products/',
              data: {
                changeValue: value
              }
            }).then(res => {
              console.log(JSON.stringify(res.data.data));
              this.items = res.data.data
            }).catch(error => {
              console.error(error);
            });
          })
          .margin(20)

        List({ space: 20, initialIndex: 0 }){
          ForEach(this.items, (item) => {
            ListItem() {
              Row(){
                Image(item.img)
                  .alt($r('app.media.icon'))// 使用alt,在网络图片加载成功前使用占位图
                  .width(150)
                  .height(180)
                Column({space:10}){
                  Text(item.name)
                    .fontWeight(800)
                    .margin(20)
                  Text(item.detail)
                  Text('¥:'+item.price)
                    .fontColor('red')
                    .fontWeight(FontWeight.Bold)
                    .fontSize(20)
                }
                .width(180)
              }.alignItems(VerticalAlign.Top)
            }
            .onClick(() => {
              this.selectedItemId = item._id;
              // 获取点击物品的id
              this.one = item._id
              console.log(JSON.stringify(this.one))
              router.pushUrl({
                url: 'pages/detail',
                params: {
                  id: this.one,
                }
              })
            })
          })
        }
        .height('90%')
        .listDirection(Axis.Vertical) // 排列方向
        .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线
        .edgeEffect(EdgeEffect.Spring) // 滑动到边缘无效果
      }
      .width('100%')
    .height('100%')
  }

  //上一个页面跳转过来之后查询的数据
  onPageShow() {
    console.log('wwww' + this.sousuoValue?.['sousuoValue']);
    axios({
      method: "post",
      url: 'http://localhost:3000/shangpins/products/',
      data: {
        changeValue: this.sousuoValue?.['sousuoValue'] // 修正获取参数的方式
      }
    }).then(res => {
      console.log(JSON.stringify(res.data.data));
      this.items = res.data.data
    }).catch(error => {
      console.error(error);
    });
  }

}

WangjiMima.ets

import { Header } from '../components/Toubu'
import  axios  from '@ohos/axios'
import router from '@ohos.router'
@Entry
@Component
struct Index {
  // 上传数据
  @State zhanghao: string = ''
  @State mima: string = ''

  build() {
    Column() {
      Header()
        .margin(20)
      TextInput({placeholder:'原账号'})
        .margin(20)
        .height(50)
        .onChange(value =>{
          console.log(value)
          this.zhanghao = value
        })
        .backgroundColor('#36D2')
      TextInput({placeholder:'新密码'})
        .margin({ left:20,right:20,bottom:20 })
        .height(50)
        .onChange(value =>{
          console.log(value)
          this.mima = value
        })
        .backgroundColor('#36D2')
      Button('修改密码')
        .width(200)
        .onClick(()=>{
          axios({
            method: "post",
            url: 'http://localhost:3000/users/upd',
            data:{
              zhanghao:this.zhanghao,
              newmima:this.mima
            },
          }).then(res => {
            console.info('result:' + JSON.stringify(res.data));
            {
              router.pushUrl({
                url: 'pages/NewApp_one',
              })
            }
          }).catch(error => {
            console.error(error);
          })
        })
    }
    .width('100%')
    .height('100%')
  }
}

XiugaiXinxi.ets

import { Header } from '../components/Toubu'
@Entry
@Component
struct XiugaiXinxi {
  @State message: string = '修改信息'

  build() {
      Column() {
        Header()

        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
    .height('100%')
  }
}

zhuce.ets

import { Header } from '../components/Toubu'
import  axios  from '@ohos/axios'
import router from '@ohos.router'
@Entry
@Component
struct Index {
  // 上传数据
  @State zhanghao: string = ''
  @State mima: string = ''
  @State zhanghao_find:string =''
  @State mima_find:string =''

  build() {
    Column() {
      Header()
        .margin(20)
      TextInput({placeholder:'注册账号'})
        .margin(20)
        .height(50)
        .onChange(value =>{
          console.log(value)
          this.zhanghao = value
        })
        .backgroundColor('#36D2')
      TextInput({placeholder:'注册密码'})
        .margin({ left:20,right:20,bottom:20 })
        .height(50)
        .onChange(value =>{
          console.log(value)
          this.mima = value
        })
        .backgroundColor('#36D2')
      Button('注册并登录')
        .width(200)
        .onClick(()=>{
          axios({
            method: "post",
            url: 'http://localhost:3000/users/publish',
            data:{
              zhanghao:this.zhanghao,
              mima:this.mima
            },
          }).then(res => {
            console.info('result:' + JSON.stringify(res.data));
              router.pushUrl({
                url: 'pages/NewApp_one',
              })
          }).catch(error => {
            console.error(error);
          })
        })
    }
    .width('100%')
    .height('100%')
  }
}

node.js后端架构

fenlei_api.js

// user_api.js
const express = require('express');
const router = express.Router();
const { fenlei } = require('../db');

router.use(express.urlencoded({ extended: true }));
router.use(express.json());

// 全部查询
router.get("/find_all", async (req, res) => { // Corrected function signature
    try {
      const results = await fenlei.find();

      if (results.length > 0) {
        // 如果找到匹配的记录,则返回所有匹配的记录
        res.json({ data: results, message: "登录成功!" });
      } else {
        res.status(404).json({ message: "未找到匹配的记录" });
      }
    } catch (error) {
      res.status(500).json({ message: "服务器内部错误" });
    }
  });

// 指定查询
router.get("/find/:name", async (req, res) => {
    try {
        const name = req.params.name;
        // 使用 find 查询所有匹配指定 name 的数据记录
        const results = await fenlei.find({ name });

        if (results.length > 0) {
            // 如果找到匹配的记录,则返回所有匹配的记录
            res.json({ data: results, message: "登录成功!" });
        } else {
            res.status(404).json({ message: "未找到匹配的记录" });
        }
    } catch (error) {
        res.status(500).json({ message: "服务器内部错误" });
    }
});

module.exports = router;

gouwuche_api.js

// user_api.js
const express = require('express');
const router = express.Router();
const { gouwuche } = require('../db');

router.use(express.urlencoded({ extended: true }));
router.use(express.json());

// 全部查询
router.post("/find", async (req, res) => {
    try {
      const { username } = req.body;
      // 使用 find 查询所有匹配指定 select_classify 的数据记录
      const results = await gouwuche.find({ username });
  
      if (results.length > 0) {
        // 如果找到匹配的记录,则返回所有匹配的记录
        res.json({ data: results, message: "登录成功!" });
      } else {
        res.status(404).json({ message: "未找到匹配的记录" });
      }
    } catch (error) {
      res.status(500).json({ message: "服务器内部错误" });
    }
  });
//   添加到购物车
router.post("/publish", async (req, res) => {
    try {
        const { username,name,detail,img,select_classifyprice,price } = req.body;
        await gouwuche.create({
            username,
            name,
            detail,
            img,
            select_classifyprice,
            price
        });
        res.send("success");
    } catch (error) {
        res.send(error, "error");
    }
});

module.exports = router;

shangpin_api.js

// user_api.js
const express = require('express');
const router = express.Router();
const { shangpin } = require('../db');

router.use(express.urlencoded({ extended: true }));
router.use(express.json());

// 全部查询
router.get("/find_all", async (req, res) => { // Corrected function signature
  try {
    const results = await shangpin.find();

    if (results.length > 0) {
      // 如果找到匹配的记录,则返回所有匹配的记录
      res.json({ data: results, message: "登录成功!" });
    } else {
      res.status(404).json({ message: "未找到匹配的记录" });
    }
  } catch (error) {
    res.status(500).json({ message: "服务器内部错误" });
  }
});

// 指定查询
router.post("/find", async (req, res) => {
  try {
    const { select_classify } = req.body;
    // 使用 find 查询所有匹配指定 select_classify 的数据记录
    const results = await shangpin.find({ select_classify });

    if (results.length > 0) {
      // 如果找到匹配的记录,则返回所有匹配的记录
      res.json({ data: results, message: "登录成功!" });
    } else {
      res.status(404).json({ message: "未找到匹配的记录" });
    }
  } catch (error) {
    res.status(500).json({ message: "服务器内部错误" });
  }
});

// 指定商品详情查询
router.post("/find_detail", async (req, res) => {
  try {
    const { _id } = req.body;
    // 使用 find 查询所有匹配指定 _id 的数据记录
    const results = await shangpin.find({ _id });

    if (results.length > 0) {
      // 如果找到匹配的记录,则返回所有匹配的记录
      res.json({ data: results, message: "登录成功!" });
    } else {
      res.status(404).json({ message: "未找到匹配的记录" });
    }
  } catch (error) {
    res.status(500).json({ message: "服务器内部错误" });
  }
});


//模糊查询
router.post('/products', async (req, res) => {
  try {
      const changeValue = req.body.changeValue; // 修正获取请求体中的参数方式

      // 使用正则表达式进行模糊查询
      const results = await shangpin.find({ name: { $regex: changeValue, $options: 'i' } });
      if (results.length > 0) {
          // 如果找到匹配的记录,则返回所有匹配的记录
          res.json({ data: results, message: "查询成功!" });
      } else {
          res.status(404).json({ message: "未找到匹配的记录" });
      }
  } catch (error) {
      console.error(error);
      res.status(500).json({ message: "服务器内部错误" });
  }
});



module.exports = router;

user_api.js

// user_api.js
const express = require('express');
const router = express.Router();
const { users } = require('../db');

router.use(express.urlencoded({ extended: true }));
router.use(express.json());

// 注册账号
router.post("/publish", async (req, res) => {
    try {
        const { zhanghao, mima } = req.body;
        await users.create({
            zhanghao, mima
        });
        res.send("success");
    } catch (error) {
        res.send(error, "error");
    }
});

// 注销账号
router.post("/del", async (req, res) => {
    console.log(req.body.zhanghao);
    try {
        const { zhanghao } = req.body;

        // 使用 deleteOne 删除指定 name 的数据
        const result = await users.deleteOne({ zhanghao });

        if (result.deletedCount === 1) {
            res.send("success");
        } else {
            res.send("未找到匹配的记录");
        }
    } catch (error) {
        res.send(error, "error");
    }
});

// 修改账号密码
router.post("/upd", async (req, res) => {
    try {
        const { zhanghao, newmima } = req.body;
        // 使用 updateOne 更新指定 name 的数据记录的 nianling 字段
        const result = await users.updateOne({ zhanghao }, { $set: { mima: newmima } });
        res.json({ message: "密码更新成功!", result });
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

// 账号登录
router.get("/find/:zhanghao/:mima", async (req, res) => {
    try {
        const zhanghao = req.params.zhanghao;
        const mima = req.params.mima;

        // 使用 find 查询所有匹配指定 name 的数据记录
        const results = await users.find({ zhanghao, mima });

        if (results.length > 0) {
            // 如果找到匹配的记录,则返回所有匹配的记录
            res.json({ data: results, message: "登录成功!" });
        } else {
            res.status(404).json({ message: "未找到匹配的记录" });
        }
    } catch (error) {
        res.status(500).json({ message: "服务器内部错误" });
    }
});

module.exports = router;

db.js

const mongoose = require('mongoose')

//连接mongodb数据库
mongoose.connect("mongodb://localhost:27017/node_one")
    .then(() => {
        console.log("数据库连接成功!")
    })
    .catch((err) => {
        console.log("数据库连接失败!", err)
    })

// 创建表用户表
const Users = new mongoose.Schema({
    zhanghao: {
        type: String,
    },
    mima: {
        type: String
    },
})
// 创建商品表
const Shangpin = new mongoose.Schema({
    name: {
        type: String,
    },
    detail: {
        type: String
    },
    img:{
        type: String
    },
    select_classify:{
        type: String
    },
    price:{
        type: String 
    }
})
//创建分类表
const Fenlei = new mongoose.Schema({
    name: {
        type: String,
    },
})
// 创建购物车表
const Gouwuche = new mongoose.Schema({
    username:{
        type: String,
    },
    name: {
        type: String,
    },
    detail: {
        type: String
    },
    img:{
        type: String
    },
    select_classify:{
        type: String
    },
    price:{
        type: String 
    }
})

const users = mongoose.model("Users", Users);
const shangpin = mongoose.model("Shangpin", Shangpin);
const fenlei = mongoose.model("Fenlei", Fenlei);
const gouwuche = mongoose.model("Gouwuche", Gouwuche);
module.exports = {
    users,
    shangpin,
    fenlei,
    gouwuche
}

index.js

// index.js
const express = require('express');
const app = express();
const userApi = require('./user_ctrl/user_api');
const shangpinApi = require('./shangpin_ctrl/shangpin_api');
const fenleiApi = require('./fenlei_ctrl/fenlei_api');
const gouwucheApi = require('./gouwuche_ctrl/gouwuche_api');

app.use('/users', userApi);

app.use('/shangpins', shangpinApi);

app.use('/gouwuche', gouwucheApi);

app.use('/fenleis', fenleiApi);

app.listen(3000, () => {
    console.log('server running');
});

后端安装指令

1. 下载node.js框架

npm install express --save

2. 下载nodemon解决node代码更新的痛点

npm install nodemon -g

3. node.js连接mongodb数据库

npm install mongoose --save

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1449006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

bpmn-js 事件总线处理

bpmn-js中使用EventBus作为事件的处理句柄&#xff0c;EventBus的使用和我们常规使用的事件总线没啥大的区别&#xff0c;其源码位于&#xff1a;/diagram-js/lib/core/EventBus.js &#xff08;bpmn-js使用diagram-js实现流程图的web端绘制呈现工具&#xff09;。 EventBus使用…

ubuntu22.04@laptop OpenCV Get Started: 008_image_filtering_using_convolution

ubuntu22.04laptop OpenCV Get Started: 008_image_filtering_using_convolution 1. 源由2. convolution应用Demo2.1 C应用Demo2.2 Python应用Demo 3. 重点分析3.1 identity矩阵3.2 all ones 5x5矩阵3.3 blur 5x5矩阵3.4 GaussianBlur 5x5矩阵3.5 medianBlur 5x5矩阵3.6 Sharpe…

「数据结构」MapSet

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;Java数据结构 &#x1f387;欢迎点赞收藏加关注哦&#xff01; Map&Set &#x1f349;概念&#x1f349;模型&#x1f349;Map&#x1f34c;TreeMap和HashMap的区别&#x1f34c;Map常用方…

儿童护眼台灯哪个值得推荐?推荐专业的儿童护眼台灯

现在的孩子很多都存在视力问题&#xff0c;而且年龄也越来越早&#xff0c;不少还为上学的孩子都早已戴上小眼镜。虽说这可能存在家族近视遗传的可能性&#xff0c;不过更多的还是后天导致的。长时间玩耍电子产品、缺乏运动、不良用眼习惯、不合适的光线等等都是导致孩子近视的…

【知识图谱--第四讲知识图谱的抽取与构建】

知识图谱的抽取与构建 实体识别与分类关系抽取与属性补全概念抽取事件识别与抽取 实体识别与分类 关系抽取与属性补全 概念抽取 事件识别与抽取

面试经典150题——最小覆盖子串(困难)

"The greatest glory in living lies not in never falling, but in rising every time we fall." - Nelson Mandela​ 1. 题目描述 2. 题目分析与解析 2.1 思路一——暴力求解 还是和之前讲的一样&#xff0c;看见题目没思路&#xff0c;先试试普通情况下人的解法…

ng : 无法加载文件 C:\Program Files\nodejs\node_global\ng.ps1, 因为在此系统上禁止运行脚本

ng : 无法加载文件 C:\Program Files\nodejs\node_global\ng.ps1&#xff0c;因为在此系统上禁止运行脚本 今天在VSCode中运行ng serve --port 8081运行基于Angular的项目时&#xff0c;报错了&#xff0c;错误如下图所示&#xff1a; 解决方法&#xff1a; 按照下图的5步即…

智能汽车行业产业研究报告:4D成像毫米波雷达—自动驾驶最佳辅助

今天分享的是智能汽车系列深度研究报告&#xff1a;《智能汽车行业产业研究报告&#xff1a;4D成像毫米波雷达—自动驾驶最佳辅助》。 &#xff08;报告出品方&#xff1a;开源证券&#xff09; 报告共计&#xff1a;43页 视觉感知最佳辅助——4D 成像毫米波雷达 感知是自动…

解决‘vue‘ 不是内部或外部命令,也不是可运行的程序(设置全局变量)

发现是没有执行&#xff1a; npm install -g vue/cli 但是发现还是不行 此时&#xff0c;我们安装了 Vue CLI&#xff0c;但是在运行 vue ui 命令时出现了问题。这通常是因为全局安装的 Vue CLI 的路径没有被正确地添加到系统的环境变量中。 可以尝试以下几种方法来解决这个问…

如何把华为手机上的数据转移到荣耀手机上?

方法/步骤 点击并进入华为手机&#xff08;旧手机&#xff09;的【手机克隆】应用&#xff0c;选择【这是旧设备】&#xff1b; 点击并进入荣耀手机&#xff08;新手机&#xff09;的【换机克隆】应用&#xff0c;选择【这是新设备】&#xff1b; 荣耀手机&#xff08;新…

《VulnStack》ATTCK-1

title: 《VulnStack》ATT&CK-1 date: 2024-01-29 14:53:49 updated: 2024-02-14 18:55:49 categories: WriteUp&#xff1a;Cyber-Range excerpt: 主机发现、端口扫描&#xff0c;服务探测&#xff0c;操作系统探测、nmap 漏洞库扫描、网站首页信息泄露、msf 渗透与信息收集…

源码推荐:hello-algo @ github

github https://github.com/krahets/hello-algo 本项目旨在创建一本开源、免费、对新手友好的数据结构与算法入门教程。全书采用动画图解&#xff0c;结构化地讲解数据结构与算法知识&#xff0c;内容清晰易懂&#xff0c;学习曲线平滑。算法源代码皆可一键运行&#xff0c;支…

【IDEA】新建Spring Initializr项目,选择java版本只有是17和21问题的解决方法

新建Spring Initializr项目时&#xff0c;选择java版本只有是17和21 2. 将https://start.spring.io修改为阿里云的服务器路径&#xff1a;https://start.aliyun.com 能够选择Java8、11等版本

【Linux笔记】动静态库的封装和加载

一、静态库的封装 我们在学习C语言阶段其实就已经知道一个可执行程序的形成过程分为预处理、编译、汇编、链接这四个阶段&#xff0c;而且也知道我们程序中使用的各种库其实是在链接的阶段加载的。 可我们那时候并不知道库是怎么被加载的&#xff0c;或者库是怎么形成的&…

项目访问量激增该如何应对

✨✨ 欢迎大家来到喔的嘛呀的博客✨✨ &#x1f388;&#x1f388;希望这篇博客对大家能有帮助&#x1f388;&#x1f388; 目录 引言 一. 优化数据库 1.1 索引优化 1.2 查询优化 1.3 数据库设计优化 1.4 事务优化 1.5 硬件优化 1.6 数据库配置优化 二. 增加服务器资源…

监督学习:从数据中挖掘模式的引导

目录 前言1 定义2 举例说明3 回归问题4 分类问题结论 前言 监督学习是机器学习领域中的一种重要方法&#xff0c;通过给模型提供带有标签的训练数据&#xff0c;使其能够学习输入与输出之间的关系。这种学习方式在各个领域都有广泛的应用&#xff0c;从垃圾邮件过滤到医学诊断…

ClickHouse--08--SQL DDL 操作

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 SQL DDL 操作1 创建库2 查看数据库3 删除库4 创建表5 查看表6 查看表的定义7 查看表的字段8 删除表9 修改表9.1 添加列9.2 删除列9.3 清空列9.4 给列修改注释9.5 修…

【AI视野·今日CV 计算机视觉论文速览 第298期】Fri, 26 Jan 2024

AI视野今日CS.CV 计算机视觉论文速览 Fri, 26 Jan 2024 Totally 71 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers Multimodal Pathway: Improve Transformers with Irrelevant Data from Other Modalities Authors Yiyuan Zhang, Xiaohan …

ARP请求的构造过程

ARP请求的构造过程&#xff1a; ARP请求的构造&#xff1a; 当设备A&#xff08;发起者&#xff09;想要与设备B&#xff08;目标&#xff09;通信&#xff0c;但它只知道设备B的IP地址&#xff08;例如&#xff0c;192.168.1.2&#xff09;&#xff0c;而不知道其MAC地址。设备…

OpenGL-ES 学习(4)---- OpenGL-ES 坐标体系

坐标体系 我们知道 OpenGL -ES 坐标系中每个顶点的 x&#xff0c;y&#xff0c;z 坐标都应该在 -1.0 到 1.0 之间&#xff0c;超出这个坐标范围的顶点都将不可见。 将一个物体&#xff08;图像&#xff09;渲染到屏幕上&#xff0c;通常经过将物体坐标转换为标准化设备坐标&am…