为P5写一个Vue组件库,让页面绚丽多彩
p5.js
是一个JavaScript的函数库,它在制作之初就和Processing有同样的目标。就是让艺术家,设计师,教育工作者和编程初学者能够很容易,很轻松地学习和使用程序设计。并且它也能给现在的网页带来一些新的东西,例如 p5 的官方网站。
定义组件
创建 p5.vue
文件,这个文件是 p5 组件的定义文件,我们主要在这个文件中来实现主要功能。
定义 template 如下:
<template>
<div ref="p5"></div>
</template>
看起来很简单,只需要一个 div 容器进行包裹,因为 p5 默认会创建一个 canvas 标签,并插入到指定的父容器中,我们这里为 div 设置了 ref 属性就是为了能准确的插入到这个容器。
首先引入 p5.js,p5 的源码可以在官网下载:
import p5 from '../lib/p5'
然后定义组件的功能,可以在 script 中写入:
export default {
name: 'P5',
props: {
sketch: Function,
},
methods: {
defaultSketch(p5) {
p5.setup = () => {
p5.createCanvas(100, 100);
};
p5.draw = () => {
p5.background(0);
};
}
},
mounted() {
let el = this.refs.p5;
let p5cv = new p5(this.sketch || this.defaultSketch, el);
this.emit("created", p5cv);
}
}
简单分析一下。
这个组件有一个 props 属性为 sketch
,这个属性被定义为一个函数,目的是外部提供一个函数,这个函数就是 p5 绘图函数。
defaultSketch
方法是默认方法,也是默认绘图函数,在组件外部没有提供绘图函数的时候,内部将调用这个默认函数来绘制一个简单的 canvas ,来填充视觉上的空白。
最后来到 mounted
生命周期函数中,p5 画布的挂载和绘图函数都是在这里进行的,所以也在这里挂载即可。
由于这个组件是外部控制的,所以我们不需要定义样式文件。
引用组件
组件定义完成后,只需要在另一个组件中引用当前组件即可。
<template>
<div class="p5-demo">
<p5 :sketch="sketch" @created="onP5Created"></p5>
</div>
</template>
然后定义组件的一些数据和绘图函数。
import p5 from '@/components/P5'
export default {
name: "webpage",
components: { p5 },
data() {
return {
p5obj: null
}
},
methods: {
// p5 绘图函数
sketch(p5) {
p5.setup = () => {
p5.createCanvas(800, 300);
p5.rectMode(p5.CENTER);
p5.noStroke();
p5.angleMode(p5.DEGREES);
}
p5.draw = () => {
p5.background("#fbf7d8");
p5.push();
p5.translate(p5.width / 2, p5.height / 2);
p5.rotate(45);
p5.fill(237, 34, 93);
p5.rect(0, 0, 150, 150);
p5.pop();
p5.push();
p5.translate(p5.width / 2, p5.height / 2);
p5.rotate(30);
p5.fill(255, 255, 255);
p5.rect(0, 0, 75, 75);
p5.pop();
}
},
onP5Created(obj) {
this.p5obj = obj;
}
}
}
然后得到一张图片:
组件优化
可以看到,目前为止,这个组件的绘图函数是在外部组件中定义的,很多时候一个绘图函数会比较长,这样会影响外部组件的阅读,所以我们可以把绘图函数独立起来,放在另一个文件中管理。
假设我们的绘图函数全部放在 /lib/p5/
下,那么上面的绘图函数就可以这样改写了:
// p5 sketch demo
module.exports = (p5, context) => {
p5.setup = () => {
p5.createCanvas(800, 300);
p5.rectMode(p5.CENTER);
p5.noStroke();
p5.angleMode(p5.DEGREES);
}
p5.draw = () => {
p5.background("#fbf7d8");
p5.push();
p5.translate(p5.width / 2, p5.height / 2);
p5.rotate(45);
p5.fill(237, 34, 93);
p5.rect(0, 0, 150, 150);
p5.pop();
p5.push();
p5.translate(p5.width / 2, p5.height / 2);
p5.rotate(30);
p5.fill(255, 255, 255);
p5.rect(0, 0, 75, 75);
p5.pop();
}
}
然后在外部组件中引入绘图函数。
import p5 from '@/components/P5'
// 引入绘图函数
import p5_demo from '../lib/p5/demo'
export default {
...
methods: {
sketch(p5) {
return p5_demo(p5, this);
}
}
...
}
这样一来,组件就变得清爽了,绘图函数和组件的业务也就可以分离,同时,在绘图函数中也引入了组件的上下文,所以如果有一些数据需要和绘图函数进行同步,则可以通过这个上下文对象来实现。
组件打包
组件开发完成后,则需要将其打包,作为一个独立组件,可以在任何一个 Vue 项目中引用。
修改 package.json ,增加一个打包指令。
"scripts": {
"lib:p5": "vue-cli-service build --target lib --name p5-vue ./src/components/p5.index.js"
}
这里的入口文件为 p5.index.js
,所以创建这个文件,在其中注册 p5 组件。
import P5 from './P5.vue'
P5.install = function (Vue) {
Vue.component(P5.name, P5);
}
// 定义 install 方法
const install = function (Vue) {
if (install.installed) return;
install.installed = true;
// 遍历并注册全局组件
Vue.component(P5.name, P5);
}
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue);
}
export default {
install,
P5
}
运行打包:
npm run lib:p5
之后即可在 dist 目录下看到打包好的文件。