Весь процесс рисования плакатов на холсте апплета "Рекомендуемая коллекция"

Апплет WeChat
Весь процесс рисования плакатов на холсте апплета "Рекомендуемая коллекция"

Далее я будуPure front-end реализует весь процесс создания плакатовЯ расскажу вам ясную и ясную идею.Я поделюсь и подробно объясню ямы, с которыми я столкнулся, чтобы вы не столкнулись с подобными проблемами.Даже если вы столкнетесь с проблемами, будет четкое направление, и рекомендуется, чтобы вы вырвали кровь.собиратьВолна, на крайний случай. (Вы не можете гарантировать будущие потребности, подобного нет, если есть, не забудьте поискать)

Дорога длинная, кто-то должен осмелиться сделать первый шаг в яме, я думаю, что я тот самый 😂😂, надеюсь, каждый сможет ступить на яму, которую я заполнил, рискуя таскать скорую помощь, ведущую к победе мини программа генерации плакатов дорога. Дарите розы, оставьте аромат в руке, друзья, которые читают, могут подарить авторуНравится, следуй за волнойОбновляйте суперсухие, суперхардкорные фронтенд статьи одну за другой.

одно написано впереди

1 Плакаты для рисования на холсте с QR-кодами. Всегда есть одна из этих ям, на которую вы можете наступить. Я проведу вас шаг за шагом, чтобы решить эти ямы

Предыстория технического отбора:taro3.0-vue

Начнем с одиннадцати вопросов.Я думаю, что в процессе рисования плакатов вы обязательно столкнетесь

Яма, с которой столкнулась структура Таро

① taro-vue createCanvasContext Недопустимая проблема с получением экземпляра холста, не удается отрисовать эффект? ✅

② Что я должен сделать, если Taro-Vue не может получить контекст холста во время инициализации и не могу нарисовать картинки вообще? ✅

Яма, с которой столкнулся холст апплета

③ Что касается ширины и высоты холста и коэффициента масштабирования, нарисованные элементы деформируются.Действительно ли высота холста равна ширине и высоте, установленным тегом cavans? ✅

④ Как холст рисует две сложенные вместе картинки и управляет уровнем? ✅

⑤ Как рисовать на холсте многострочный текст? ✅

⑥ Как точно восстановить положение каждого элемента плаката согласно дизайн-проекту. ✅

⑦ Как рисовать изображения base64 на холсте ✅

⑧ как нарисовать картинку сети два холста холст апи, нарисовать картинку В чем разница для завершения ✅

Создайте яму, обнаруженную QR-кодом

⑨ Как правильно выбрать и сгенерировать инструмент QR-кода? ✅

⑩ Что делать, если сгенерированный QR-код не распознается, ✅

⑪ Как нарисовать логотип на QR-коде✅

2 Достичь эффекта

2. Первый этап реального боя 1: инициализация холста апплета

1 Два способа для cavnas получить контекст

Проблемы, которые мы собираемся решить

① taro-vue createCanvasContext Недопустимая проблема с получением экземпляра холста, не удается отрисовать эффект?

② Что делать, если taro-vue не может получить контекст холста во время инициализации?

Официальный сайт WeChat представляет дваcanvasПолучить контекст, один старыйapi , один новыйapi, далее я объясню дваapiПрименение.

Метод createCanvasContext старой версии

createCanvasContextЭто приобретение, предоставленное WeChatcanvasСтарый интерфейс экземпляра используется следующим образом.

wxml

<canvas style="width: 300px; height: 200px;" canvas-id="firstCanvas"></canvas>

добрый день от написанияhello,worldНачинать.

js пишется так

onReady(){
    /*  使用 wx.createContext 获取绘图上下文 context , firstCanvas 与 canvas 属性中的canvas-id一一对应  */
    const context = wx.createCanvasContext('firstCanvas')
    /* 设置字体大小 */
    context.setFontSize(20) 
    /* 设置字体颜色 */
    context.setFillStyle('pink')
    /* 设置文本内容,位置 */
    context.fillText('hello,world', 0, 0)
    context.draw()
}

