Опубликовать пакет NPM на основе компонента Vue скретч-карты

Vue.js
Опубликовать пакет NPM на основе компонента Vue скретч-карты

Введение

Модуль скретч-карты должен быть реализован в проекте. Когда проект будет урегулирован после завершения проекта, модуль скретч-карты может быть инкапсулирован. Когда он используется в следующем новом проекте, это может повысить эффективность проекта. , конечно, это также будет более эффективно.Хорошо для использования другими друзьями.

Адрес источника:GitHub.com/Zen G Zoe/vUE…адрес пакета npm:Уууу, эта лошадь plus.com/package/v ue…

Эффект компонента скретч-карты следующий:

Во-вторых, реализация компонента vue скретч-карты.

Реализация функции скретч-карты может быть разделена на три этапа:

1. Построение рабочего процесса

Рабочий процесс используетvue-cliизwebpack-simpleШаблон, может удовлетворить основные компоненты запроса компиляции:

vue init webpack-simple vue-scratch-card

После выполнения введите информацию package.json в соответствии с компонентом.

Use sass? (y/N) y

В проекте здесь я выбираюuse sass.

существуетsrcСоздано в каталогеpackagesкаталог, используемый для хранения всех подкомпонентов, в этом компоненте есть только один компонент скретч-карты, поэтому вpackagesновыйscratch-cardКаталог используется для хранения компонентов наших скретч-карт. Если есть другие подкомпоненты, вы можете продолжитьpackagesДобавьте подкомпоненты, и окончательный каталог выглядит следующим образом:

.
├── README.md
├── index.html
├── node_modules
├── package-lock.json
├── package.json
├── src
│   ├── App.vue
│   ├── assets
│   │   └── logo.png
│   ├── main.js             //组合所有子组件,封装组件
│   ├── main.js             //入口文件
│   └── packages            //用于存放所有的子组件
│       └── scratch-card    //用于存放刮刮卡组件
│           └── scratch-card.vue   //刮刮卡组件代码
└── webpack.config.js

Для поддержки компонентов вы можете использовать теги<script>Путь введения: упакованные файлы, упакованные в компоненты, должны быть только единообразно упакованы как js:

Итак, нам нужно изменить наш файл конфигурацииwebpack.config.js:

//webpack.config.js
 output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'vue-scratch-card.js',
    library : 'vue-scratch-card',  //设置的是使用require时的模块名
    libraryTarget : 'umd',    //libraryTarget可以设置不同的umd代码,可以是commonjs标准、amd标准,也可以生成通过script标签引入的
    umdNamedDefine : true,    //会对UMD的构建过程中的amd模块进行命名,否则就用匿名的define
},

При этом для сохранения упакованногоdistкаталог, который должен быть.gitignoreудалено изdistсодержание.

2. Canvas реализует скретч-карту

Скретч-карты в основномCanvasДля достижения, как правило, скретч-карта сочетается с лотереей, тогда нашаDOMДолжен включать дисплей, показывающий результаты лотереиDOM, структура следующая:

//scratch-card.vue
<template>
    <div :id='elementId' class='scratchCard'>
        <div class="result" v-show='showLucky'>
            <slot name='result'></slot>
            <img :src="resultImg" alt="" class="pic" />
        </div>
        <canvas id='scratchCanvas'></canvas>
    </div>
</template>

Среди них добавление<slot>Слот, чтобы настроить результат лотереи при вызове этого компонентаDOM.

Далее идет логическая часть, реализующая скретч-карту.

Общая структура js выглядит следующим образом:

//scratch-card.vue
    export default {
        name : 'vueScratchCard',
        data(){
            return {
                supportTouch : false,       //是否支持touch事件
                events : [],                //touch事件 or mouse事件合集
                startMoveHandler : null,     //touchstart or mousedown 事件
                moveHandler : null,         //touchmove or mousemove 事件
                endMoveHandler : null,      //touchend or mouseend 事件
                showLucky : false,          //显示隐藏抽奖结果
                firstTouch : true,          //是否第一次touchstart or mousedown
            }
        },
        props : {
            elementId : {   //组件最外层DOM的id属性
                type : String,
                default : 'scratch',
            },
            moveRadius : {  //刮刮范围
                type : Number,
                default : 15
            },
            ratio : {   //要求刮掉的面积占比,达到这个占比后,将会自动把其余区域清除
                type : Number,
                default : 0.3
            },
            startCallback : {   //第一次刮回调函数
                type : Function,
                default : function(){
                }
            },
            clearCallback : {   //达到ratio占比后的回调函数
                type : Function ,
                default : function(){
                }
            },
            coverColor : {  //刮刮卡遮罩颜色
                type : String,
                default : '#C5C5C5'
            },
            coverImg : {    //刮刮卡遮罩图片
                type : String,
            },
            resultImg : {       //中奖的图
                type : String,
                default : 'https://raw.githubusercontent.com/ZENGzoe/imagesCollection/master/2018/default.jpg'
            }
        },
        mounted : function(){
        },
        methods : {
        }
    }

