【插件开发】升级Vue2.x+Element-ui+组件式开发Creator2.x

前言

当我们需要制作更复杂的插件时,你可能希望有更多封装好的组件可以使用,或者你希望更灵活地控制UI适配、配色、动态适配…

这些功能HTML开发中都已经有非常多的解决方案啦! 得益于Cocos插件面板可以使用HTML进行开发,我们也可以通过引入Vue、UI组件库等模块解决这些问题!还好上学时技能点得比较花,当时就想到了Vuetify、Quasar、Element-UI这些ui组件库。
一顿操作之后发现,Creator内置的Vue版本才1.x,组件库基本要求2.x​:sweat_smile:
Vue2.x提供了比Vue1.x更多的功能,比如组件式开发,我们可以封装自己的组件(就像游戏中的Prefab)。
所以我们也顺便把内置的Vue版本升级一下!

虽然经过了多次没有结果的尝试以及放弃,但还是给我折腾出来了!
写出来跟大家分享一下,虽然并没有实现全部Element-UI的功能,如果有大佬研究过了,还希望不吝赐教~
源码已发布至Store,如果你不想自己动手,可直接翻到结尾~

一、使用Vue

创建空插件

起手式不赘述了了,我创建的插件名是vuedemo,注意修改对应的路径~
附上官方文档:
你的第一个扩展包 · Cocos Creator

下载vue脚本

可以前往以下网站获取:
vue CDN by jsDelivr - A CDN for npm and GitHub

引入Vue

