京东Nutui4.X小程序集成Nutui-bingo组件

  • Post author:
  • Post category:小程序


Bingo介绍

NutBingo组件是由京东平台开发的抽奖组件库,基于 NutUI 的抽奖组件库,助力营销活动和小游戏场景。

官方参考文档


NutUI-Bingo – 移动端Vue抽奖组件库

github库


GitHub – jdf2e/nutui-bingo: Bingo – 基于 NutUI 的抽奖组件

特性

  • 12 个抽奖组件(大转盘、跑马灯、九宫格、刮刮卡、神秘大礼盒、摇奖机、砸金蛋、红包雨、摇一摇、娃娃机、摇骰子、你藏我猜)
  • 基于京东APP 10.0 视觉规范
  • 详尽的文档和示例
  • 支持 TypeScript
  • 灵活的自定义设置

注:目前官方的组件库只支持h5,目前官方描述小程序还在适配中

集成到微信小程序

本项目同样是采用京东的nutui-taro 4.x框架集成vue3开发微信小程序;

NutUI-Vue 组件库,基于 Taro,使用 Vue 技术栈开发小程序应用,开箱即用,帮助研发快速开发用户界面,提升开发效率,改善开发体验。

从现有的文档内未找到有关小程序的集成方案,本方案就集成微信小程序中使用进行了尝试,发现基础功能通过修改后,基本上能够使抽奖类组件集成在nut-taro框架中运行;

nutui-taro 4.x官方参考文档


NutUI – 移动端 Vue3 小程序组件库


安装nutbingo

本文以npm安装为示例,官方也推存:“我们推荐使用 NPM 或 YARN 方式安装,不推荐在页面中直接引入的用法”


npm下安装

# Vue3
npm i @nutui/nutui-bingo

安装提示完毕后,在package.json文件中能看到组件版件信息,即表示安装到项目中

"@nutui/nutui-bingo": "^1.0.7",


npm使用示例

import { createApp } from "vue";
import App from "./App.vue";
import NutBig from "@nutui/nutui-bingo";
import "@nutui/nutui-bingo/dist/style.css";
createApp(App).use(NutBig).mount("#app");

注:这种方式将导入所有组件


推荐按需使用按需加载

import { createApp } from "vue";
import App from "./App.vue";
import { Turntable } from "@nutui/nutui-bingo";
import "@nutui/nutui-bingo/dist/style.css";
createApp(App).use(Turntable).mount("#app");


小程序项目引入

在app.ts中加入抽奖营销组件,如:Marquee(跑马灯)

import { createApp } from 'vue'
import './app.scss'

// npm i --sever @nutui/nutui-bingo
import { Marquee  } from "@nutui/nutui-bingo"
import "@nutui/nutui-bingo/dist/style.css";

const app = createApp({});
app.use(Marquee );
export default app

创建小程序页面

从命令行进入到系统盘符,再进入到项目保存的目录中,比如:gwApp,执行taro命令创建draw小程序页面

$ taro create --name draw
👽 Taro v3.6.1


✔ 创建文件: D:\Workspaces\taro\gwApp\src\pages\draw\index.vue
✔ 创建文件: D:\Workspaces\taro\gwApp\src\pages\draw\index.config.ts

✔ 创建页面 draw 成功!

在VSCode中打开页面,删除无关的自动创建的代码,复制Nut-Bigo官方的Marquee跑马灯组件示例代码;

<template>
  <nutbig-marquee
    :prize-list="prizeList"
    :prize-index="prizeIndex"
    :speed="100"
    :circle="40"
    @start-turns="startTurns"
    @end-turns="endTurns"
  >
  </nutbig-marquee>
</template>