Прежде чем вы начнете писать свою логику, вам нужно рассмотреть настраиваемые свойства компонента, добавив вprops, так что использование компонентов может быть более гибким.

Когда компонент смонтирован в экземпляре, начните инициализировать компонент, нарисуйтеCanvas.

//scratch-card.vue
...

mounted : function(){
    this.$nextTick(() => {
        this.init();
    })
},
methods : function(){
    init : function(){
        if(!this.isSupportCanvas){
            alert('当前浏览器不支持canvas');
            return;
        }
        const canvasWrap = document.getElementById(this.elementId);
        this.canvas =canvasWrap.querySelector('#scratchCanvas');
        this.ctx = this.canvas.getContext('2d');
        this.canvas.width = canvasWrap.clientWidth;
        this.canvas.height = canvasWrap.clientHeight;

        this.createCanvasStyle();
    },
    createCanvasStyle : function(){
        var _this = this;
        //当传入coverImg时,优先使用图片,否则使用颜色作为刮刮卡遮罩
        if(this.coverImg){
            var coverImg = new Image();
            coverImg.src = this.coverImg;
            coverImg.onload = function(){
                _this.ctx.drawImage(coverImg , 0 , 0 , _this.canvas.width , _this.canvas.height);
            }
        }else{
            _this.ctx.fillStyle = _this.coverColor;
            _this.ctx.fillRect(0,0,_this.canvas.width , _this.canvas.height);
        }
    },
}
...

когда необходимоCanvasПри добавлении междоменного изображения вам необходимо преобразовать изображение в base64.

Событие, связанное со страницей ПК,mousesdown,mousemove,mouseup, событие, связанное с мобильной страницей,touchstart,touchmove,touchend, поэтому вам нужно различать привязки событий на разных сторонах.

//scratch-card.vue
...
init : function(){
    ...
    this.bindEvent();
},
bindEvent : function(){
    if('ontouchstart' in window) this.supportTouch = true;
    this.events = this.supportTouch ? ['touchstart', 'touchmove', 'touchend'] : ['mousedown', 'mousemove', 'mouseup'];
    this.addEvent();
},
...

Чтобы уменьшить пространство, привяжите событияaddEventДля конкретной реализации вы можете просмотреть исходный код.

Эффект протирания скретч-картой даетCanvasизglobalCompositeOperationреализация свойства, установкаglobalCompositeOperation = "destination-out"Позвольте вашему пальцу или мыши взаимодействовать сCanvasОбласть перекрытия холста не видна, что позволяет создать эффект скретч-карты. существуетtouchmoveа такжеmousemoveДобавьте эффект очистки к связанному событию. Реализация выглядит следующим образом:

moveEventHandler : function(e){
    e.preventDefault();
    
    e = this.supportTouch ? e.touches[0] : e;

    const canvasPos = this.canvas.getBoundingClientRect(),
          scrollT = document.documentElement.scrollTop || document.body.scrollTop,
          scrollL = document.documentElement.scrollLeft || document.body.scrollLeft,
           //获取鼠标或手指在canvas画布的位置
          mouseX = e.pageX - canvasPos.left - scrollL, 
          mouseY = e.pageY - canvasPos.top - scrollT;

    this.ctx.beginPath();
    this.ctx.fillStyle = '#FFFFFF';
    this.ctx.globalCompositeOperation = "destination-out";
    this.ctx.arc(mouseX, mouseY, this.moveRadius, 0, 2 * Math.PI);
    this.ctx.fill();
},

Каждый раз, когда палец или мышь уходят, вычисляется стертая область, и когда стертая область превышает согласованный процент холста, вся стертая область очищается.Canvasхолст. Вычисление стертой области эквивалентно вычислению того, есть ли данные в пикселях на холсте.getImageDataметод для получения пикселей холста. Конкретная реализация выглядит следующим образом:

