当前位置:   article > 正文

使用Jetpack Compose跨平台开发Web程序,快来试试?

jetpack compose for web

a8a58b9bd6dd49be8b5fea8bc5649882.jpeg

/   今日科技快讯   /

近日,数据公司IDC发布了2022年中国智能手机出货量以及相关排名。数据显示,2022年全年中国智能手机市场出货量约2.86亿台,同比下降13.2%,创有史以来最大降幅。就排名来看,vivo、荣耀分别排名第一、第二;OPPO与苹果并列第三,小米第五。

/   作者简介   /

本篇文章转自黄林晴的博客,文章主要分享了如何使用Compose-jb开发Web应用,相信会对大家有所帮助!

原文地址:

https://juejin.cn/post/7187306464875118651

/   前言   /

在之前的Compose跨平台的文章中,我们已经了解了Compose-jb以及如何使用Compose-jb开发简单的桌面端应用,第二弹,我们就来了解下如何使用Compose-jb开发Web应用。相信看完这一弹之后你会对Compose-jb有新的了解。

环境要求

环境要求主要有两点:

  • JDK 11或更高版本

  • IntelliJ IDEA 2020.3 或更高版本(也可以使用AS,这里为了使用IDEA提供的项目模板)

/   开发流程   /

创建项目

同样的,我们打开IDEA创建Compose Multiplatform项目,选择Single plaform,不过这里我们选择Platform为Web平台,如下图所示。

6e809fe5c72f679bbffa6a18d1b479ab.png

创建好项目后,来看项目目录结构,如下图所示。

6d9a2deff7e240a8562444313fff11c5.png

可以看到同样的在配置文件中指定了平台配置,这一点是比较重要的,便于以后我们在原有项目基础上添加配置。并且以后我们会发现,这个配置也不一定在根目录中的build文件中,所以我们需要知道配置的含义,这一点目前规划在后续的弹中会单独分享。

项目结构

在jsMain文件夹下Main文件通过renderComposable的rootElementId属性与index.html中的div标签绑定,从而将页面在web中显示。index.html代码截图如下所示。

e9ff5a2b387f287a3eb2a905e413e065.png

Main.kt代码截图如下所示。

4389a7a22e14f933222ade4241ed1649.png

当我看到这段代码之后,我心里是慌的,Div?style?attrs?这都是什么玩意啊,学了Compose的我都不知道,这也能叫跨平台?

cde63dcdc64f47c52a09f287056910cc.png

这是Compose for Web专门提供的一套DOM API,Div组件也是为Web实现的对应Composeable组件,通过attrs方法设置标签属性。所以这些代码,都是无法直接在Android或Desktop平台上复用的。所以,从这一点来讲使用Compose实现跨平台,目前存在严重的割裂问题,和Flutter相比还是有一定的差距。

运行程序(./gradlew jsBrowserRun),页面如下图所示。

4430ad3895506dd6b9ef47e91e939aa0.png

这是项目默认实现的一个加减计数器的功能。接下来我们来添加自己的组件。

添加输入框

和开发Desktop一样,我们先来添加一个输入框,在Compose for Web中输入框采用Input组件,代码如下所示:

  1. renderComposable(rootElementId = "root") {
  2.     Div {
  3.         P {
  4.             Input(type = InputType.Text) {}
  5.         }
  6.         P {
  7.             Input(type = InputType.Password)
  8.         }
  9.         P {
  10.             Button(attrs = {
  11.                 onClick {
  12.                 }
  13.             }) {
  14.                 Text("Login")
  15.             }
  16.         }
  17.     }
  18. }

通过type属性指定输入框的类别分别为文字和密码,运行程序,结果如下图所示。

60496ebd50d38ae4b2898c229d67613d.png

接着我们通过添加Text标签为输入框添加属性说明,修改部分的代码如下所示:

  1. P {
  2.     Text("用户名")
  3.     Input(type = InputType.Text) {}
  4. }
  5. P {
  6.     Text("密码")
  7.     Input(type = InputType.Password)
  8. }

再次运行程序,结果如下图所示。

3d7cd61bb68046040c52e3e641295e4e.png

嗯,挺丑的。上述代码我们在最外层使用Div包裹是为了便于为这块区域设置一些属性,比如我们设置背景色为蓝色,代码如下所示。

  1. Div({style {
  2.    backgroundColor(Color.blue)
  3. }}){
  4.    ...
  5. }

运行程序,结果如下所示。