<script>
import { ref, reactive, toRefs } from 'vue';
import { Dongdong } from '@nutui/icons-vue-taro';
import NutBig from '@nutui/nutui-bingo';
export default {
  name: 'draw',
  components: {
    Dongdong,
    NutBig
},
  setup() {
    // 转盘上要展示的奖品数据
    const prizeList = ref([
        {
          id: "xiaomi",
          prizeName: "小米手机",
          prizeImg:
            "https://img14.360buyimg.com/imagetools/jfs/t1/104165/34/15186/96522/5e6f1435E46bc0cb0/d4e878a15bfd9362.png",
        },
        {
          id: "blue",
          prizeColor: "rgb(251, 219, 216)",
          prizeName: "蓝牙耳机",
          prizeImg:
            "https://img13.360buyimg.com/imagetools/jfs/t1/91864/11/15108/139003/5e6f146dE1c7b511d/1ddc5aa6e502060a.jpg",
        },
        {
          id: "thanks",
          prizeName: "谢谢参与",
          prizeImg:
            "https://img11.360buyimg.com/imagetools/jfs/t1/96116/38/15085/5181/5e6f15d1E48e31d30/71353b61dff705d4.png",
        },
        {
          id: "apple",
          prizeName: "apple watch",
          prizeImg:
            "https://img11.360buyimg.com/imagetools/jfs/t1/105385/19/15140/111093/5e6f1506E48bd0dfb/829a98a8cdb4c27f.png",
        },
        {
          id: "fruit",
          prizeColor: "rgba(246, 142, 46, 0.5)",
          prizeName: "迪士尼苹果",
          prizeImg:
            "https://img11.360buyimg.com/imagetools/jfs/t1/108308/11/8890/237603/5e6f157eE489cccf1/26e0437cfd93b9c8.png",
        },
        {
          id: "thanks",
          prizeName: "谢谢参与",
          prizeImg:
            "https://img11.360buyimg.com/imagetools/jfs/t1/96116/38/15085/5181/5e6f15d1E48e31d30/71353b61dff705d4.png",
        },
        {
          id: "fish",
          prizeName: "海鲜套餐",
          prizeImg:
            "https://img14.360buyimg.com/imagetools/jfs/t1/90507/38/15165/448364/5e6f15b4E5df0c718/4bd4c3d375eec312.png",
        },
        {
          id: "thanks",
          prizeName: "谢谢参与",
          prizeImg:
            "https://img11.360buyimg.com/imagetools/jfs/t1/96116/38/15085/5181/5e6f15d1E48e31d30/71353b61dff705d4.png",
        },
      ]);
      // 转盘样式的选项
      const styleOpt = reactive({
        prizeItem: {},
        startStyle: {},
        contentBg: {
          background: "rgb(255, 231, 149)",
        },
      });
      // 中奖的奖品的index(此数据可根据后台返回的值重新赋值)
      const prizeIndex = ref(0);
      const startTurns = () => {
        const index = Math.floor(Math.random() * prizeList.value.length);
        prizeIndex.value = index;
      };
      const endTurns = () => {
        console.log("中奖了");
      };
      return {
        prizeList,
        styleOpt,
        prizeIndex,
        startTurns,
        endTurns,
      };
  }
}
</script>

此时代码已经编写完成,但编译是不通过的,默认情况下nut-bingo是不支持直接在nut-taro框架中使用的,强行运行会提示在 nut-taro的目录下模块包中是找不到bigMarquee,注意此bigMarquee多了big前缀,是无法找到对应组件的。

PS D:\Workspaces\taro\gwApp> cnpm run dev:weapp

> gwapp@1.0.0 dev:weapp
> npm run build:weapp -- --watch


> gwapp@1.0.0 build:weapp
> taro build --type weapp --watch

👽 Taro v3.6.1

Tips:
1. 预览模式生成的文件较大,设置 NODE_ENV 为 production 可以开启压缩。
Example:
$ set NODE_ENV=production && taro build --type weapp --watch
2. 建议开启持久化缓存功能,能有效提升二次编译速度,详情请参考: https://docs.taro.zone/docs/config-detail#cache。



✖ Webpack
  Compiled with some errors in 401.55ms

⚠️ Warnings: 

    at HarmonyImportSpecifierDependency.getLinkingErrors (D:\Workspaces\taro\gwApp\node_modules\.store\webpack@5.69.0\node_modules\webpack\lib\dependencies\HarmonyImportDependency.js:160:8)
