HarmonyOS开发:NodeJs脚本实现组件化动态切换

这篇具有很好参考价值的文章主要介绍了HarmonyOS开发:NodeJs脚本实现组件化动态切换。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

上篇文章,我们使用NodeJs脚本完成了HarmonyOS项目的组件化运行,但是由于脚本是基于4.0.0.400版本的DevEco Studio开发的,可能在配置文件的修改上有些许差距,那么遇到这种情况怎么办,一种是再写一套针对性的脚本文件或者在原有的脚本中增加配置版本参数,第二种就是自己搞一个,俗话说,授人以鱼不如授人以渔,索性这篇文章,就把上篇的脚本,是如何实现的,给大家阐述一下,这样,大家就可以自己操作了。

分析需求

需求的总体概括就非常的简单,让动态共享包的模块,在运行包和动态共享包之间可以动态的切换,省去人工配置的步骤,由上篇文章,我们已经得知,动态共享包和运行包之间的区别,主要来源于三处,分别是hvigorfile.ts文件、module.json5文件和缺少入口ability

HarmonyOS开发:NodeJs脚本实现组件化动态切换,HarmonyOS点石成金,鸿蒙脚本开发,鸿蒙组件化实现,鸿蒙模块化开发,HarmonyOS组件化开发

首先,肯定需要一个可以控制的开关,利用这个开关,判断是否要进行模块的动态切换,如果需要切换,那么就执行动态共享包切换运行包,否则就还原,大致流程如下:

HarmonyOS开发:NodeJs脚本实现组件化动态切换,HarmonyOS点石成金,鸿蒙脚本开发,鸿蒙组件化实现,鸿蒙模块化开发,HarmonyOS组件化开发

梳理模板

无论是由动态共享包切换为运行包,还是由运行包切换为动态共享包,我们改变的都是配置文件,也就是上述中存在差异的那三个文件,文件的内容,如何来回的更改呢,当然了可以设置统一的内容,只更改区别之处,但是为了直观,方便的查看和修改,无疑使用模版是比较简单的。

首先准备好两份文件,一份是动态共享包,一份是运行包,切换的时候,直接选择不同的模版即可。

动态共享包模版

动态共享包,需要提供两个模版即可,分别是hvigorfile.ts文件和module.json5文件。

1、hvigorfile.ts
import { hspTasks } from '@ohos/hvigor-ohos-plugin';
 
export default {
    system: hspTasks,  /* Built-in plugin of Hvigor. It cannot be modified. */
    plugins:[]         /* Custom plugin to extend the functionality of Hvigor. */
}
2、module.json5
{
  "module": {
    "name": "mine",
    "type": "shared",
    "description": "$string:shared_desc",
    "deviceTypes": [
      "phone",
      "tablet"
    ],
    "deliveryWithInstall": true,
    "pages": "$profile:main_pages"
  }
}

运行包模版

运行包除了两个配置文件不同,还必须有Ability,作为主入口,这是必不可少的。

1、hvigorfile.ts
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
 
export default {
    system: hapTasks,  /* Built-in plugin of Hvigor. It cannot be modified. */
    plugins:[]         /* Custom plugin to extend the functionality of Hvigor. */
}
2、module.json5
{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone",
      "tablet"
    ],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ts",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:icon",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:icon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ]
      }
    ]
  }
}

3、Ability