В старой версии использовалосьcreateCanvasContextвходящийcanvasна этикеткеcanvas-idсвойства, чтобы получитьcanvasПример, старая версия используется, если честно, недостаточно гибкая, много парcanvasПараметры линии и цвета инкапсулированы в методы, и методы необходимо вызывать каждый раз при их изменении.

Новая версия контекстально GetContext

Новый способ - сначала пройтиcreateSelectorQueryПолучатьcanvasузел элемента, затем черезgetContextПолучить контекст.

wxml

 <canvas type="2d" id="myCanvas"></canvas>

js

const query = wx.createSelectorQuery()
query.select('#myCanvas')
.fields({
    node: true,
    size: true
})
.exec((res)=>{
    const { node } = res[0]
    if (!node) return
    /* 获取 canvas 实例 */
    const context = node.getContext('2d')
    context.fillStyle = 'pink'
    /* 设置字体样式 大小 字体类别 */
    context.font = 'normal 400 12px PingFangSC-Regular',
    context.fillText('hello,world', 0, 0)
})

таким образом и первыйcreateSelectorQueryметод, будут тонкие различия в том, как используется API, это письмо больше похоже на нативныйDOMНаписание, установка цвета, стиля, прямое изменениеcontextсвойства вместо вызова соответствующегоapi.

таро-вью использует холст

Решите проблему: ① taro-vue createCanvasContext недействителен для получения экземпляра холста, и эффект не может быть отрисован?

Поскольку наш выбор технологии апплетаtaro-vue2, поэтому я сосредоточусь здесь наВ настоящее время в taro-vue createCanvasContext используется для получения экземпляров холста, и отрисовка холста никогда не была успешной.Даже если createCanvasContext может создавать контексты, ничего не может быть отрисовано (такие проходящие схемы пробовали снова и снова). Если вы спросите меня, почему? На самом деле, я тоже не знаю. Только студенты Bump Lab должны знать лучше. На GitHub также есть проблемы. Надеюсь, команда таро отнесется к этому серьезно.

Решение состоит в том, чтобы использовать последнююapi, что является вторым решением, упомянутым выше. код показывает, как показано ниже:

import Taro  from '@tarojs/taro'
const query = Taro.createSelectorQuery()
query.select('#myCanvas')
.fields({
    node: true,
    size: true
})
.exec(res=>{
    //TODO:....
})

② Что делать, если taro-vue не может получить контекст холста во время инициализации?

В использованииtaro-vueВ процессе будет проблема, то есть проблема в том, что узел node апплета не может быть получен, это может быть вызвано жизненным циклом самого апплета и хаосом жизненного цикла vue. Особенно когда мы выбираем компоненты вместо страниц. Для таких случаев официальная документация дает ответ. Выполняется при первом отображении страницы.Этот жизненный цикл соответствует жизненному циклу onReady страницы апплета на стороне апплета. Начиная с этого жизненного цикла, доступ к реальному DOM можно получить с помощью таких API, как createCanvasContext или createselectorquery.

То есть, если вы хотите получитьdomузел, мы можем сделать это,

компонент

mounted () {
    eventCenter.once(getCurrentInstance().router.onReady, () => {
       const query = Taro.createSelectorQuery()
        query.select('#myCanvas')
        .fields({
           node: true,
           size: true
        })
        .exec(res=>{
        //TODO:....
        })         
    })
}

К сожалению, эта ситуация иногда вызываетeventCenter.once()Когда функция обратного вызова не выполняется, например, текущий компонент получаетv-ifситуацию контролировать. Итак, как это решить, для этой ситуации я учу вас решению.

мы можем использоватьtaroв, черезTaro.nextTickметод, поставить задачу получить элемент в следующий разnextTickвоплощать в жизнь.

mounted(){
  Taro.nextTick(() => {
      // 获取元素
  })   
}

2 ИнициализироватьcanvasУстановить ширину и высоту в процентах

Проблемы, которые мы собираемся решить:

③ Что касается ширины и высоты холста и коэффициента масштабирования, нарисованные элементы деформируются.Действительно ли высота холста равна ширине и высоте, установленным тегом cavans?

<template>
    <view>
        <canvas
            id="myPoster"
            type="2d"
            class="canves"
            :style="canvasStyle"
        />
    </view>
</<template>