ModuleDependencyWarning: export 'bigMarquee' (imported as '__unplugin_components_0') was not found in '@nutui/nutui-taro' (possible exports: ActionSheet, Address, AddressList, Animate, Audio, AudioOperate, Avatar, AvatarGroup, Backtop, Badge, Barrage, Button, Calendar, CalendarItem, Card, Cascader, Category, CategoryPane, Cell, CellGroup, Checkbox, CheckboxGroup, CircleProgress, Col, Collapse, CollapseItem, Comment, ConfigProvider, Countdown, Countup, DatePicker, Dialog, Divider, Drag, Ecard, Elevator, Ellipsis, Empty, FixedNav, Form, FormItem, Grid, GridItem, Image, ImagePreview, Indicator, InfiniteLoading, Input, InputNumber, Invoice, Layout, List, Locale, Menu, MenuItem, Navbar, Noticebar, Notify, NumberKeyboard, Overlay, Pagination, Picker, Popover, Popup, Price, Progress, PullRefresh, Radio, RadioGroup, Range, Rate, Row, Searchbar, ShortPassword, SideNavbar, SideNavbarItem, Signature, Skeleton, Sku, Step, Steps, Sticky, SubSideNavbar, Swipe, Swiper, SwiperItem, Switch, TabPane, Tabbar, TabbarItem, Table, Tabs, Tag, Textarea, TimeDetail, TimePannel, TimeSelect, Toast, Tour, TrendArrow, Uploader, Video, Watermark, default, install, version)

✖ Errors: 

resolve '@nutui/nutui-taro/dist/packages/bigmarquee/style' in 'D:\Workspaces\taro\gwApp\src\pages\draw'
  Parsed request is a module
  using description file: D:\Workspaces\taro\gwApp\package.json (relative path: ./src/pages/draw)
    Field 'browser' doesn't contain a valid alias configuration
    resolve as module
      D:\Workspaces\taro\gwApp\src\pages\draw\node_modules doesn't exist or is not a directory
      D:\Workspaces\taro\gwApp\src\pages\node_modules doesn't exist or is not a directory
      D:\Workspaces\taro\gwApp\src\node_modules doesn't exist or is not a directory
      looking for modules in D:\Workspaces\taro\gwApp\node_modules
        existing directory D:\Workspaces\taro\gwApp\node_modules\@nutui\nutui-taro
          using description file: D:\Workspaces\taro\gwApp\node_modules\@nutui\nutui-taro\package.json (relative path: .)
            using description file: D:\Workspaces\taro\gwApp\node_modules\@nutui\nutui-taro\package.json (relative path: ./dist/packages/bigmarquee/style)

nutui-bingo适配修改

因为官方目前还在做nutui-bingo组件的小程序适配方案,但我们为了使Marquee跑马灯组件能在nutui-taro框架中集成使用,需自行进行适配修改;

首先我们通过编译错误,我们了解到bigMarquee在@nutui/nutui-taro模块包中不存在

ModuleDependencyWarning: export 'bigMarquee' (imported as '__unplugin_components_0') was not found in '@nutui/nutui-taro' ....
....
resolve '@nutui/nutui-taro/dist/packages/bigmarquee/style' in 'D:\Workspaces\taro\gwApp\src\pages\draw'
....

根据提示我们进入到node_modules/@nutui/nutui-taro/dist/packages/,并未发现bigmarquee包目录,实际不存在;

bigMarquee是如何生成的,我们实际配置的是Marquee组件名称。

通过全局搜索,在项目下的components.d.ts文件中找到bigMarquee,同时发现所有引用的nutui-taro组件均在该配置文件中有自动生成,其中的NutbigMarquee组件从导入的’@nutui/nutui-taro’包中引用了’bigMarquee’

....
NutbigMarquee: typeof import('@nutui/nutui-taro')['bigMarquee']
NutCell: typeof import('@nutui/nutui-taro')['Cell']
....

也就是该NutbigMarquee组件指向的bigMarquee名称,是taro在编译时通过小程序页面的使用nut标签,在components.d.ts中生成的对应组件名称,在由nutui-taro根据app.ts中app.use(Marquee)加载的组件名称进行匹配,但是其它引入组件则没有big前缀,如:Cell。通过对比组件的标签用法,我们发现标签前缀不同;并且Marquee组件理因是’@nutui/nutui-bingo’模块下的,而非’@nutui/nutui-taro’模块下,因此该bigMarquee名称生成是错误的;

<!-- nutui-taro组件 -->
<nut-cell>
<!-- nutui-bingo组件 -->
<nutbig-marquee>

通过进一步对nutui-taro的组件名生成方式研究,其实该组件名称是通过小程序项目下的config/index.js配置文件内的函数逻辑生成;

const NutUIResolver = () => {
  return (name) => {
    if (name.startsWith('Nut')) {
      const partialName = name.slice(3);
      return {
        name: partialName,
        from: '@nutui/nutui-taro',
        sideEffects: `@nutui/nutui-taro/dist/packages/${partialName.toLowerCase()}/style`
      }
    }
  }
}