import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import hilog from '@ohos.hilog';
import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';
import window from '@ohos.window';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy() {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage) {
    // Main window is created, set main page for this ability
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('pages/Index', (err, data) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }
      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
    });
  }

  onWindowStageDestroy() {
    // Main window is destroyed, release UI related resources
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground() {
    // Ability has brought to foreground
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground() {
    // Ability has back to background
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
  }
}

技术实现

1、创建配置文件

第一步,书写开关,也就是配置文件,当然了配置文件具体如何定义,看自己安排,无论何种形式展现,该有的参数一定要有,比如是否要开启组件化以及开启组件化的模块名字,至于其他的参数,可以根据需要进行添加,目前我定义的配置文件如下,具体的解释,都有注释,上篇文章中也做了一系列的解读。

#组件化配置文件
#是否开启组件化
startModule=false
#开启的组件名字,开启后,当前的组件可以独立运行
startModuleName=
#上述组件开启后,其他非必要组件是否改为动态包模式,默认不改变
startOtherShared=false
#过滤组件名字,永远不会独立运行,以应为逗号作为分割
filterModuleName=
#当前脚本默认加载的页面,默认不填是Index.ets
loadPage=

配置文件,这里我自定义了后缀,具体是什么文件都所谓,主要的是文件里的内容。

HarmonyOS开发:NodeJs脚本实现组件化动态切换,HarmonyOS点石成金,鸿蒙脚本开发,鸿蒙组件化实现,鸿蒙模块化开发,HarmonyOS组件化开发

有了配置文件之后,我们就可以根据配置文件来一层一层的实现相关逻辑。

2、初始化项目

nodeJs环境,在安装DevEco Studio的时候就已经配置完成,检验是否安装,可以在命令行中执行如下命令:

node -v

如果正常能显示版本号,则安装成功。

HarmonyOS开发:NodeJs脚本实现组件化动态切换,HarmonyOS点石成金,鸿蒙脚本开发,鸿蒙组件化实现,鸿蒙模块化开发,HarmonyOS组件化开发

在需要创建脚本的目录,执行初始化操作:

npm init

具体的步骤解释:

package name 包名,也就是工程名,默认是括号中的内容 
version:版本号,默认是括号中的内容 
description:描述信息 
entry point:入口文件名,默认是括号中的内容 
test command:测试命令 
git repository:git仓库地址 
keywords: 密码 
author: 作者名字 
license: (ISC)许可证

一路按照相关提示,执行下一步即可,其实就是生产了一个json配置文件,大家也可以自己手动创建。

HarmonyOS开发:NodeJs脚本实现组件化动态切换,HarmonyOS点石成金,鸿蒙脚本开发,鸿蒙组件化实现,鸿蒙模块化开发,HarmonyOS组件化开发

执行完毕之后,就会在当前目录,创建一个json文件。

HarmonyOS开发:NodeJs脚本实现组件化动态切换,HarmonyOS点石成金,鸿蒙脚本开发,鸿蒙组件化实现,鸿蒙模块化开发,HarmonyOS组件化开发

json文件内容:

HarmonyOS开发:NodeJs脚本实现组件化动态切换,HarmonyOS点石成金,鸿蒙脚本开发,鸿蒙组件化实现,鸿蒙模块化开发,HarmonyOS组件化开发

3、创建执行js文件

HarmonyOS开发:NodeJs脚本实现组件化动态切换,HarmonyOS点石成金,鸿蒙脚本开发,鸿蒙组件化实现,鸿蒙模块化开发,HarmonyOS组件化开发

这个js文件就是我们所有逻辑的书写地方,为了能够让js文件可以正常运行,我们需要在package.json文件里进行配置,如下:

HarmonyOS开发:NodeJs脚本实现组件化动态切换,HarmonyOS点石成金,鸿蒙脚本开发,鸿蒙组件化实现,鸿蒙模块化开发,HarmonyOS组件化开发

以后执行脚本的时候,直接在命令行中,执行npm run module即可,我们先简单的输出一个“Hello world”,首先在module.js里进行打印,如下所示:

HarmonyOS开发:NodeJs脚本实现组件化动态切换,HarmonyOS点石成金,鸿蒙脚本开发,鸿蒙组件化实现,鸿蒙模块化开发,HarmonyOS组件化开发

执行命令结果:

HarmonyOS开发:NodeJs脚本实现组件化动态切换,HarmonyOS点石成金,鸿蒙脚本开发,鸿蒙组件化实现,鸿蒙模块化开发,HarmonyOS组件化开发

3、完成最后的逻辑

由于需要对文件进行操作,这里使用到了Node.js中的核心模块fs,一句话介绍,fs模块提供了丰富的函数和方法,可以进行文件的读取、写入、复制、删除等操作,同时也支持目录的创建、遍历和修改等操作,如果你想要更详细的了解,可以查看我的往期文章,或者在网上搜索也行,有大量的资料存在。

1)、读取配置文件

所有的功能实现都是基于配置文件,所以配置文件里的参数至关重要,也是程序的第一步,读取配置文件,逐项拿到设置的相关参数,并记录下来。

//读取文件信息
    let path = require('path');
    let dirName = path.join(__dirname); //获取跟目录
    try {
        //读取配置文件,查找对应的配置信息
        let data = fs.readFileSync(dirName + "/module.harmony", 'utf-8');
        var startModule;
        var startModuleName;
        var filterModuleName;
        var startOtherShared;
        var loadContentPage;
        data.split(/\r?\n/).forEach((line, position) => {
            if (position === 2) {
                let open = line.split("=")[1];
                startModule = open.toString();
            }
            if (position === 4) {
                let moduleName = line.split("=")[1];
                startModuleName = moduleName.toString();
            }
            if (position === 6) {
                let otherName = line.split("=")[1];
                startOtherShared = otherName.toString();
            }
            if (position === 8) {
                let filterName = line.split("=")[1];
                filterModuleName = filterName.toString();
            }
            if (position === 10) {
                //load的页面信息
                let loadPage = line.split("=")[1];
                loadContentPage = loadPage.toString();
            }
        });
        //开启组件化之后,单独的模块可以独立运行
        //不开启组件化,那么entry可以独立运行,其他均不可,需要一一更改配置文件
        traverseFolder(dirName, startModule.indexOf("true") !== -1,
            startModuleName, startOtherShared, filterModuleName, loadContentPage);

    } catch (e) {
        console.log("发生了错误,请检查配置文件是否存在,或反馈至AbnerMing");
    }
