Проект разработан на основе фреймворка Wafer2. Бэкэнд использует Node.js SDK, предоставленный Tencent Cloud, для доступа к API хранилища объектов. Код ядра интерфейса реализует функцию редактора изображений и поддерживает перемещение, вращение и масштабирование. , генерация предварительного просмотра и редактирование изображений и текста. Состояние сохраняется, а анимационная часть реализуется с помощью CSS-анимации.
Модальное поле ввода в апплете представляет собой отдельно упакованный компонент InputBox.
Конфиденциальная информация, такая как AppId, была удалена из кода. Вы можете добавить свои собственные AppId и AppSecret, чтобы настроить фоновую среду и реализовать тестирование входа. Подробные методы добавления см. в разделе «Использование» ниже. Если вы запускаете его локально, вы можете изменить его. поле page
в файле app.json
. Просмотрите разные страницы по порядку.
git clone https://github.com/yeliudev/LemonJournal.git
LemonJournal
в инструментах разработчика WeChat. appid
файла project.config.json
/client/utils/util.js
<image>
(соответствующий изображению) и тег <text>
(соответствующий тексту) в одном пользовательском компоненте <sticker>
и выполнить условный рендеринг в зависимости от того, пуста ли открытая text
переменная. , а затем свяжите его с тремя событиями onTouchStart()
, onTouchEnd()
и onTouchMove()
для управления положением, углом, размером, уровнем всего компонента, а также поведением кнопок «поворот» и «удаление». onTouchStart: function ( e ) {
// 若未选中则直接返回
if ( ! this . data . selected ) {
return
}
switch ( e . target . id ) {
case 'sticker' : {
this . touch_target = e . target . id
this . start_x = e . touches [ 0 ] . clientX * 2
this . start_y = e . touches [ 0 ] . clientY * 2
break
}
case 'handle' : {
// 隐藏移除按钮
this . setData ( {
hideRemove : true
} )
this . touch_target = e . target . id
this . start_x = e . touches [ 0 ] . clientX * 2
this . start_y = e . touches [ 0 ] . clientY * 2
this . sticker_center_x = this . data . stickerCenterX ;
this . sticker_center_y = this . data . stickerCenterY ;
this . remove_center_x = this . data . removeCenterX ;
this . remove_center_y = this . data . removeCenterY ;
this . handle_center_x = this . data . handleCenterX ;
this . handle_center_y = this . data . handleCenterY ;
this . scale = this . data . scale ;
this . rotate = this . data . rotate ;
break
}
}
} ,
onTouchEnd : function ( e ) {
this . active ( )
this . touch_target = ''
// 显示移除按钮
this . setData ( {
removeCenterX : 2 * this . data . stickerCenterX - this . data . handleCenterX ,
removeCenterY : 2 * this . data . stickerCenterY - this . data . handleCenterY ,
hideRemove : false
} )
// 若点击移除按钮则触发移除事件,否则触发刷新数据事件
if ( e . target . id === 'remove' ) {
this . triggerEvent ( 'removeSticker' , this . data . sticker_id )
} else {
this . triggerEvent ( 'refreshData' , this . data )
}
} ,
onTouchMove : function ( e ) {
// 若无选中目标则返回
if ( ! this . touch_target ) {
return
}
var current_x = e . touches [ 0 ] . clientX * 2
var current_y = e . touches [ 0 ] . clientY * 2
var diff_x = current_x - this . start_x
var diff_y = current_y - this . start_y
switch ( e . target . id ) {
case 'sticker' : {
// 拖动组件则所有控件同时移动
this . setData ( {
stickerCenterX : this . data . stickerCenterX + diff_x ,
stickerCenterY : this . data . stickerCenterY + diff_y ,
removeCenterX : this . data . removeCenterX + diff_x ,
removeCenterY : this . data . removeCenterY + diff_y ,
handleCenterX : this . data . handleCenterX + diff_x ,
handleCenterY : this . data . handleCenterY + diff_y
} )
break
}
case 'handle' : {
// 拖动操作按钮则原地旋转缩放
this . setData ( {
handleCenterX : this . data . handleCenterX + diff_x ,
handleCenterY : this . data . handleCenterY + diff_y
} )
var diff_x_before = this . handle_center_x - this . sticker_center_x ;
var diff_y_before = this . handle_center_y - this . sticker_center_y ;
var diff_x_after = this . data . handleCenterX - this . sticker_center_x ;
var diff_y_after = this . data . handleCenterY - this . sticker_center_y ;
var distance_before = Math . sqrt ( diff_x_before * diff_x_before + diff_y_before * diff_y_before ) ;
var distance_after = Math . sqrt ( diff_x_after * diff_x_after + diff_y_after * diff_y_after ) ;
var angle_before = Math . atan2 ( diff_y_before , diff_x_before ) / Math . PI * 180 ;
var angle_after = Math . atan2 ( diff_y_after , diff_x_after ) / Math . PI * 180 ;
this . setData ( {
scale : distance_after / distance_before * this . scale ,
rotate : angle_after - angle_before + this . rotate
} )
break
}
}
this . start_x = current_x ;
this . start_y = current_y ;
}
sticker
(наклейку, поставляемую вместе с программным обеспечением), image
(изображение, загруженное пользователем) и text
(пользовательский текст), все из которых сохраняются в объекте json в следующем формате. Каждый независимый компонент. Все они содержат уникальный идентификатор и соответствующую информацию. При сохранении объект генерируется клиентом, кодируется в строку json и сохраняется в базе данных. Когда состояние редактирования восстанавливается, объект получается путем анализа строки json и затем визуализируется. на странице редактирования. {
"backgroundId" : "5" , 背景图id
"assemblies" : [
{
"id" : "jhjg" , 组件id
"component_type" : "image" , 组件类型(自定义图片)
"image_url" : "https://example.com/jhjg.png" , 图片地址
"stickerCenterX" : 269 , 中心横坐标
"stickerCenterY" : 664 , 中心纵坐标
"scale" : 1.7123667831396403 , 缩放比例
"rotate" : - 3.0127875041833434 , 旋转角度
"wh_scale" : 1 , 图片宽高比
"z_index" : 19 组件层级
} ,
{
"id" : "gs47" ,
"component_type" : "text" , 组件类型(文字)
"text" : "test" , 文字内容
"stickerCenterX" : 479 ,
"stickerCenterY" : 546 ,
"scale" : 1.808535318980528 ,
"rotate" : 29.11614626607893 ,
"z_index" : 10
} ,
{
"id" : "chjn" ,
"component_type" : "sticker" , 组件类型(贴纸)
"sticker_type" : "food" , 贴纸类型
"sticker_id" : "1" , 贴纸id
"image_url" : "https://example.com/weapp/stickers/food/1.png" ,
"stickerCenterX" : 277 ,
"stickerCenterY" : 260 ,
"scale" : 1.3984276885130673 ,
"rotate" : - 16.620756913892055 ,
"z_index" : 5
}
]
}
Лицензия MIT
Авторские права (c) 2021 г. Е Лю