ソースを参照

add: 添加刮刮卡

guoxiaoxiao8 5 年 前
コミット
5a4f8beb07

+ 10 - 0
src/config.json

@@ -671,6 +671,16 @@
       "showDemo": true,
       "author": "Ymm0008",
       "showTest": true
+    },
+    {
+      "version": "1.0.0",
+      "name": "Luckycard",
+      "type": "component",
+      "chnName": "刮刮卡",
+      "desc": "挂挂卡抽奖",
+      "sort": "6",
+      "showDemo": true,
+      "author": "guoxiao"
     }
   ]
 }

+ 8 - 4
src/nutui.js

@@ -134,6 +134,8 @@ import './packages/fixednav/fixednav.scss'; // import Gesture from './packages/g
 
 import Collapse from './packages/collapse/index.js';
 import './packages/collapse/collapse.scss';
+import Luckycard from "./packages/luckycard/index.js";
+import "./packages/luckycard/luckycard.scss";
 
 const packages = {
   Cell,
@@ -198,8 +200,10 @@ const packages = {
   Address,
   Notify,
   CountUp,
-  FixedNav, // Gesture: Gesture
-  Collapse: Collapse
+  FixedNav,
+  // Gesture: Gesture
+  Collapse: Collapse,
+  Luckycard: Luckycard
 };
 
 const components = {};
@@ -227,7 +231,7 @@ pkgList.map(item => {
   }
 });
 
-const install = function(Vue, opts = {}) {
+const install = function (Vue, opts = {}) {
   if (install.installed) return;
 
   if (opts.locale) {
@@ -283,4 +287,4 @@ export default {
   ...filters,
   ...directives,
   ...methods
-};
+};

+ 7 - 0
src/packages/luckycard/__test__/luckycard.spec.js

@@ -0,0 +1,7 @@
+import { shallowMount, mount } from '@vue/test-utils'
+import LuckyCard from '../luckycard.vue';
+import Vue from 'vue';
+		
+describe('LuckyCard.vue', () => {
+			
+});

+ 40 - 0
src/packages/luckycard/demo.vue

@@ -0,0 +1,40 @@
+<template>
+    <div class="demo-list">
+        <h4>基本用法</h4>
+        <nut-luckycard 
+        content="1000万"
+        ></nut-luckycard>
+        <h4>内容异步</h4>
+        <nut-luckycard 
+        :content="val"
+        ></nut-luckycard>
+        <h4>刮开层和背景层都支持自定义颜色,奖品信息支持HTML</h4>
+        <nut-luckycard 
+        coverColor="#F9CC9D" 
+        backgroundColor="#C3D08B" 
+        content="<em>1000<em><strong>元</strong>"
+        ></nut-luckycard>
+        <h4>刮开层支持图片</h4>
+        <nut-luckycard 
+        content="1000万" 
+        :coverImg="coverImage"
+        ></nut-luckycard>
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {
+            val:"谢谢惠顾",
+            coverImage:""
+        };
+    },
+    mounted(){
+        setTimeout(() => {
+           this.val="数据修改" 
+        }, 500);
+    },
+    methods: {
+    }
+}
+</script>

+ 49 - 0
src/packages/luckycard/doc.md

@@ -0,0 +1,49 @@
+# Luckycard 挂挂卡抽奖
+
+## 基本用法
+
+```html
+    <nut-luckycard 
+    content="1000万"
+    ></nut-luckycard>
+```
+## 异步数据
+
+```html
+    <nut-luckycard 
+    :content="val"
+    ></nut-luckycard>
+```
+## 支持自定义颜色
+
+```html
+    <nut-luckycard 
+        coverColor="#F9CC9D" 
+        backgroundColor="#C3D08B" 
+        content="<em>1000<em><strong>元</strong>"
+        ></nut-luckycard>
+```
+## 支持背景是图片
+
+```html
+    <nut-luckycard 
+        content="1000万" 
+        :coverImg="coverImage"
+        ></nut-luckycard>
+```
+
+## Prop
+
+| 字段 | 说明 | 类型 | 默认值
+|----- | ----- | ----- | ----- 
+| content | 奖项信息,支持html | String | ''
+| height | 卡片高度 | String | 50px
+| width | 卡片高度 | String | 300px
+| coverColor | 刮开层颜色 | String | ''
+| coverImg | 刮开层是图片(不支持跨域。设置此项后coverColor失效) | String | ''
+| fontSize | 中奖信息字号 | String | 20px
+| backgroundColor | 内容层背景颜色 | String | '#FFFFFF'
+| ratio | 触发事件的刮开比 | Number |0.5(介于0-1之间)
+
+
+

+ 8 - 0
src/packages/luckycard/index.js

@@ -0,0 +1,8 @@
+import LuckyCard from './luckycard.vue';
+import './luckycard.scss';
+
+LuckyCard.install = function(Vue) {
+  Vue.component(LuckyCard.name, LuckyCard);
+};
+
+export default LuckyCard