caleArea : function(){
    let pixels = this.ctx.getImageData(0,0,this.canvas.width,this.canvas.height),
        transPixels = [];
    
    pixels.data.map((item , i) => {
        const pixel = pixels.data[i+3];
        if(pixel === 0){
            transPixels.push(pixel);
        }
    })

    if(transPixels.length / pixels.data.length > this.ratio){
        this.ctx.clearRect(0,0,this.canvas.width , this.canvas.height);
        this.canvas.removeEventListener(this.events[0],this.startMoveHandler);
        this.canvas.removeEventListener(this.events[1] , this.moveHandler , false);
        document.removeEventListener(this.events[2] , this.endMoveHandler , false);

        this.clearCallback();
    }
}

Каждый раз, когда палец или мышь уходит, чтобы не загрязнять события других областей и не занимать контент, связанные события должны быть очищены.

Тогда вся логика скретч-карты здесь реализована, и следующим шагом будет инкапсуляция компонента скретч-карты в плагин.

3. Упакован в виде плагина

Чтобы инкапсулировать компонент Vue в виде плагина, должен быть общедоступныйinstallметод, так что черезVue.use()Вызов плагина. Для получения дополнительной информации см. VUEофициальная документация.

существуетscratch-cardновый в каталогеindex.js, используется для инкапсуляцииscratchCardизinstallметод:

//scratch-card/index.js
import vueScratchCard from './scratch-card'

vueScratchCard.install = Vue => Vue.component(vueScratchCard.name , vueScratchCard);

if(typeof window !== 'undefined' && window.Vue){
    window.Vue.use(vueScratchCard);
}

export default vueScratchCard;

Здесь мы упаковали нашу скретч-карту подкомпонента, если есть другие подкомпоненты, вы можете продолжитьpackagesкаталог и, наконец, вsrcновый каталогindex.js, который объединяет все подкомпоненты.

//src/index.js

import VueScratchCard from './packages/scratch-card/index.js';

const install = function(Vue , opts = {}){
    Vue.component(VueScratchCard.name , VueScratchCard);
}

//支持使用标签<script>的方式引入
if(typeof window !== 'undefined' && window.Vue){
    install(window.Vue);
}

export default {
    install ,
    VueScratchCard
}

На этом наш компонент завершен.

3. Опубликовать в нпм

Опубликовать вnpmперед этим нужно изменитьpackage.json,настраивать"private":true,иначеnpmОткажется публиковать приватные пакеты. Кроме того, вам нужно добавить файл ввода,"main":"dist/vue-scratch-card.js", можно использовать, когдаrequireилиimportМодули загружаются при упаковке пакетов.

//package.json
  "private": false,
  "main" : "dist/vue-scratch-card.js",

Процесс выпуска npm выглядит следующим образом:

1. ВnpmЗарегистрировать аккаунт

2. Чтобы войти в npm, вам нужно изменить адрес зеркала на npm

npm login

3. Добавьте информацию о пользователе и введите пароль учетной записи.

npm adduser

4. Опубликовать

npm publish 

После успешного выпуска вы можетеnpmПоиск опубликованных пакетов.

В-четвертых, установите и используйте пакет

После этого мы можем установить и использовать его напрямую~~

Установить:

npm install vue-scratch-card0 -S 

использовать:

1. Использование по импорту

import ScratchCard from 'vue-scratch-card0'
Vue.use(ScratchCard)

<vue-scratch-card 
    element-id='scratchWrap'
    :ratio=0.5
    :move-radius=50
/>

2. Через теги<script>Цитировать

<vue-scratch-card 
    element-id='scratchWrap'
    :ratio=0.5
    :move-radius=50
    :start-callback=startCallback
    :clear-callback=clearCallback
    cover-color='#caa'
  />

<script src="./node_modules/vue/dist/vue.js"></script>
<script>
    new Vue({
      el : '#app',
      data () {
        return {

        }
      },
      methods : {
        startCallback(){
          console.log('抽奖成功!')
        },
        clearCallback(){
          console.log('清除完毕!')
        }
      }
    })
</script>

V. Резюме

При публикации пакета npm он продолжает запрашиватьPackage name too similar to existing packages, но на официальном сайте npm пакет с таким названием не был найден, и в это время он то и дело менялся.package.jsonИмя в , наконец, успешно выпущено, это непросто~_~