Здесь мы должны сначала понять два понятия,Ширина и высота контейнера: мы даемcanvasШирина и высота настройки метки такие же, как в приведенном выше коде.canvasStyle,ДаcanvasШирина и высота контейнера.Ширина и высота холста: И ширина и высота нашего холста, в новой версииapi, получивnodeУзел, динамически устанавливаемыйnode.widthа такжеnode.heightценность .

В качестве холста мы рассчитываем использовать весь экран, для разных мобильных телефонов размер экрана будет разным, поэтому нам нужно динамически получать ширину и высоту устройства. Здесь есть проблемаШирина и высота контейнера равны ширине и высоте холста?, ответ нет, почему вы так говорите, причины следующиеcanvasХолст имеет примитивШирина и высота холста, и коэффициент масштабирования, и это с точки зрения одного пикселя, когда мы даемcanvasнастройки контейнераШирина и высота контейнераПосле этого, если нет соответствующей настройкиcanvasхолстШирина и высота холстатак же какscale, нарисованный холст будет серьезно деформирован, поясняем на примере.

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

Ожидаемый результат состоит в том, что холст заполняет экран, а изображения отображаются в нормальных пропорциях. когда мы не даемcavnasНастройки холстаШирина и высота холстаИ при коэффициенте масштабирования. Происходит следующее.

фактический эффект:

Итак, когда мы инициализируем, нам нужно датьcanvasСделайте следующее. Об этом говорится в официальных документах WeChat.

import Taro, {
    eventCenter,
    getCurrentInstance
} from '@tarojs/taro'

export default {
    
    name:'myPoster',
    data(){
        const {
            windowHeight,
            windowWidth,
            pixelRatio
        } = Taro.getSystemInfoSync() /* 动态获取设备的宽和高  */
       return {
            canvasStyle: {           /* cavnas 的宽高 */
                width: windowWidth + 'px',
                height: windowHeight + 'px',
            },
            windowWidth,
            pixelRatio,   /* 屏幕缩放比 */
            windowHeight,
            scale:1       
       }
    },
    mounted(){
        Taro.nextTick(() => {
            const query = Taro.createSelectorQuery()
            query.select('#myPoster').fields({
                node: true,
                size: true
            }).exec(res => {
                let {
                    node,
                } = res[0]
                if (!node) return
                 /* 第一步: canvas 画布的宽高 和 元素的宽高 必须保持相同的长宽比列,否则会变形 */
                const dpr = this.pixelRatio
                const context = node.getContext('2d')
                node.width = windowWidth * dpr
                node.height = windowHeight * dpr
                context.scale(dpr, dpr)
                context.fillStyle = '#fff'
                context.fillRect(0, 0, windowWidth, windowHeight)
            })
        })
    }
}

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

Далее этап рисования.

3 Второй этап реального боя: этап рисования холста виртуальной точки

объяснениеcanvasПеред тем, как сгенерировать плакат и идеально восстановить дизайн-проект, следует задуматься над вопросом, ведьcanvasХолст, не в конце концовdomмодель, вы можете использоватьdivилиview, путем пользовательской настройки стиля макета.cavnasНам нужно нарисовать эффект макета элементов.Здесь нам нужно точно получить значения x и y каждого элемента на холсте относительно холста. Итак, первое, что приходит на ум, это как получить точное значение x, y каждого элемента.

1 Виртуальная точка восстанавливает фактический эскиз проекта

Решать проблему:⑥ Как точно восстановить положение каждого элемента плаката согласно дизайн-проекту.Для задачи идеально восстановить осадку конструкции более надежное решение – нормально навесить в пропорции 1:1.domэлемент, а затем нарисуйте его, получив позицию элементаcanvasПозиция элемента холста. Мы используем картинку, чтобы проиллюстрировать принцип.

Меры предосторожности

Примечание 1: выберите правильный элемент, чтобы получить точку

Вот аналогия, мы находимся вdomТакая структура может существовать внутри элемента.

<view class="box" >
    <view class="parent" >
        <view class="son" > 这里是将要绘制到canvas中的内容。 </view>
    </view>
</view>