+ 206 - 0
src/packages/luckycard/luckycard.js

@@ -0,0 +1,206 @@
+/*
+ * lucky-card.js - Scratch CARDS based on HTML5 Canvas
+ *
+ * Copyright (c) 2015 Frans Lee dmon@foxmail.com
+ *
+ * Licensed under the MIT license:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *
+ * Version:  1.0.3
+ */
+'use strict';
+
+/**
+ * Instantiate parameters
+ *
+ * @constructor
+ */
+function LuckyCard(settings, callback) {
+    this.cover = null;
+    this.ctx = null;
+    this.scratchDiv = settings.scratchDiv;
+    this.cardDiv = null;
+    this.cHeight = 0;
+    this.cWidth = 0;
+    this.supportTouch = false;
+    this.events = [];
+    this.startEventHandler = null;
+    this.moveEventHandler = null;
+    this.endEventHandler = null;
+
+    this.opt = {
+        coverColor: '#C5C5C5',
+        coverImg: '',
+        ratio: .8,
+        callback: null
+    };
+
+    this.init(settings, callback);
+};
+
+function _calcArea(ctx, callback, ratio) {
+    var pixels = ctx.getImageData(0, 0, this.cWidth, this.cHeight);
+    var transPixels = [];
+    _forEach(pixels.data, function(item, i) {
+        var pixel = pixels.data[i + 3];
+        if (pixel === 0) {
+            transPixels.push(pixel);
+        }
+    });
+
+    if (transPixels.length / pixels.data.length > ratio) {
+        callback && typeof callback === 'function' && callback();
+    }
+}
+
+function _forEach(items, callback) {
+    return Array.prototype.forEach.call(items, function(item, idx) {
+        callback(item, idx);
+    });
+}
+
+function _isCanvasSupported() {
+    var elem = document.createElement('canvas');
+    return !!(elem.getContext && elem.getContext('2d'));
+}
+
+/**
+ * touchstart/mousedown event handler
+ */
+function _startEventHandler(event) {
+    event.preventDefault();
+    this.moveEventHandler = _moveEventHandler.bind(this);
+    this.cover.addEventListener(this.events[1], this.moveEventHandler, false);
+    this.endEventHandler = _endEventHandler.bind(this);
+    document.addEventListener(this.events[2], this.endEventHandler, false);
+};
+
+/**
+ * touchmove/mousemove event handler
+ */
+function _moveEventHandler(event) {
+    event.preventDefault();
+    var evt = this.supportTouch ? event.touches[0] : event;
+    var coverPos = this.cover.getBoundingClientRect();
+    var pageScrollTop = document.documentElement.scrollTop || document.body.scrollTop;
+    var pageScrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
+    var mouseX = evt.pageX - coverPos.left - pageScrollLeft;
+    var mouseY = evt.pageY - coverPos.top - pageScrollTop;
+
+    this.ctx.beginPath();
+    this.ctx.fillStyle = '#FFFFFF';
+    this.ctx.globalCompositeOperation = "destination-out";
+    this.ctx.arc(mouseX, mouseY, 10, 0, 2 * Math.PI);
+    this.ctx.fill();
+};
+
+/**
+ * touchend/mouseup event handler
+ */
+function _endEventHandler(event) {
+    event.preventDefault();
+    if (this.opt.callback && typeof this.opt.callback === 'function') _calcArea.call(this, this.ctx, this.opt.callback, this.opt.ratio);
+    this.cover.removeEventListener(this.events[1], this.moveEventHandler, false);
+    document.removeEventListener(this.events[2], this.endEventHandler, false);
+};
+
+/**
+ * Create Canvas element
+ */
+LuckyCard.prototype.createCanvas = function() {
+    this.cover = document.createElement('canvas');
+    this.cover.className = 'nut-cover';
+    this.cover.height = this.cHeight;
+    this.cover.width = this.cWidth;
+    this.ctx = this.cover.getContext('2d');
+    if (this.opt.coverImg) {
+        var _this = this;
+        var coverImg = new Image();
+        coverImg.src = this.opt.coverImg;
+        coverImg.onload = function() {
+            _this.ctx.drawImage(coverImg, 0, 0, _this.cover.width, _this.cover.height);
+        }
+    } else {
+        this.ctx.fillStyle = this.opt.coverColor;
+        this.ctx.fillRect(0, 0, this.cover.width, this.cover.height);
+    }
+    this.scratchDiv.appendChild(this.cover);
+    this.cardDiv.style.opacity = 1;
+}
+
+/**
+ * To detect whether support touch events
+ */
+LuckyCard.prototype.eventDetect = function() {
+    if ('ontouchstart' in window) this.supportTouch = true;
+    this.events = this.supportTouch ? ['touchstart', 'touchmove', 'touchend'] : ['mousedown', 'mousemove', 'mouseup'];
+    this.addEvent();
+};
+
+/**
+ * Add touchstart/mousedown event listener
+ */
+LuckyCard.prototype.addEvent = function() {
+    this.startEventHandler = _startEventHandler.bind(this);
+    this.cover.addEventListener(this.events[0], this.startEventHandler, false);
+};
+
+/**
+ * Clear pixels of canvas
+ */
+LuckyCard.prototype.clearCover = function() {
+    this.ctx.clearRect(0, 0, this.cover.width, this.cover.height);
+    this.cover.removeEventListener(this.events[0], this.startEventHandler);
+    this.cover.removeEventListener(this.events[1], this.moveEventHandler);
+    this.cover.removeEventListener(this.events[2], this.endEventHandler);
+};
+
+
+/**
+ * LuckyCard initializer
+ *
+ * @param {Object} settings  Settings for LuckyCard
+ * @param {function} callback  callback function
+ */
+LuckyCard.prototype.init = function(settings, callback) {
+    if (!_isCanvasSupported()) {
+        alert('对不起,当前浏览器不支持Canvas,无法使用本控件!');
+        return;
+    }
+    var _this = this;
+    _forEach(arguments, function(item) {
+        if (typeof item === "object") {
+            for (var k in item) {
+                if (k === 'callback' && typeof item[k] === 'function') {
+                    _this.opt.callback = item[k].bind(_this);
+                } else {
+                    k in _this.opt && (_this.opt[k] = item[k]);
+                }
+            }
+        } else if (typeof item === "function") {
+            _this.opt.callback = item.bind(_this);
+        }
+    });
+    /* this.scratchDiv = document.getElementById('scratch');*/
+    if (!this.scratchDiv) return;
+    this.cardDiv = this.scratchDiv.querySelector('.nut-content');
+    if (!this.cardDiv) return;
+
+    this.cHeight = this.cardDiv.clientHeight;
+    this.cWidth = this.cardDiv.clientWidth;
+    this.cardDiv.style.opacity = 0;
+    this.createCanvas();
+    this.eventDetect();
+};
+
+/**
+ * To generate an instance of object
+ *
+ * @param {Object} settings  Settings for LuckyCard
+ * @param {function} callback  callback function
+ */
+LuckyCard.case = function(settings, callback) {
+    return new LuckyCard(settings, callback);
+};
+
+export default LuckyCard.case;

