├── README.md ├── bin ├── Ribbon.vue ├── RibbonAnimation.vue ├── enhanceAppFile.js └── ribbon.js ├── index.js └── package.json /README.md: -------------------------------------------------------------------------------- 1 | ## 💌 vuepress-plugin-ribbon-animation 2 | 3 | > 项目地址:[https://www.zpzpup.com/blog] 4 | 5 | > vue vuepress vuepress-theme-reco vuepress-plugin-ribbon 感谢支持 6 | 7 | ## 📢 说明 8 | 9 | ***放到开头,这里重点说明下,大家如果有啥问题咱就直接提‘lssues’吧,后面朋友遇到相同问题大家也可以参考*** 10 | 11 | ## 🏠 项目截图 12 |

13 | 14 |

15 | 16 | 17 | ## 📎 项目配置也是很简单 18 | > npm install vuepress-plugin-ribbon-animation -D 19 | 20 | or 21 | 22 | >cnpm install vuepress-plugin-ribbon-animation -D 23 | 24 | 1.1.1 修复打包bug 25 | 26 | 1.1.2 修复组件高度bug 27 | 28 | 1.1.3 去掉console 29 | 30 | 大家目前去用1.1.3的版本 前面几个是测试用的版本 其他的大家就提lssues吧 31 | 32 | ```js 33 | // 只要把这个放进 config的plugins中就可以了 有木有很简单 34 | ["ribbon-animation", { 35 | size: 90, // 默认数据 36 | opacity: 0.3, // 透明度 37 | zIndex: -1, // 层级 38 | opt: { 39 | // 色带HSL饱和度 40 | colorSaturation: "80%", 41 | // 色带HSL亮度量 42 | colorBrightness: "60%", 43 | // 带状颜色不透明度 44 | colorAlpha: 0.65, 45 | // 在HSL颜色空间中循环显示颜色的速度有多快 46 | colorCycleSpeed: 6, 47 | // 从哪一侧开始Y轴 (top|min, middle|center, bottom|max, random) 48 | verticalPosition: "center", 49 | // 到达屏幕另一侧的速度有多快 50 | horizontalSpeed: 200, 51 | // 在任何给定时间,屏幕上会保留多少条带 52 | ribbonCount: 2, 53 | // 添加笔划以及色带填充颜色 54 | strokeSize: 0, 55 | // 通过页面滚动上的因子垂直移动色带 56 | parallaxAmount: -0.5, 57 | // 随着时间的推移,为每个功能区添加动画效果 58 | animateSections: true 59 | }, 60 | ribbonShow: false, // 点击彩带 true显示 false为不显示 61 | ribbonAnimationShow: true // 滑动彩带 62 | }] 63 | ``` 64 | 如果觉得很省事,帮到你了可以点个 ⭐ star 感激不尽 😁😁😁 [链接:🚀](https://github.com/JabinPeng/vuepress-plugin-ribbon-animation). 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /bin/Ribbon.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 124 | -------------------------------------------------------------------------------- /bin/RibbonAnimation.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 24 | -------------------------------------------------------------------------------- /bin/enhanceAppFile.js: -------------------------------------------------------------------------------- 1 | import Ribbon from "./Ribbon.vue"; 2 | import RibbonAnimation from './RibbonAnimation.vue' 3 | export default ({ 4 | Vue 5 | }) => { 6 | Vue.component(Ribbon.name, Ribbon); 7 | Vue.component(RibbonAnimation.name, RibbonAnimation); 8 | }; 9 | -------------------------------------------------------------------------------- /bin/ribbon.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ribbons Class File. 3 | * Creates low-poly ribbons background effect inside a target container. 4 | */ 5 | (function (name, factory) 6 | { 7 | if (typeof window === "object") 8 | { 9 | window[name] = factory(); 10 | } 11 | 12 | })("Ribbons", function () 13 | { 14 | var _w = window, 15 | _b = document.body,//返回html dom中的body节点 即 16 | _d = document.documentElement;//返回html dom中的root 节点 即 17 | 18 | // random helper 19 | var random = function () 20 | { 21 | if (arguments.length === 1) // only 1 argument 22 | { 23 | if (Array.isArray(arguments[0])) // extract index from array 24 | { 25 | var index = Math.round(random(0, arguments[0].length - 1)); 26 | return arguments[0][index]; 27 | } 28 | return random(0, arguments[0]); // assume numeric 29 | } else 30 | if (arguments.length === 2) // two arguments range 31 | { 32 | return Math.random() * (arguments[1] - arguments[0]) + arguments[0]; 33 | } 34 | return 0; // default 35 | }; 36 | 37 | // screen helper 38 | var screenInfo = function (e) 39 | { 40 | var width = Math.max(0, _w.innerWidth || _d.clientWidth || _b.clientWidth || 0), 41 | height = Math.max(0, _w.innerHeight || _d.clientHeight || _b.clientHeight || 0), 42 | scrollx = Math.max(0, _w.pageXOffset || _d.scrollLeft || _b.scrollLeft || 0) - (_d.clientLeft || 0), 43 | scrolly = Math.max(0, _w.pageYOffset || _d.scrollTop || _b.scrollTop || 0) - (_d.clientTop || 0); 44 | 45 | return { 46 | width: width, 47 | height: height, 48 | ratio: width / height, 49 | centerx: width / 2, 50 | centery: height / 2, 51 | scrollx: scrollx, 52 | scrolly: scrolly }; 53 | 54 | }; 55 | 56 | // mouse/input helper 57 | var mouseInfo = function (e) 58 | { 59 | var screen = screenInfo(e), 60 | mousex = e ? Math.max(0, e.pageX || e.clientX || 0) : 0, 61 | mousey = e ? Math.max(0, e.pageY || e.clientY || 0) : 0; 62 | 63 | return { 64 | mousex: mousex, 65 | mousey: mousey, 66 | centerx: mousex - screen.width / 2, 67 | centery: mousey - screen.height / 2 }; 68 | 69 | }; 70 | 71 | // point object 72 | var Point = function (x, y) 73 | { 74 | this.x = 0; 75 | this.y = 0; 76 | this.set(x, y); 77 | }; 78 | Point.prototype = { 79 | constructor: Point, 80 | 81 | set: function (x, y) 82 | { 83 | this.x = x || 0; 84 | this.y = y || 0; 85 | }, 86 | copy: function (point) 87 | { 88 | this.x = point.x || 0; 89 | this.y = point.y || 0; 90 | return this; 91 | }, 92 | multiply: function (x, y) 93 | { 94 | this.x *= x || 1; 95 | this.y *= y || 1; 96 | return this; 97 | }, 98 | divide: function (x, y) 99 | { 100 | this.x /= x || 1; 101 | this.y /= y || 1; 102 | return this; 103 | }, 104 | add: function (x, y) 105 | { 106 | this.x += x || 0; 107 | this.y += y || 0; 108 | return this; 109 | }, 110 | subtract: function (x, y) 111 | { 112 | this.x -= x || 0; 113 | this.y -= y || 0; 114 | return this; 115 | }, 116 | clampX: function (min, max) 117 | { 118 | this.x = Math.max(min, Math.min(this.x, max)); 119 | return this; 120 | }, 121 | clampY: function (min, max) 122 | { 123 | this.y = Math.max(min, Math.min(this.y, max)); 124 | return this; 125 | }, 126 | flipX: function () 127 | { 128 | this.x *= -1; 129 | return this; 130 | }, 131 | flipY: function () 132 | { 133 | this.y *= -1; 134 | return this; 135 | } }; 136 | 137 | 138 | // class constructor 139 | var Factory = function (options) 140 | { 141 | this._canvas = null; 142 | this._context = null; 143 | this._sto = null; 144 | this._width = 0; 145 | this._height = 0; 146 | this._scroll = 0; 147 | this._ribbons = []; 148 | this._options = options; 149 | 150 | this._onDraw = this._onDraw.bind(this); 151 | this._onResize = this._onResize.bind(this); 152 | this._onScroll = this._onScroll.bind(this); 153 | this.setOptions(options); 154 | this.init(); 155 | }; 156 | 157 | // class prototype 158 | Factory.prototype = { 159 | constructor: Factory, 160 | 161 | // Set and merge local options 162 | setOptions: function (options) 163 | { 164 | if (typeof options === "object") 165 | { 166 | for (var key in options) 167 | { 168 | if (options.hasOwnProperty(key)) 169 | { 170 | this._options[key] = options[key]; 171 | } 172 | } 173 | } 174 | }, 175 | 176 | // Initialize the ribbons effect 177 | init: function () 178 | { 179 | try 180 | { 181 | this._canvas = document.createElement("canvas"); 182 | this._canvas.style["display"] = "block"; 183 | this._canvas.style["position"] = "fixed"; 184 | this._canvas.style["margin"] = "0"; 185 | this._canvas.style["padding"] = "0"; 186 | this._canvas.style["border"] = "0"; 187 | this._canvas.style["outline"] = "0"; 188 | this._canvas.style["left"] = "0"; 189 | this._canvas.style["top"] = "0"; 190 | this._canvas.style["width"] = "100%"; 191 | this._canvas.style["height"] = "100%"; 192 | this._canvas.style["z-index"] = "-1"; 193 | // this._canvas.style["background-color"]="#1f1f1f"; 194 | this._canvas.id = "bgCanvas"; 195 | this._onResize(); 196 | 197 | this._context = this._canvas.getContext("2d"); 198 | this._context.clearRect(0, 0, this._width, this._height); 199 | this._context.globalAlpha = this._options.colorAlpha; 200 | 201 | window.addEventListener("resize", this._onResize); 202 | window.addEventListener("scroll", this._onScroll); 203 | document.body.appendChild(this._canvas); 204 | } 205 | catch (e) { 206 | console.warn("Canvas Context Error: " + e.toString()); 207 | return; 208 | } 209 | this._onDraw(); 210 | }, 211 | 212 | // Create a new random ribbon and to the list 213 | addRibbon: function () 214 | { 215 | // movement data 216 | var dir = Math.round(random(1, 9)) > 5 ? "right" : "left", 217 | stop = 1000, 218 | hide = 200, 219 | min = 0 - hide, 220 | max = this._width + hide, 221 | movex = 0, 222 | movey = 0, 223 | startx = dir === "right" ? min : max, 224 | starty = Math.round(random(0, this._height)); 225 | 226 | // asjust starty based on options 227 | if (/^(top|min)$/i.test(this._options.verticalPosition)) 228 | { 229 | starty = 0 + hide; 230 | } else 231 | if (/^(middle|center)$/i.test(this._options.verticalPosition)) 232 | { 233 | starty = this._height / 2; 234 | } else 235 | if (/^(bottom|max)$/i.test(this._options.verticalPosition)) 236 | { 237 | starty = this._height - hide; 238 | } 239 | 240 | // ribbon sections data 241 | var ribbon = [], 242 | point1 = new Point(startx, starty), 243 | point2 = new Point(startx, starty), 244 | point3 = null, 245 | color = Math.round(random(0, 360)), 246 | delay = 0; 247 | 248 | // buils ribbon sections 249 | while (true) 250 | { 251 | if (stop <= 0) break;stop--; 252 | 253 | movex = Math.round((Math.random() * 1 - 0.2) * this._options.horizontalSpeed); 254 | movey = Math.round((Math.random() * 1 - 0.5) * (this._height * 0.25)); 255 | 256 | point3 = new Point(); 257 | point3.copy(point2); 258 | 259 | if (dir === "right") 260 | { 261 | point3.add(movex, movey); 262 | if (point2.x >= max) break; 263 | } else 264 | if (dir === "left") 265 | { 266 | point3.subtract(movex, movey); 267 | if (point2.x <= min) break; 268 | } 269 | // point3.clampY( 0, this._height ); 270 | 271 | ribbon.push({ // single ribbon section 272 | point1: new Point(point1.x, point1.y), 273 | point2: new Point(point2.x, point2.y), 274 | point3: point3, 275 | color: color, 276 | delay: delay, 277 | dir: dir, 278 | alpha: 0, 279 | phase: 0 }); 280 | 281 | 282 | point1.copy(point2); 283 | point2.copy(point3); 284 | 285 | delay += 4; 286 | color += this._options.colorCycleSpeed; 287 | } 288 | this._ribbons.push(ribbon); 289 | }, 290 | 291 | // Draw single section 292 | _drawRibbonSection: function (section) 293 | { 294 | if (section) 295 | { 296 | if (section.phase >= 1 && section.alpha <= 0) 297 | { 298 | return true; // done 299 | } 300 | if (section.delay <= 0) 301 | { 302 | section.phase += 0.02; 303 | section.alpha = Math.sin(section.phase) * 1; 304 | section.alpha = section.alpha <= 0 ? 0 : section.alpha; 305 | section.alpha = section.alpha >= 1 ? 1 : section.alpha; 306 | 307 | if (this._options.animateSections) 308 | { 309 | var mod = Math.sin(1 + section.phase * Math.PI / 2) * 0.1; 310 | 311 | if (section.dir === "right") 312 | { 313 | section.point1.add(mod, 0); 314 | section.point2.add(mod, 0); 315 | section.point3.add(mod, 0); 316 | } else { 317 | section.point1.subtract(mod, 0); 318 | section.point2.subtract(mod, 0); 319 | section.point3.subtract(mod, 0); 320 | } 321 | section.point1.add(0, mod); 322 | section.point2.add(0, mod); 323 | section.point3.add(0, mod); 324 | } 325 | } else 326 | {section.delay -= 0.5;} 327 | 328 | var s = this._options.colorSaturation, 329 | l = this._options.colorBrightness, 330 | c = "hsla(" + section.color + ", " + s + ", " + l + ", " + section.alpha + " )"; 331 | 332 | this._context.save(); 333 | 334 | if (this._options.parallaxAmount !== 0) 335 | { 336 | this._context.translate(0, this._scroll * this._options.parallaxAmount); 337 | } 338 | this._context.beginPath(); 339 | this._context.moveTo(section.point1.x, section.point1.y); 340 | this._context.lineTo(section.point2.x, section.point2.y); 341 | this._context.lineTo(section.point3.x, section.point3.y); 342 | this._context.fillStyle = c; 343 | this._context.fill(); 344 | 345 | if (this._options.strokeSize > 0) 346 | { 347 | this._context.lineWidth = this._options.strokeSize; 348 | this._context.strokeStyle = c; 349 | this._context.lineCap = "round"; 350 | this._context.stroke(); 351 | } 352 | this._context.restore(); 353 | } 354 | return false; // not done yet 355 | }, 356 | 357 | // Draw ribbons 358 | _onDraw: function () 359 | { 360 | // cleanup on ribbons list to rtemoved finished ribbons 361 | for (var i = 0, t = this._ribbons.length; i < t; ++i) 362 | { 363 | if (!this._ribbons[i]) 364 | { 365 | this._ribbons.splice(i, 1); 366 | } 367 | } 368 | 369 | // draw new ribbons 370 | this._context.clearRect(0, 0, this._width, this._height); 371 | 372 | for (var a = 0; a < this._ribbons.length; ++a) // single ribbon 373 | { 374 | var ribbon = this._ribbons[a], 375 | numSections = ribbon.length, 376 | numDone = 0; 377 | 378 | for (var b = 0; b < numSections; ++b) // ribbon section 379 | { 380 | if (this._drawRibbonSection(ribbon[b])) 381 | { 382 | numDone++; // section done 383 | } 384 | } 385 | if (numDone >= numSections) // ribbon done 386 | { 387 | this._ribbons[a] = null; 388 | } 389 | } 390 | // maintain optional number of ribbons on canvas 391 | if (this._ribbons.length < this._options.ribbonCount) 392 | { 393 | this.addRibbon(); 394 | } 395 | requestAnimationFrame(this._onDraw); 396 | }, 397 | 398 | // Update container size info 399 | _onResize: function (e) 400 | { 401 | var screen = screenInfo(e); 402 | this._width = screen.width; 403 | this._height = screen.height; 404 | 405 | if (this._canvas) 406 | { 407 | this._canvas.width = this._width; 408 | this._canvas.height = this._height; 409 | 410 | if (this._context) 411 | { 412 | this._context.globalAlpha = this._options.colorAlpha; 413 | } 414 | } 415 | }, 416 | 417 | // Update container size info 418 | _onScroll: function (e) 419 | { 420 | var screen = screenInfo(e); 421 | this._scroll = screen.scrolly; 422 | } }; 423 | // export 424 | return Factory; 425 | }); 426 | export default Ribbons 427 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path') 2 | 3 | module.exports = (options = {}, context) => ({ 4 | define() { 5 | const { 6 | size = 90, opacity = 0.6, zIndex = -1, opt = { 7 | // 色带HSL饱和度 8 | colorSaturation: "80%", 9 | // 色带HSL亮度量 10 | colorBrightness: "60%", 11 | // 带状颜色不透明度 12 | colorAlpha: 0.65, 13 | // 在HSL颜色空间中循环显示颜色的速度有多快 14 | colorCycleSpeed: 6, 15 | // 从哪一侧开始Y轴 (top|min, middle|center, bottom|max, random) 16 | verticalPosition: "center", 17 | // 到达屏幕另一侧的速度有多快 18 | horizontalSpeed: 200, 19 | // 在任何给定时间,屏幕上会保留多少条带 20 | ribbonCount: 2, 21 | // 添加笔划以及色带填充颜色 22 | strokeSize: 0, 23 | // 通过页面滚动上的因子垂直移动色带 24 | parallaxAmount: -0.5, 25 | // 随着时间的推移,为每个功能区添加动画效果 26 | animateSections: true 27 | }, 28 | ribbonShow = true, 29 | ribbonAnimationShow = true 30 | } = options 31 | 32 | return { 33 | RIBBON_SIZE: size, 34 | RIBBON_OPACITY: opacity, 35 | RIBBON_Z_INDEX: zIndex, 36 | RIBBON_OPTIONS: opt, 37 | RIBBON_SHOW: ribbonShow, 38 | RIBBONANIMATION_SHOW: ribbonAnimationShow, 39 | } 40 | }, 41 | enhanceAppFiles: resolve(__dirname, "./bin/enhanceAppFile.js"), 42 | globalUIComponents: ["Ribbon", "RibbonAnimation"] 43 | }); 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuepress-plugin-ribbon-animation", 3 | "version": "1.1.2", 4 | "description": "ribbons plugin", 5 | "main": "index.js", 6 | "keywords": [ 7 | "vuepress", 8 | "ribbon", 9 | "animation" 10 | ], 11 | "author": "JabinPeng", 12 | "license": "MIT", 13 | "__npminstall_done": "Wed Jan 13 2021 21:00:17 GMT+0800 (GMT+08:00)", 14 | "_from": "vuepress-plugin-ribbon-animation@1.0.0", 15 | "_resolved": "https://registry.npm.taobao.org/vuepress-plugin-ribbon-animation/download/vuepress-plugin-ribbon-animation-1.0.0.tgz", 16 | "_gitHub": "https://github.com/JabinPeng/vuepress-plugin-ribbon-animation" 17 | } 18 | --------------------------------------------------------------------------------