2)、动态修改配置文件信息

根据配置文件信息,进行组件化运行,也就是动态共享包切换为运行包,如何切换,拿到差异性文件,然后读取模版信息,进行写入即可。

需要注意的是,动态共享包,切换为运行包,需要动态创建ability,除此之外,关于组件的名字,ability名字,尽量和组件保持一致。

运行包切换为动态共享包,也是读取配置文件,然后进行写入即可。

function traverseFolder(folderPath, isModule, startModuleName,
                        startOtherShared, filterModuleName, loadContentPage) {
    const items = fs.readdirSync(folderPath);

    items.forEach(item => {
        let dir = folderPath + "/" + item;
        const stats = fs.statSync(dir);
        if (stats.isDirectory()) {
            let hvigorFilePath = dir + "/hvigorfile.ts";
            fs.readFile(hvigorFilePath, "utf8", (err, dataStr) => {
                if (err) {
                    return;
                }
                if (isModule) {
                    //开启组件化
                    //把当前的组件改为运行状态
                    if (item == startModuleName) {

                        let moduleName = item.substring(0, 1).toUpperCase()
                            + item.substring(1, item.length)

                        //修改为可运行状态
                        let entryHvigorFile = getEntryHvigorFile();
                        //读取string.json文件,增加label
                        let jsonName = dir + "/src/main/resources/base/element/string.json";
                        fs.readFile(jsonName, "utf8", (err, dataStr) => {
                            if (err) {
                                return;
                            }
                            let obj = JSON.parse(dataStr);
                            let array = obj["string"];
                            let label = { "name": "shared_label", "value": item };
                            let isSharedLabel = false;

                            for (var i = 0; i < array.length; i++) {
                                let name = array[i]["name"];
                                if (name == "shared_label") {
                                    isSharedLabel = true;
                                    break;
                                }
                            }

                            if (!isSharedLabel) {
                                array.push(label);
                            }
                            writeContent(jsonName, JSON.stringify(obj));
                            //进一步更改json5文件
                            let json5 = dir + "/src/main/module.json5";
                            writeContent(json5, getEntryModuleJson5(item, moduleName));
                        });

                        if (loadContentPage == null || loadContentPage == "") {
                            //为空的时候才去创建
                            //创建Index.ets文件
                            let indexPath = dir + "/src/main/ets/pages";
                            const indexItem = fs.readdirSync(indexPath);
                            let isHaveIndex = false;
                            indexItem.forEach(item => {
                                if (item == "Index.ets") {
                                    //证明存在
                                    isHaveIndex = true;
                                }
                            });

                            if (!isHaveIndex) {
                                //不存在,就要去创建
                                writeContent(indexPath + "/Index.ets", getIndex());
                            }
                        }
                        //创建Ability文件
                        let etsPath = dir + "/src/main/ets/" + item + "ability/" + moduleName + "Ability.ts";
                        fs.mkdir(dir + "/src/main/ets/" + item + "ability", function (err) {
                            if (err) {
                                writeContent(etsPath, getAbility(moduleName, loadContentPage));
                                return;
                            }
                            //写入文件
                            writeContent(etsPath, getAbility(moduleName, loadContentPage));
                        });

                    } else {
                        //非当前的组件,需要改为动态包模式吗,根据配置文件来改变,有两种是永远不能改变的
                        if (item != "entry" && filterModuleName.indexOf(item) == -1 && startOtherShared) {
                            //把其他的模块都改成动态包,不能运行
                            let moduleJson5 = getSharedModuleJson5(item);
                            let hvigorFile = getSharedHvigorFile();
                            writeContent(hvigorFilePath, hvigorFile);
                            writeContent(dir + "/src/main/module.json5", moduleJson5);
                        }
                    }
                } else {
                    //主模块和需要过滤的模块不进行动态包设置
                    if (item != "entry" && filterModuleName.indexOf(item) == -1) {
                        //把其他的模块都改成动态包,不能运行
                        let moduleJson5 = getSharedModuleJson5(item);
                        let hvigorFile = getSharedHvigorFile();
                        writeContent(hvigorFilePath, hvigorFile);
                        writeContent(dir + "/src/main/module.json5", moduleJson5);
                    }
                }
            });
        }
    });
}