Для приведенной выше структуры нам нужно толькоsonСодержание в обращается кcanvasВ канве тогда возникает проблема, какой уровень информации об элементе мы хотим получить (left,top,width,height), ответ должен быть в состоянии угадать, это должен быть ближайший слой контента, который вы хотите нарисовать, то есть поверхностьsonуровень. Если мы выберем внешний слой, мы можем получить родительский элементpadding,marginи другие воздействия, приводящие к неточному реальному местоположению.

Примечание 2. Старайтесь не добавлять элементы для получения информации.padding marign, если рисуете текстовое содержимое, попробуйте сделать высоту контейнера равной высоте текста

Также есть проблема, то есть старайтесь не добавлять больше элементов к элементам, которые нужно нарисовать.padding marignи другие свойства, если вы рисуете простой текст, не устанавливайтеlineHeight, Как показано в примере:

Мы ожидаем получитьaИнформация о местоположении точки, но в конечном итоге получитьbинформация о местоположении точки. Если вы используетеbуказать, чтобы нарисоватьcanvas, идеально восстановить проектный чертеж не получится, поэтому рисуем таким образомcanvasследует обратить внимание на эти детали.

Инкапсулировать метод получения информации о местоположении

Нам нужно нарисовать каждую точку на плакате.Первое, что приходит в голову, это получить метод положения элемента апплета и инкапсулировать метод. мы используемpromiseЧтобы предотвратить глубокие обратные вызовы и прост в использованииasync awaitСинтаксический сахар. Не много чепухи, ни слова о коде.

    /* 获取元素位置 */
    geDomPostion(dom, isAll) {
        return new Promise((resolve) => {
            Taro.createSelectorQuery().select(dom).boundingClientRect(rect => {
                const {
                    top,
                    left
                } = rect
                /* isAll 是否获取设备宽高等信息 */
                resolve(isAll ? rect : {
                    top,
                    left
                })
            }).exec()
        })
    },

намекать: при использованииwxНативные или другие межсетевые фреймворкиmpvue wepy uniappда одноклассник, поставьTaroзаменитьwxВот и все.

2 Рисование сетевых картинок

рисовать веб-картинки

Следующая задача, которую нам предстоит решить:⑨ Как рисовать изображения по сети, в чем разница между двумя способами рисования изображений через API холста?

мы используемcanvasПри рисовании изображения вы можете напрямую передать локальное изображениеcanvasкоторый предоставилdrawImageЧтобы рисовать, а для сети картинки так рисовать нельзя, нам сначала нужно пройтиgetImageInfoчтобы получить временный путь к изображению. использоватьgetImageInfoПри отрисовке сетевых ресурсов обратите внимание на настройку легального доменного имени загрузки, иначе мы не сможем успешно получить информацию об изображении. Сначала нам нужно настроить апплет в фоновом режимеdownloadFileзаконное доменное имя.

Конкретные шаги заключаются в следующем: первый шаг:

Шаг 2:

третий шаг:

Следующее, что нам нужно сделать, это прочитать временный путь изображения и нарисовать его вcanvasПодойдет холст.

 /* backGroundImageUrl 是我们要画的网络图片的地址  */
 this.getImageInfo(this.backGroundImageUrl).then(res=>{
      const {
        width,   /* 宽度 */
        height,  
        path     /* 临时路径 */
      } = res1
      /* 第二步: 绘制banner图 */
    const bannerImage = await this.geDomPostion('#bannerImage')
    this.startTop = bannerImage.top - 30
    this.drawImage(context, node, path, 0, 0, width, height, 0, this.startTop, windowWidth, windowWidth)
    context.save()
 })

this.drawImageЭто наш инкапсулированный метод.Как упоминалось ранее, для получения апплетаcontextДва способа интерфейса, два способа рисованияcanvasКартинки, есть некоторые отличия, сразу скажем.

Разница между новым и старым интерфейсом

Метод рисования старой версии

старая версия APIcreateCanvasContextможно использовать напрямуюdrawImageРисовать картинки. следующим образом

/* 绘制图片 */
context.drawImage(url,x,y,width,height,dx,dy,dwidth,dheight)

В то время наш проект использовал второй новый API.getContextВ то время был получен контекст, поэтому способ рисования изображения будет изменен.