d62eec0781c7a74016bbc752e887cf14.png

好吧,更丑了... Compose for Web 允许开发者基于 DSL 定义 Style 样式,但是到目前为止我的感觉是写的很累,感觉如果不会Web就无法写好Compose for Web,这叫哪门子的跨平台?

添加超链接

超链接直接使用A标签即可,比如这里我们添加一个用户隐私协议,代码如下所示。

  1. P {
  2.     A("https://www.baidu.com/") { 
  3.         Text("用户协议")
  4.     }
  5. }

运行程序,结果如下图所示。

8b86b7fe36ff4d3ced68fd7493211cbe.png

如果想用Compose写好Web,我觉得最主要的是Style DSL,但是在这里我们没办法一一展示。需要我们在项目中去实战。接下来,我们来实现与Desktop一样的查询数据功能。

实现查询数据功能

本来打算仍然借用「wanandroid」中「每日一问」接口的,但是这个接口存在跨域问题,导致无法请求,所以我们这里将接口返回的json数据,定义为Api文件中的data变量,Ktor的使用方式是一样的,所以并不影响实际结果。

定义HttpUtil类并实现getData方法,代码如下所示。

  1. class HttpUtil {
  2.     /**
  3.      * 获取数据
  4.      */
  5.     suspend fun getData(): DemoReqData {
  6.         val rockets = Json.decodeFromString<DemoReqData>(string = Api.data)
  7.         return rockets
  8.     }
  9. }

在Desktop中我们可以直接在Main 文件中直接调用取数据的方法,但是这里不行,因为renderComposable下无法启动协程。所以这里我们定义一个DataSource类继承自CoroutineScope,同样定义一个loadData方法,代码如下所示。

  1. class DataSource : CoroutineScope {
  2.     private var job = Job()
  3.     override val coroutineContext: CoroutineContext
  4.         get() = job
  5.     private val _stateFlow = MutableStateFlow(DemoReqData())
  6.     var stateFlow = _stateFlow.asStateFlow()
  7.     fun loadData() {
  8.         launch {
  9.             _stateFlow.value = HttpUtil().getData()
  10.         }
  11.     }
  12. }

这样我们可以在loadData方法中启动协程并调用HttpUtil中的getData方法,然后赋值给stateFlow,这一点得益于Flow 是 kotlinx 包下的组件,与平台无关。

最后,我们在Main中定义一个按钮,点击“请求数据”,然后将数据显示出来,代码如下所示。

  1. renderComposable(rootElementId = "root") {
  2.     val dataSource = DataSource()
  3.     val data = dataSource.stateFlow.collectAsState()
  4.     Button(attrs = {
  5.         onClick {
  6.             dataSource.loadData()
  7.         }
  8.     }) {
  9.         Text("请求数据")
  10.     }
  11.     Div {
  12.         repeat(data.value.data?.datas?.size ?: 0) {
  13.             Div {
  14.                 P {
  15.                     Text("作者:" + data.value.data?.datas?.get(it)?.author)
  16.                 }
  17.                 P {
  18.                     Text("标题:" + data.value.data?.datas?.get(it)?.title)
  19.                 }
  20.                 P({
  21.                     style {
  22.                         height(1.px)
  23.                         backgroundColor(Color.red)
  24.                     }
  25.                 }) {}
  26.             }
  27.         }
  28.     }
  29. }

这里将作者信息与标题显示出来,为了效果明显添加了一个红色的横线,运行程序,点击“请求数据”,结果如下图所示。

277f615081d4422b90684a515bb9f07a.png

这样我们就使用Compose实现了一个Web端简单的查询数据功能。

/   写在最后   /

Compose For Web中提供了更贴近HTML风格的Composable API,所以UI代码无法与Android或Desktop的UI代码直接复用。但是逻辑层的代码都是可以共用的,目前Google也在推进解决这样的“割裂”问题,从目前来看,Compose跨平台还有一定的路要走,我们将在后续的第N弹中持续探索...

推荐阅读:

我的新书,《第一行代码 第3版》已出版!

Kotlin Flow响应式编程,StateFlow和SharedFlow

由浅入深,详解 ViewModel 的那些事

欢迎关注我的公众号

学习技术或投稿

6f6aaec688a48a904b13ce451d84bf0b.png

c50656a83d24e45b392baf0f930e1db2.jpeg

长按上图,识别图中二维码即可关注

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/253942
推荐阅读
相关标签
  

闽ICP备14008679号