相关总结

由于逻辑比较简单,完整的逻辑,大家可以查看源码:

https://gitee.com/abnercode/harmony-os-module

由于开发环境的不同,配置文件信息也有所不同,无非就是更改的模版不一样,只需要在脚本中,换成你的环境下的配置文件内容即可。文章来源地址https://www.toymoban.com/news/detail-731919.html

到了这里,关于HarmonyOS开发:NodeJs脚本实现组件化动态切换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 组件化开发之如何封装组件-react

    组件是构建用户界面的基本单元,它是一个独立的、可重用的、可组合的代码单元,用于表示UI的一部分。 人话:当谈论组件时,就像在搭积木一样,每个组件都是一个 独立的、可以重复使用 的代码块,用来构建网页或应用的各个部分。比如界面的布局,像按钮、文本输入

    2024年02月11日
    浏览(63)
  • Vue组件化开发--公共组件的封装

    目录 为什么要封装组件 应用场景 vue自己封装组件(局部、全局)  Vue组件的三要素 ①全局组件 1)方式:  2)示例: ②局部组件 1)方式: 2)示例: 命名规范:(注意) 脚手架vue-cli中的组件 父传子(props) 通过 $on 传递父组件方法 $parent获取父组件然后使用父组件中的

    2024年02月05日
    浏览(59)
  • 小程序组件化开发

        随着小程序的普及,越来越多的开发者开始使用小程序进行开发,而小程序的组件化开发已经成为了一种标配的开发模式。本文将深入介绍小程序组件化开发的相关知识,包括组件的定义、生命周期、通信和使用等方面,帮助大家更好地理解和使用小程序的组件化开发

    2023年04月20日
    浏览(49)
  • 组件化开发复习

    createApp 函数传入了一个对象 App ,这个对象其实本质上就是一个组件,也是我们应用程序的根组件 可以写为:  我们先来学习一下全局组件的注册:  全局组件需要使用我们全局创建的 app 来注册组件;  通过 component 方法传入组件名称、组件对象即可注册一个全局组件了;

    2024年02月15日
    浏览(66)
  • Vue 组件化开发

    提示:这里可以添加本文要记录的大概内容: Vue.js 是一种现代化的前端框架,可以用于构建可复用的组件化应用程序。Vue.js 提供了一种基于组件的架构,使得开发人员可以将应用程序分解为多个可重用的组件。 Vue.js 组件是一个可复用的代码模块,可以在 Vue.js 应用程序中使

    2024年02月15日
    浏览(49)
  • react组件化开发详解

    React是一个流行的JavaScript库,用于构建用户界面,并且以组件化的方式进行开发。下面将详解React组件化开发的概念和步骤: 组件化思维: 组件化开发是将复杂的用户界面划分为独立、可重用的小部件(组件)。每个组件负责处理自己的逻辑和渲染,可以嵌套和组合其他组件

    2024年02月12日
    浏览(55)
  • 小程序的组件化开发

    目录: 1 小程序组件化思想 2 自定义组件的过程 3 组件样式实现细节 4 组件使用过程通信 5 组件插槽定义使用 6 Component构造器 在小程序里面需要创建组件的话需要在最外层建component包,然后在使用新建component来创建类似page的4个文件: 组件和页面的区别就是,组件文件会有额

    2024年02月10日
    浏览(40)
  • Vue开发实战(03)-组件化开发

    对组件功能的封装,可以像搭积木一样开发网页。 Vue官方的示例图对组件化开发的形象展示。左边是一个网页,可以按照功能模块抽象成很多组件,这些组件就像积木一样拼接成网页。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aS7Zk8tp-16862

    2024年02月08日
    浏览(99)
  • 【Vue】Vite 组件化开发

    1. 什么是组件化开发 组件化开发指的是:根据封装的思想,把页面上可重用的部分封装为组件,从而方便项目的开发和维护。 例如:https://gitee.com/vdpadmin/variant-form 所展示的效果,就契合了组件化开发的思想。用户可以通过拖拽组件的方式,快速生成一个页面的布局结构。

    2024年02月10日
    浏览(48)
  • 【前端知识】React 基础巩固(十七)——组件化开发(一)

    什么是组件化开发? 分而治之的思想 将一个页面拆分成一个个小的功能块 将应用抽象成一颗组件树 React的组件相对于Vue更加的灵活和多样 按照不同的方式可以分为很多类组件 根据 组件的定义方式 ,分为: 函数组件 、 类组件 根据 组件内部是否有状态需要维护 ,分为:

    2024年02月12日
    浏览(69)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包