const config = {
    ...
    mini: {
        miniCssExtractPluginOption: {
          ignoreOrder: true,
        },
        webpackChain(chain) {
          chain.plugin('unplugin-vue-components').use(Components({
            resolvers: [NutUIResolver()]
          }))
        },
        ...    
    }
    ...
}

原来小程序中的组件名生成是通过NutUIResolver()函数,判断子组件name的前3位为Nut,在通过name.slice(3)截取剩余字符内容为需要的子组件名称,并且告知框架该组件来源于from表示的模块包名,并引入sideEffects表示的模块样式;

基本了解组件编译流程后,bigMarquee的来源,就是因为页面中使用的是组件标签,slice(3)截取后变成了big-marquee,小程序页面在编译的时间,通过页面的组件标签转换成bigMarquee后在nutui-taro框架模块下找不到该子组件,因此也导致编译不通过;

对NutUIResolver()函数进入改造,使改造后生成的子组件名称,适配标签;

const NutUIResolver = () => {
  return (name) => {
    if (name.startsWith('Nutbig')) {
      const partialName = name.slice(6);
      return {
        name: partialName,
        from: '@nutui/nutui-bingo',
        sideEffects: `@nutui/nutui-bingo/dist/packages/${partialName.toLowerCase()}/style`
      }
    } else if (name.startsWith('Nut')) {
      const partialName = name.slice(3);
      return {
        name: partialName,
        from: '@nutui/nutui-taro',
        sideEffects: `@nutui/nutui-taro/dist/packages/${partialName.toLowerCase()}/style`
      }
    }
  }
}

对组件名为nutbig开头,重新按slice(6)位截取,使其能正常的匹配到app.use(Marquee)加载的组件名,成功将Marquee组件捆绑到小程序页面标签上;from指向正确的@nutui/nutui-bingo模块包,sideEffects指向不变(注:实际nutui-bingo模块下的打包子模块组件目录中并没有style);

增加nutui-bingo子组件style样式配置

默认安装nutui-bingo组件后,在@nutui/nutui-bingo/dist/packages/marquee文件夹下是没有style对应的样式引入文件,需要手动创建,可以参考@nutui/nutui-taro/dist/packages下的子组件内的style.mjs,在当前marquee文件下创建一个相同的style.mjs文件

import '../../styles/variables.scss';
import './index.scss';

增加上面的引入scss样式文件,从而使sideEffects通够成功匹配到style样式引入文件

我们来看报bigMarquee样式引入失败时的提示

resolve '@nutui/nutui-taro/dist/packages/bigmarquee/style' in 'D:\Workspaces\taro\gwApp\src\pages\draw'

通过对项目下config/index.js的NutUIResolver()函数进入改造后,会重新匹配@nutui/nutui-taro/dist/packages/marquee/style样式引入文件,此时文件已经存在,则保证能够通过taro的编译较验;


执行Taro编译

在VSCode的终端命令行窗口执行cnpm run dev:weapp

PS D:\Workspaces\taro\gwApp> cnpm run dev:weapp

> gwapp@1.0.0 dev:weapp
> npm run build:weapp -- --watch


> gwapp@1.0.0 build:weapp
> taro build --type weapp --watch

👽 Taro v3.6.1

Tips:
1. 预览模式生成的文件较大,设置 NODE_ENV 为 production 可以开启压缩。
Example:
$ set NODE_ENV=production && taro build --type weapp --watch
2. 建议开启持久化缓存功能,能有效提升二次编译速度,详情请参考: https://docs.taro.zone/docs/config-detail#cache。



✔ Webpack
  Compiled successfully in 329.67ms

→ Watching... [2023/3/10 14:05:56]

成功通过编译;


NutbigMarquee组件引用名

再次打开项目下的components.d.ts文件,正常生成NutbigMarquee组件,并且从正确的’@nutui/nutui-bingo’导入’Marquee’;

....
NutbigMarquee: typeof import('@nutui/nutui-bingo')['Marquee']
NutCell: typeof import('@nutui/nutui-taro')['Cell']
....

运行小程序抽奖

打开微信小程序开发工具,加载项目目录,成功加载编译后的页面;

到此成功将untui-bingo下的跑马灯组件集成到了小程序中;



版权声明:本文为jilo88原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。