Метод рисования новой версии

  const image = node.createImage()
  image.src = url
  image.onload = () => {
    context.drawImage(image,x,y,width,height,dx,dy,dwidth,dheight)
  }

Учащиеся, использующие новую версию API для рисования изображений, обратите внимание, что этоonloadОбратный вызов выполняется при загрузке изображения, поэтому описаниеАсинхронный. Есть еще один момент, на который следует обратить внимание по сравнению со старой версией.drawImageПервый параметр — это путь к образу, а новая версияdrawImageПервый параметрimageэлемент.

Инкапсулировать метод рисования изображений

Только что на последнем шаге рисования сетевой картинки мы назвалиthis.drawImageметод. Потому что в течение всего процесса генерации плаката внутри будет отрисовываться несколько картинок, поэтому мы инкапсулируем метод для отрисовки картинок по отдельности.

/* 绘制图片 */
drawImage(context, node, url, ...arg) {
    return new Promise((resolve) => {
        const image = node.createImage()
        image.src = url
        image.onload = () => {
            context.drawImage(image, ...arg)
            resolve()
        }
    })
},

Так что мы можем пройти,async,awaitОпределите, загружено ли изображение.

Введение context.drawImage

Я кратко познакомлю вас здесьcontext.drawImageПрименение,

CanvasContext.drawImage(imageResource / dom, sx,  sy,  sWidth,  sHeight,  dx,  dy,  dWidth,  dHeight)

Нарисуйте изображение на холсте, первый параметр представляет собой путь в старом API и представляет новую версию API.imagDomэлемент,

sxнужно нарисовать на холсте,imageResource / domверхняя левая координата x прямоугольного (обрезанного) поля выбора

syнужно нарисовать на холсте,imageResource / domY-координата левого верхнего угла прямоугольного (обрезанного) поля выбора.

sWidthнужно нарисовать на холсте,imageResource / domширина прямоугольного (обрезанного) поля выбора

sHeightнужно нарисовать на холсте,imageResource / domвысота прямоугольного (обрезанного) поля выбора

dxПоложение верхнего левого угла imageResource по оси x целевого холста.

dyПоложение верхнего левого угла imageResource по оси Y целевого холста.

dWidthШирина нарисованного imageResource на целевом холсте, позволяющая масштабировать нарисованный imageResource.

dHeightВысота нарисованного imageResource на целевом холсте, позволяющая масштабировать нарисованный imageResource.

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

3 Рисование многослойных картинок

Решать проблему:④ Как холст рисует две сложенные вместе картинки и управляет уровнем?

Если мы нарисуем две картинки, сложенные друг на друга, какую работу нам нужно сделать? Первое, что приходит к уму, это проблема уровня. Мы ожидаем, что фоновое изображение будет размещено ниже, например, такие изображения, как аватары, размещены на вершине, но в холсте нет контроля.zIndexИерархические свойства, так как решить эту проблему? Ответ на самом делеcanvasв, нарисованопоследовательностьЭто порядок иерархии холста, верхний слой, который рисуется позже, рисуется первым, затем для такого рода иерархической задачи нам нужно только обеспечить, чтобы элементы с более высокими уровнями рисовались позже, а элементы с более низкими уровнями. Сначала нарисуйте, что можно отлично решить.Далее, в плакате, нарисуйте картинки, текст и другую информацию.

<!-- 头像区 -->
<image  class="userheadImage"  id="userheadImage"  :src="headImage"  />

    /*TODO: 绘制头像 */
    const userheadImage = await this.geDomPostion('#userheadImage',true)
    /* 圆形图片 */
    let d = userheadImage.height / 2
    const cx = userheadImage.left + userheadImage.width / 2
    let cy = userheadImage.top + userheadImage.height / 2
    context.arc(cx, cy, d, 0, 2 * Math.PI)
    context.strokeStyle = '#FFFFFF'
    context.stroke()
    context.clip()
    await this.drawImage(context, node, this.headImage, userheadImage.left, userheadImage.top, userheadImage.width, userheadImage.height)
    context.restore()
    this.drawText(context,{ top: userheadImage.top + userheadImage.height + 40 ,left : userheadImage.left - 70 },'我不是外星人「前端Sharing」',18,'normal 600 20px PingFangSC-Regular','#fff')