+ 3 - 0
src/packages/luckycard/luckycard.scss

@@ -0,0 +1,3 @@
+.nut-luckycard{
+
+}

+ 86 - 0
src/packages/luckycard/luckycard.vue

@@ -0,0 +1,86 @@
+<template>
+    <div class="nut-luckycard" :style="{height:height+'px',width:width+'px'}">
+        <div class="nut-content" v-html="content" :style="{backgroundColor:backgroundColor,fontSize:fontSize+'px'}"></div>
+    </div>
+</template>
+
+<script>
+import LuckyCard from './luckycard.js';
+export default {
+    name:'nut-luckycard',
+    props: {
+        content:{
+            type:String,
+            default:''
+        },
+        height: {
+            type: [String, Number],
+            default: 50
+        },
+        width: {
+            type: [String, Number],
+            default: 300
+        },
+        coverColor:{
+            type:String,
+            default:'#C5C5C5'
+        },
+        coverImg:{
+            type:String,
+            default:''
+        },
+        fontSize:{
+            type:[String, Number],
+            default:20
+        },
+        backgroundColor:{
+            type:String,
+            default:'#FFFFFF'
+        },
+        ratio:{
+            type: [String, Number],
+            default:0.5
+        }
+    },
+    data() {
+        return {};
+    },
+    methods: {
+    },
+    mounted(){
+        this.$nextTick(()=>{
+            const _vm = this;
+            LuckyCard({
+                scratchDiv:this.$el,
+                coverColor:this.coverColor,
+                coverImg:this.coverImg,
+                ratio:Number(this.ratio),
+                callback:function(){
+                    //console.log(this);
+                    //this.clearCover();
+                    _vm.$emit('open',this);
+                }
+            })
+        })
+    }
+}
+</script>
+<style lang="scss">
+.nut-luckycard{ 
+    position: relative;
+    .nut-cover{ 
+        position:absolute; 
+        top:0; 
+        left:0;
+    }
+    .nut-content{
+        display:flex;
+        align-items: center;
+        justify-content: center;
+        height:100%;
+        width:100%;
+        line-height: 100%;
+        user-select:none;
+    }
+}
+</style>

+ 1 - 0
types/nutui.d.ts

@@ -85,3 +85,4 @@ export declare class CountUp extends UIComponent {}
 export declare class FixedNav extends UIComponent {}
 export declare class Gesture extends UIComponent {}
 export declare class Collapse extends UIComponent {}
+export declare class Luckycard extends UIComponent {}