将下载的脚本放到插件目录中
image
并在index.js文件中导入vue脚本:
const Vue = Editor.require(packages://vuedemo/utils/vue.js);

测试Vue

写一个简单的页面

// index.js
Editor.Panel.extend({
  style: "",

  template: `
  <div id="app">{{name}}</div>
  `,

  $: {
    app: '#app',
  },

  ready() {
    new Vue({
      el: this.$app,
      data: {
        name: "hello world~"
      },
      methods: {

      }
    });
  },

  messages: {

  }
});

image
至此就顺利引入了Vue。这部分还是很简单的。
需要注意的是,要暴露Vue对应的根节点,即代码中的#app

:exclamation: 注意
Creator内置了Vue,所以一定要手动导入Vue,不能使用npm安装Vue,也不能直接require(“vue”)导入!

二、使用Element-UI

引入Element-UI

Element-UI可以选择使用npm方式引入:
npm install Element-UI
由于Element-UI基于Vue2.x,因此不需要指定版本(demo的Element-UI版本:2.15.13)
image
除了Element-UI本身,还会下载一堆它的依赖项,问题不大。

注册Element-UI

// index.js
const Vue = Editor.require(`packages://vuedemo/utils/vue.js`);

const VueCache = window.Vue;
window.Vue = Vue;
const ElementUi = Editor.require(`packages://vuedemo/node_modules/element-ui`);
Vue.use(ElementUi);
window.Vue = VueCache;

虽然注册只需要简单的一句Vue.use,但由于存在内置的Vue1.x,需要临时替换全局变量**Vue**为Vue2.x,否则Element-UI会被注册到Vue1.x上:roll_eyes:
由于Element-UI并没有内置版本,你也可以使用require(element-ui);

引用样式文件

Element-UI的样式文件(css)需要单独引入。我们可以将它写到html代码(template属性)中。

// index.js
template: `
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="${Editor.url("packages://vuedemo/node_modules/element-ui/lib/theme-chalk/index.css")}">
  </head>
	<div id="app">{{name}}</div>
`

这里使用了绝对路径,不是很美观,但相对路径并不是当前文件夹… 如果你有更好的方案欢迎留言讨论~

测试Element-UI

复制一段官网的代码来试试看~

// index.js
Editor.Panel.extend({
  template: `
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="${Editor.url("packages://vuedemo/node_modules/element-ui/lib/theme-chalk/index.css")}">
  </head>
  <div id="app">
    <div>{{name}}</div>
    <el-row>
      <el-button type="primary">主要按钮</el-button>
      <el-button type="success">成功按钮</el-button>
      <el-button type="info">信息按钮</el-button>
      <el-button type="warning">警告按钮</el-button>
      <el-button type="danger">危险按钮</el-button>
    </el-row>
  </div>
  `,
});

:exclamation: 注意
所有HTML元素都应放在app元素之内,否则会失去Vue、Element-UI的功能。

image
水哦~
Element-UI封装了大量常用的组件,可以极大地减少开发的成本。

三、Vue组件式开发

创建组件

这里会将上面的按钮组作为一个组件(vue的component)来示例。
先创建对应的文件夹、文件:
image
编写组件脚本内容:

// components/buttonGroup.js
Vue.component("button-group", {
    template: `
    <div>
      <el-row>
        <el-button type="primary">{{buttonName}}</el-button>
        <el-button type="success">成功按钮</el-button>
        <el-button type="info">信息按钮</el-button>
        <el-button type="warning">警告按钮</el-button>
        <el-button type="danger">危险按钮</el-button>
      </el-row>
    </div>
    `,
    data() {
        return {
            buttonName: "一个按钮"
        }
    },
});

导入组件

返回到index.js中,导入上面制作的buttonGroup组件:

// index.js
const VueCache = window.Vue;
window.Vue = Vue;
const ElementUi = Editor.require(`packages://vuedemo/node_modules/element-ui`);
Vue.use(ElementUi);
// 👇在这里
Editor.require(`packages://vuedemo/components/buttonGroup.js`);
// 👆在这里
window.Vue = VueCache;

只需要一行代码。
注意:要写在Vue被覆盖之后。这是为了组件代码中可以直接通过全局变量使用Vue,而不需要再次导入。

使用组件

在HTML代码中添加组件:

// index.js
Editor.Panel.extend({
  template: `
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="${Editor.url("packages://vuedemo/node_modules/element-ui/lib/theme-chalk/index.css")}">
  </head>
  <div id="app">
    <div>{{name}}</div>
    <div>👇在这里</div>
    <button-group></button-group>
    <div>👆在这里</div>
  </div>
  `
});

image
完成~
组件的功能远不止演示的这么一点,它还可以传递参数、回调…
组件可以对常用的组件进行复用,也减少了单文件下的复杂代码逻辑。具体就看Vue文档啦~

四、一些问题

虽然到这里已经可以使用了,但其实有一些隐藏问题。

  1. 有部分Element-UI的功能无法使用,比如Message、Notification。

无法使用的原因是,代码中使用了import Vue from 'vue';,这样获取到的是内置的Vue,因此调用时会产生错误。
我尝试修改代码,使其得到正确的Vue,但遇到了另一个奇怪的问题… 它们被挂到了页面上,但是不显示:crazy_face:
庆幸的是,这部分功能只有若干(会动态挂载节点的)模块,其他功能不受影响。
image

  1. 无法使用Element-UI的字体图标

我看到了字体文件的css代码文件,但就是无法正确显示…

这些内容稍微超出了我微弱的前端知识… 如果有相关解决方案,欢迎指教~

五、想不到吧有解决方案

无法使用字体

const fontStyleTag = document.createElement('style');

fontStyleTag.innerHTML = `
@font-face {
  font-family: element-icons;
  src: url('https://unpkg.com/element-ui/lib/theme-chalk/fonts/element-icons.woff') format("woff"),
    url('https://unpkg.com/element-ui/lib/theme-chalk/fonts/element-icons.ttf') format("truetype");
  font-weight: 400;
  font-display: "auto";
  font-style: normal
}`;

document.head.appendChild(fontStyleTag);

不知道为何,无法从html代码中发出http请求,因此下载不到对应的字体文件。
上述方案中,通过代码动态地在中插入了节点,就可以顺利进行下载了。这不是一个很完美的方案,但能解决问题。

无法使用部分功能的问题,虽然修改源码可以绕过require和显示等问题,但修改npm包源码会不利于传播和升级,如果不是必要的话,还是不改了吧。

结尾

过程中踩了许多坑,主要还是因为内置Vue… 导致同时存在两个Vue版本,需要各种处理:persevere:
个人其实更喜欢Vuetify,但Vuetify在内部逻辑上禁止同时存在多个Vue版本,尝试了好几次最后还是放弃了。

如果你在读完本文后没有达到最后的效果,可以参考我发布在商店的示例源码(需要一瓶快乐水):
Cocos Store-vue2.x+element-ui插件开发示例源码

感谢论坛各位大佬的经验,给了我很多的帮助,本文主要参考了以下论坛文章:
成功!cc2.*+ 插件升级vue并引入element-ui组件

2赞

优秀如你~~

大佬这个是不是vue3也适用?

理论可行~ vue.js文件换成vue3的即可

很赞啊,大佬

这个真的很赞