в нашем использованииcontext.clip()После этого не забудьте использоватьcontext.restore()Сбросить, иначе никакие другие элементы не будут отрисовываться.

Эффект:

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

4 Рисование многострочного текста

Решать проблему:⑤ Как рисовать на холсте многострочный текст?

canvasнарисованный текст, не похожий на нашdomКак и текст под элементом, он может автоматически переноситься, как восстановить эффект многострочного текста? Вот способ научить вас,Мы можем рисовать слово за словомcanvas, а затем добавьте ширину каждого слова. Если общая ширина больше ширины контейнера, начните новую строку, увеличьте высоту каждой строки и начните с начала., переходим непосредственно к коду.

       /** 画多行文本
         * @param ctx          canvas 上下文
         * @param str          多行文本
         * @param initHeight   容器初始 top值
         * @param initWidth    容器初始 left值
         * @param canvasWidth  容器宽度
         */
        drawRanksTexts(ctx, str, initHeight, initWidth, canvasWidth) {
            let lineWidth = 0;
            let lastSubStrIndex = 0;
            /* 设置文字样式 */
            ctx.fillStyle = "#303133"
            ctx.font = 'normal 400 15px  PingFangSC-Regular'
            for (let i = 0; i < str.length; i++) {
                lineWidth += ctx.measureText(str[i]).width
                if (lineWidth > canvasWidth) { /* 换行 */
                    ctx.fillText(str.substring(lastSubStrIndex, i), initWidth, initHeight)
                    initHeight += 20
                    lineWidth = 0
                    lastSubStrIndex = i
                }
                if (i == str.length - 1) {  /* 无需换行 */
                    ctx.fillText(str.substring(lastSubStrIndex, i + 1), initWidth, initHeight)
                }
            }

        },

передача

/* TODO: 复制多行文本 */
const rowsText = await this.geDomPostion('#context', true)
this.drawRanksTexts(context, this.skuName, rowsText.top, rowsText.left, rowsText.width)

Эффект

4. Третий этап реального боя: Генерация QR-кода

Следующее что делаем рисуем QR код, процесс рисования QR кода автор наступил на много ям, особенноtaro-vueне поддерживаетсяcreateCanvasContextЯ надеюсь, что смогу использовать яму, на которую я ступил, чтобы позволить всем избежать тех же ошибок и избежать многих окольных путей. Рисование двумерного кода на самом деле не так сложно, как можно себе представить.На самом деле, это преобразование ссылки в двумерный код, чтобы мобильный телефон мог сканировать код или долго нажимать, чтобы распознать его.Хотя принцип очень просто, есть еще много деталей, на которые нужно обратить внимание.

Нанесение QR-кода ничем не отличается от двух способов,Первый способ заключается в использованииcanvasНарисуй это. Второй преобразует ссылку вbase64, затем позвольте изображению показать ссылку.Далее проведем технический подбор библиотеки двумерного кода для этих двух методов.

1 О выборе библиотеки QR-кодов

Решать проблему⑨ Как правильно выбрать и сгенерировать инструмент QR-кода?

В процессе формирования QR-кода мы не должны использовать алгоритм вручную, потому что даже если мы сможем сделать это вручную, это займет много времени, и будет многоbug, потому что сейчас экология генерации QR-кодов очень здоровая, напримерqrcode.jsИ так все очень хорошо, но плохо только то, что апплет не поддерживается. Здесь я представляю несколько библиотек QR-кода

weapp-qrcode

Например, для коротких ссылок, например, GitHub автора.GitHub.com/удачи Али…или Дом НаггетсТалант /user/241858…Такого рода все относятся к коротким ссылкам, вам не нужно писать очень длинные параметры, в этом случае используйтеweapp-qrcodeБолее, чем достаточно. Этот метод основан на первомcanvasнарисовано. И он использует старую версию API, поэтому есть проблема, если вы используете новую версию.getContextобразом, вам нужно загрузить исходный код, а затем изменить исходный код, чтобы он поддерживалgetContextСюда. Давайте представим weapp-qrcodeиспользование.

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

//  将 dist 目录下,weapp.qrcode.esm.js 复制到项目目录中  如果用 taro uniapp 等框架 ,可以用  npm install 
import drawQrcode from '../../utils/weapp.qrcode.esm.js'

drawQrcode({
  width: 200,
  height: 200,
  canvasId: 'myQrcode',
  // ctx: wx.createCanvasContext('myQrcode'),
  text: 'https://juejin.cn/user/2418581313687390',
  // v1.0.0+版本支持在二维码上绘制图片
  image: {
    imageResource: '../../images/icon.png',
    dx: 70,
    dy: 70,
    dWidth: 60,
    dHeight: 60
  }
})

результат

Таким образом, это, наконец, удалось, потому что выполнениеdemo, Я используюgithubКороткая ссылка. Но как только я вернулся к проекту компании автора, ссылка была очень длинной, а сгенерированный QR-код был настолько плотным, что мобильник вообще не мог его распознать, мне ничего не оставалось, как перейти на другие технические решения, поэтому автор выбрал второй, более устойчивый путь, для формированияbase64документ.

qrcode-base64

qrcode-base64это преобразовать ссылку QR-код вbase64Ссылка и эта ссылка какsrcСвойство присваивается изображению. Давайте сначала представим основное использование.

скачать

npm install qrcode-base64

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

import QR from 'qrcode-base64'

var imgData = QR.drawImg(this.data.codeText, {
    typeNumber: 4,
    errorCorrectLevel: 'M',
    size: 500
})
// 返回输出base64编码imgData

Как показано в приведенном выше блоке кода,imgDataгенерируетсяbase64ссылка, мы можем напрямую использовать ее как изображениеsrc, тогда пустьcanvasРисуем картинку в наш постер, но есть другая проблема,canvasне поддерживает рисованиеbase64Ссылка на изображение не влияет на реальную машину, за один шаг есть десять ям, мы должны найти способ решить эту проблему.

2 изображения на холсте base64

Решать проблему⑦ Как рисовать изображения base64 на холсте

для вышеупомянутогоcanvasне поддерживаетсяbase64изображение, то нам также нужно нарисовать QR-код на плакате, так что это не невозможно, мы можем использовать файловую систему, предоставляемую апплетом, для решения проблемы.

файловая система апплета

wx.getFileSystemManagerПолучить глобально уникальный файловый менеджер, возвращаемое значение похоже наnodeв фс.

writeFileЗаписывайте файлы, вы можете записывать картинки в систему.

const fs = wx.getFileSystemManager()

fs.writeFile(/* 写入文件 */)

Способ упаковки

Инкапсулировать метод рисования QR-кода

  /* 生成二维码 */
        drawCode(ctx, node, x, y) {
            return new Promise((resolve) => {
                const codeImageWidth = 150   /* 绘制二维码宽度 */
                const canvasImageWidth = 85 /* 二维码绘制到canvas的宽度 */
                const left = x - 15          /* left 值 */
                const top = y - 22           /* top 值 */
                const LogoWidth = 15       /* 二维码logo宽度 */
                const url = 'https://juejin.cn/user/2418581313687390'
                
                const base64 = QR.drawImg(url, {
                    typeNumber: 4,
                    errorCorrectLevel: 'L',
                    size: codeImageWidth
                })
                /* 创建读写流 */
                const fs = Taro.getFileSystemManager()
                const times = new Date().getTime()
                const codeimg = Taro.env.USER_DATA_PATH + '/' + times + '.png'

                /* 将base64图片写入 */
                fs.writeFile({
                    filePath: codeimg,
                    data: base64.slice(22),  /* 数据流 */
                    encoding: 'base64',      
                    success: async () => {
                        const offset = (canvasImageWidth - LogoWidth) / 2 /* 偏移量 */
                         /* 绘制图片 */
                        await this.drawImage(ctx, node, codeimg, 0, 0, codeImageWidth, codeImageWidth, left, top, canvasImageWidth, canvasImageWidth)
                        await this.drawImage(ctx, node, this.logoUrl, left + offset, top + offset, LogoWidth, LogoWidth)
                        resolve()

                    }
                })
            })

        },

Как показано выше, мы завершили отрисовку QR-кода. Давайте посмотрим, как его использовать.

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

мы вwxmlНапишите на нем элемент в качестве заполнителя, чтобы мы могли получить расположение QR-кода.

<view id="qrCode" class="store-uscode" />
/*TODO: 第四步:绘制二维码 */
const qrCode = await this.geDomPostion('#qrCode')
await this.drawCode(context, node, qrCode.left - 20, qrCode.top - this.cavnsOffsetop)

Эффект

Сканирование прошло успешно

3 Отладка размера QR-кода, как сделать QR-код узнаваемым и нарисовать логотип QR-кода

Решать проблему:⑩ Что делать, если сгенерированный QR-код не распознается.

Иногда, когда QR-код, который мы показываем, относительно мал, из-за того, что цветные блоки слишком плотные, мобильный телефон не сможет его распознать. тогда мыКак настроить QR-код, чтобы страница максимально точно восстанавливала эскиз дизайна?, вот небольшая хитрость для вас, вы можете сначала перейти на веб-сайт генерации QR-кода, сначала адаптироваться к наилучшему соотношению, которое может распознать мобильный телефон, и избежать ситуации, которая не может быть распознана. Рекомендуемый веб-сайт:Кормовой QR-код: https://cli.im/Мы можем отладить пиксели QR-кода и размер логотипа онлайн, пока не будет настроен оптимальный размер дизайна.

Настройте QR-код онлайн

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

const codeImageWidth = 150   /* 绘制二维码宽度 */
const canvasImageWidth = 85  /* 二维码绘制到canvas的宽度 */
const left = x - 15          /* left 值 */
const top = y - 22           /* top 值 */
const LogoWidth = 15         /* 二维码logo宽度 */

const offset = (canvasImageWidth - LogoWidth) / 2 /* 偏移量 */

4 Когда все будет готово, сгенерируйте постер и отправьте его друзьям

Мы запустили весь процесс. Последним шагом является создание изображения плаката и пересылка изображения. Вы можете использовать апплет WeChat для создания плакатовcanvasсерединаcanvasToTempFilePathСоздайте путь к изображению, а затем передайтеpreviewImageМетод просмотра изображений, при просмотре изображений вы можете активировать функцию обмена друзьями апплета WeChat. Здесь есть одна вещь, на которую мы должны обратить внимание, это перехватcanvasЭффективная высота.

Над кодом:

/* 生成海报 */
makePc(node) {
    const {
        startTop,    /* 截取canvas画布的顶部 */
        endTop,      /* 截取canvas画布的底部 */
        windowWidth  /* 屏幕宽度 */
    } = this
    const _this = this
    Taro.canvasToTempFilePath({
        x: 0,
        y: startTop,
        width: windowWidth,
        height: endTop - startTop,
        destWidth: windowWidth * 3,
        destHeight: (endTop - startTop) * 3,
        canvas: node,
        success: function (res) {
            Taro.hideLoading()
            Taro.previewImage({
                urls: [res.tempFilePath]
            })

        }
    })
}

CanvasToTempFilePath соображения

Или вернуться к исходному вопросу, при звонкеcanvasToTempFilePathПри вызове метода параметры, передаваемые старым и новым API, различаются.

В старых версиях API черезcreateCanvasContextРисунокcanvas,canvasToTempFilePathсвойства конфигурацииcanvas, документация для разработчиков WeChat объясняет это такcanvasИдентификатор холста, переданныйcanvasЭкземпляр компонента (используйте это свойство, когда тип холста = "2d"), т. е.canvasконтекстcontext.

Но мы используем новую версию,getContextспособ рисованияcanvas, когда мы переходим вcontext, не влияет, что?Есть такая штука, проблема с документацией разработчика WeChat? Позднее было обнаружено, что таким образом поступающий query.selectприобретенныйcanvasизnodeУзлы действительно много ям~~~. Выйдет глоток старой крови.

5 Обзор эффектов

5 Резюме

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

адрес проекта

Выкладываю весь процесс создания плакатаdemoпроект, загрузитьgithub, Заинтересованные студенты, можете посмотреть, особенно те, кто выполняет эту функцию, приходите~

Адрес проекта, пожалуйста, нажмите здесь

новый год

В новом году я желаю вам удачи в новом году и желаю, чтобы сообщество Nuggets становилось все лучше и лучше.