目录
给女朋友的微信小程序系列。
和女朋友的四周年纪念日要到了,往年的周年纪念日都是亲手画画,手绘纪念本,但是今年实在没那么多时间画画了,所以选择了用微信小程序做一个手绘本(虽然最后花的时间也不少)
初学前端不久,有的地方代码重复性高,多多见谅
扫描文末二维码,可以观看实际效果 (在底部tab栏“更多”,点击“四周年”)
由于要做成和书本相似,我选择了外面做一个书本打开的动画,书本完全打开后,会放大,然后变为展示一个轮播图,左右滑动可以切换下一页(不会做类似于翻书的动画哈哈)。每一页可以有视频、图片、文字等里面的内容可以自定义css,比如图片的长度宽度,绝对定位等。
这是外面书本的效果,有翻书的动画

这是翻书结束后,会变为一个轮播图,左右滑动查看不同页面

直接复制即可使用,但是我只保留了一些页面(隐私问题哈哈哈)。在wxml里,可以自己编辑书本、在 js文件里面的data的anniversary数组里添加数据,就可以变为自制的页面啦。
送给女朋友的,当然是要自己设计的页面哦,图片、文字的摆放,完全由自己安排
本人比较菜,不太会动画,所以大部分动画都是使用css3的transition做的,通过js来动态添加类名,比较繁琐。
注意,书本封面和书页的自定义,需要在这里编辑
<!-- 背景图,可以在这里修改背景图片 -->
<view>
<image src="https://cdn.nlark.com/yuque/0/2022/jpeg/25607170/1669648738488-b417a44b-af8a-498e-b420-586428fd49d5.jpeg" mode="aspectFill" class="bg-image"></image>
</view>
<!-- 翻书页面 -->
<view class="book-box {{book_box_opacity ? '': 'book-box-opacity'}}" wx:if="{{!anniversaryShow}}">
<!-- 书本 -->
<view class="book {{bookClick?'bookRight':''}} {{bookPageBig? 'bookPageBig':''}}" bindtap="bookOpen">
<!-- 封面 -->
<view class="startCover {{bookClick ? 'startCoverHover' : ''}}">
<!-- 正面 -->
<view>可以自定义css和wxml,来制作属于你的封面</view>
<!-- 背面 -->
<view class="coverBack">
</view>
</view>
<!-- 书页 -->
<block>
<!-- 2018 -->
<view class="bookPage page0 {{page0Open?'pageHover0':''}}">
<!-- 2018的正面 -->
<view class="photo page0Inner">
可以自定义css和wxml,来制作属于你的书页
</view>
<!-- 背面 -->
<view class="pageBack">
</view>
</view>
<!-- 2019 -->
<view class="bookPage page1 {{page1Open?'pageHover1':''}}">
<!-- 2019的正面 -->
<view class="page1Inner">
<view style="text-align: left;padding-left: 20rpx;" class="font3">2019</view>📌
<view wx:for="{{6}}" wx:key="index" class="text font3">~~~~~~~~~~</view>
</view>
<!-- 背面 -->
<view class="pageBack">
</view>
</view>
<!-- 2020 -->
<view class="bookPage page2 {{page2Open?'pageHover2':''}}">
<!-- 2020的正面 -->
<view class="photo">
可以自定义css和wxml,来制作属于你的书页
</view>
<!-- 背面 -->
<view class="pageBack">
</view>
</view>
<!-- 2021 -->
<view class="bookPage page3 {{page3Open?'pageHover3':''}}">
<!-- 2021的正面 -->
<view class="photo">
可以自定义css和wxml,来制作属于你的书页
</view>
<!-- 背面 -->
<view class="pageBack">
</view>
</view>
<!-- 2022 -->
<view class="bookPage page4 {{page4Open?'pageHover4':''}}">
<!-- 2022的正面 -->
<view class="page4Child photo">
<!-- 根据不同情况, 显示不同的图片 -->
<image src="{{nowBookImg}}"></image>
<!-- 红色书签 -->
<view class="bookmark">
</view>
</view>
</view>
<!-- other -->
<view class="bookPage page5 {{page5Open?'pageHover5':''}}"></view>
</block>
<!-- 封底 -->
<view class="endCover {{bookClick ? 'endCoverHover' : ''}}"></view>
<!-- 点我 -->
<view class="clickMe {{bookClick ? 'clickMeHover':''}}">
<text class="tex font2">打开康康</text>
</view>
</view>
<view class="speedLook font2" bindtap="speedLook" wx:if="{{!bookClick}}">可以点书本,一页一页翻书,也可以点这里快速查看</view>
</view>
<!-- 轮播图滚筒 -->
<swiper class="swiper" bindchange="swiperChange" wx:if="{{anniversaryShow}}" style="z-index: 999;">
<swiper-item wx:for="{{anniversary}}" wx:for-item="anniversary" wx:key="index" class="swiper_item">
<!-- 背景图 -->
<view>
<image src="{{anniversary.detail.background.bacImg}}" mode="aspectFill" class="bg-image"></image>
</view>
<!-- 顶部导航栏 -->
<view class="top-box" style="padding-top:{{top}}px;background-color: {{anniversary.detail.background.navigationColor}};color: {{anniversary.detail.background.navigationFontColor}};">
<view class="top-title">
<view style="height:{{menuHeight}}px;line-height:{{menuHeight}}px;">
<span class="title" style="font-weight: {{anniversary.detail.background.navigationFontWeight}};">{{anniversary.title}}</span>
</view>
</view>
</view>
<!-- 内容层 -->
<view class="page" style="height: calc(100% - {{top+menuHeight}}px);">
<!-- 图片 -->
<view class="position img" wx:for="{{anniversary.detail.picture}}" wx:key="index" style="width:{{item.css.width}};height:{{item.css.height}};top:{{item.css.top}};left:{{item.css.left}};right:{{item.css.right}};bottom:{{item.css.bottom}};transform: {{item.css.transform}};" bindtap="lookPic" data-data="{{anniversary.detail.picture}}" data-item="{{item}}">
<image src="{{item.src}}"></image>
<image src="https://cdn.nlark.com/yuque/0/2022/png/25607170/1666521211442-09f57685-8d83-4d9d-8c74-3c92caf11994.png" class="tip tip1" wx:if="{{item.css.decorate}}"></image>
<image src="https://cdn.nlark.com/yuque/0/2022/png/25607170/1666527339846-34e2e079-9c9c-448e-a6be-0a0d2b130ed3.png" class="tip tip2" wx:if="{{item.css.decorate}}"></image>
</view>
<!-- 文字 -->
<view class="position word {{item.css.fontStyle}}" wx:for="{{anniversary.detail.word}}" wx:key="index" style="width:{{item.css.width}};height:{{item.css.height}};top:{{item.css.top}};left:{{item.css.left}};right:{{item.css.right}};bottom:{{item.css.bottom}};background-color: {{item.css.backColor}};color: {{item.css.color}};font-size: {{item.css.fontSize}};font-weight: {{item.css.fontWeight}};text-shadow: {{item.css.textShadow}};text-align: {{item.css.textAlign}};">
<text decode="{{true}}" user-select>{{item.wordPush||item.content}}</text>
</view>
<!-- 视频 -->
<view class="position video" wx:for="{{anniversary.detail.video}}" wx:key="index" style="width:{{item.css.width}};height:{{item.css.height}};top:{{item.css.top}};left:{{item.css.left}};right:{{item.css.right}};bottom:{{item.css.bottom}};" wx:if="{{item.src!==''}}">
<video src="{{item.src}}"></video>
</view>
<!-- 特殊需求 - 音乐播放器 -->
<view class="music" wx:if="{{anniversary.id == 'music'}}">
<view class="{{music.isPlaying?'rocker rocker_start':'rocker'}}">
<image src="https://cdn.nlark.com/yuque/0/2022/png/25607170/1664697279285-e1cf77ae-3e94-4cd4-a38c-97bbe1d68c7f.png"></image>
</view>
<view class="music_image">
<!-- 这里可以放音乐封面或者其他图片 -->
<image src="" class="{{music.isPlaying ? 'circular' : ''}}"></image>
<!-- 边缘扩散动画效果 -->
<view class="pulse1 {{music.isPlaying ? 'pulseAnimation' : ''}}"></view>
<view class="pulse2 {{music.isPlaying ? 'pulseAnimation' : ''}}"></view>
<view class="pulse3 {{music.isPlaying ? 'pulseAnimation' : ''}}"></view>
</view>
<view class="music_bottom">
<view class="music_title">我们俩</view>
<view class="music_progress">
<view>04:07</view>
<view class="music_line">
<!-- 进度条的长度、颜色等,请在less文件修改,这里长度设置为 ⅓ -->
<view class="music_line_hover"> </view>
</view>
<view>12:03</view>
</view>
<view class="music_btn">
<view>
<image src="https://cdn.nlark.com/yuque/0/2022/png/25607170/1664696496445-455f1142-745c-46e3-bf1a-65b0f539cd84.png"></image>
</view>
<view class="music_start" bindtap="musicBtn">
<image src="https://cdn.nlark.com/yuque/0/2022/png/25607170/1664696496419-5e483b3f-126b-47b6-9484-813fe5972a53.png" wx:if="{{music.isPlaying}}"></image>
<image src="https://cdn.nlark.com/yuque/0/2022/png/25607170/1664696496460-7619fba5-c4e4-4e94-8e43-a1099d8362e4.png" wx:else style="margin-left: 8rpx;"></image>
</view>
<view>
<image src="https://cdn.nlark.com/yuque/0/2022/png/25607170/1664696496453-cb8b2c5d-df45-4e7f-bbfc-ca34d8833907.png"></image>
</view>
</view>
</view>
</view>
<!-- 特殊需求 - 结束页面退出按钮 -->
<view class="closeBtn font2" bindtap="closeBookBtn" wx:if="{{anniversary.id == 'beybey'}}">合上手账</view>
</view>
</swiper-item>
</swiper>
注意,轮播图的数据需要在这里添加,可以仿造我给的示例进行添加,自定义图片文字的摆放位置
const app = getApp();
const {
globalData
} = app
Page({
/**
* 页面的初始数据
*/
data: {
...globalData, //获取app.js的导航栏高度数据
bookClick: false, //首页点击书本
anniversary: [ //纪念本数据
//#region //备份模板
// {
// id: '', //id,特殊效果需要特殊的id,然后在wxml里面使用wx:if判断是否显示
// type:[],//是否需要有特殊效果 titlePush、video等,不需要就空数组(可以自定义效果,然后在swiperChange函数的switch里面增加对应的操作)
// time: ["", "", ""], //时间,用处不大
// title: '', //标题,会显示在导航栏,颜色在下面修改
// detail: { //详情
// word: [ //文字数组,如果需要titlePush一字一字弹出的效果,只能第一个元素实现(可以自己修改函数,实现全覆盖)
// {
// css: {//文字的css参数,有需要的话可以添加其他类型,然后在wxml对应位置加上内联样式
// width: '500rpx',
// height: '300rpx',
// top: '700rpx',
// left: '100rpx',
// right:'',
// bottom:'',
// color:'',
// backColor: '',
// fontSize: '30rpx',
// fontWeight:'900',
// textShadow: '3rpx 3rpx 3rpx #fff',
// fontStyle:'font',//是否使用特殊字体(class:font、font2、font3等,分别对应不同字体。注:需要自己找字体,然后在less文件里面增加,我这不提供字体url)
// textAlign:'center',
// },
// content: ` 段首缩进\n 换行`,//每段的段首缩进请打七个空格 、想换行为 \n
// }
// ],
// picture: [ //图片数组
// {//图片的css样式,如有需要可以新增,然后在wxml对应位置新增内联样式
// src: '',//图片路径
// css: {
// width: '500rpx',//宽度
// height: '300rpx',//高度
// top: '50rpx',//绝对定位
// left: '100rpx',//绝对定位
// right:'',//绝对定位
// bottom:'',//绝对定位
// transform: 'rotate(20deg)',//css3,可以让元素旋转放大平移等操作
// decorate: true,//是否需要装饰的图片(就是图片左上角和右下角那两个装饰,可以自定义装饰图片)
// }
// },
// ],
// video:[//视频
// {
// src:'',//视频链接
// css:{//视频css
// width:"",//宽
// height:'',//高
// top:'',//绝对定位
// left:'',//绝对定位
// right:'',//绝对定位
// bottom:''//绝对定位
// }
// }
// ],
// background: { //背景图数据
// bacImg: '',//背景图图片路径
// navigationColor: '#00000000', //导航栏背景颜色 如果想透明,就设置最后两位为00
// navigationFontColor: '#000000', //导航栏文字颜色
// navigationFontWeight: '', //导航栏文字粗细 900为粗体字
// }
// }
// },
//#endregion
//#region 已完成部分
{ //封面
id: 0, //id
time: ["2022", "12", "03"], //时间
title: '', //标题
detail: { //详情
word: [], //文字数组
picture: [], //图片数组
background: { //背景图数据
bacImg: 'https://cdn.nlark.com/yuque/0/2022/png/25607170/1665555350967-71815500-10c4-4d28-ba4e-ebc2534eb822.png?x-oss-process=image%2Fresize%2Cw_537%2Climit_0',
navigationColor: '#00000000', //导航栏背景颜色
navigationFontColor: '#000000', //导航栏文字颜色
}
}
},
{ //音乐 这个页面是特殊效果
id: 'music', //id
type: ['music'],
time: ["2018", "12", "03"], //时间
title: '这里是音乐', //标题
detail: { //详情
word: [], //文字
picture: [], //图片数组
background: { //背景图数据
bacImg: '',
navigationColor: '#6d6d6d', //导航栏背景颜色
navigationFontColor: '#ffffff', //导航栏文字颜色
}
}
},
{ //示例
id: 'text', //id,特殊效果需要特殊的id,然后在wxml里面使用wx:if判断是否显示
type: ['titlePush'], //是否需要有特殊效果 titlePush 等,不需要就空数组(可以自定义效果,然后在swiperChange函数的switch里面增加对应的操作)
time: ["", "", ""], //时间,用处不大
title: '测试测试', //标题,会显示在导航栏,颜色在下面修改
detail: { //详情
word: [ //文字数组,如果需要一字一字弹出的效果,只能第一个元素实现(可以自己修改函数,实现全覆盖)
{
css: { //文字的css参数,有需要的话可以添加其他类型,然后在wxml对应位置加上内联样式
width: '500rpx',
height: '300rpx',
top: '700rpx',
left: '100rpx',
right: '',
bottom: '',
color: 'red',
backColor: '',
fontSize: '50rpx',
fontWeight: '900',
textShadow: '3rpx 3rpx 3rpx #fff',
fontStyle: '', //是否使用特殊字体(class:font、font2、font3等,分别对应不同字体。注:需要自己找字体,然后在less文件里面增加,我这不提供字体url)
textAlign: '',
},
content: ` 段首缩进\n换行`, //每段的段首缩进请打七个空格 、想换行为 \n
},
{
css: { //文字的css参数,有需要的话可以添加其他类型,然后在wxml对应位置加上内联样式
width: '750rpx',
height: '',
top: '',
left: '',
right: '',
bottom: '100rpx',
color: 'red',
backColor: '',
fontSize: '30rpx',
fontWeight: '900',
textShadow: '3rpx 3rpx 3rpx #fff',
fontStyle: 'font', //是否使用特殊字体(class:font、font2、font3等,分别对应不同字体。注:需要自己找字体,然后在less文件里面增加,我这不提供字体url)
textAlign: 'center',
},
content: `可以放置多个图片、文字、视频`, //每段的段首缩进请打七个空格 、想换行为 \n
},
],
picture: [ //图片数组
{ //图片的css样式,如有需要可以新增,然后在wxml对应位置新增内联样式
src: 'https://cdn.nlark.com/yuque/0/2022/jpeg/25607170/1669648738488-b417a44b-af8a-498e-b420-586428fd49d5.jpeg', //图片路径
css: {
width: '300rpx', //宽度
height: '500rpx', //高度
top: '50rpx', //绝对定位
left: '100rpx', //绝对定位
right: '', //绝对定位
bottom: '', //绝对定位
transform: 'rotate(20deg)', //css3,可以让元素旋转放大平移等操作
decorate: true, //是否需要装饰的图片(就是图片左上角和右下角那两个装饰,可以自定义装饰图片)
}
},
{ //图片的css样式,如有需要可以新增,然后在wxml对应位置新增内联样式
src: 'https://cdn.nlark.com/yuque/0/2022/png/25607170/1665555350967-71815500-10c4-4d28-ba4e-ebc2534eb822.png?x-oss-process=image%2Fresize%2Cw_537%2Climit_0', //图片路径
css: {
width: '200rpx', //宽度
height: '300rpx', //高度
top: '', //绝对定位
left: '', //绝对定位
right: '100rpx', //绝对定位
bottom: '100rpx', //绝对定位
transform: 'rotate(-20deg)', //css3,可以让元素旋转放大平移等操作
decorate: true, //是否需要装饰的图片(就是图片左上角和右下角那两个装饰,可以自定义装饰图片)
}
},
],
background: { //背景图数据
bacImg: 'https://cdn.nlark.com/yuque/0/2022/jpeg/25607170/1669648738488-b417a44b-af8a-498e-b420-586428fd49d5.jpeg', //背景图图片路径
navigationColor: '#00000000', //导航栏背景颜色 如果想透明,就设置最后两位为00
navigationFontColor: '#000000', //导航栏文字颜色
navigationFontWeight: '', //导航栏文字粗细 900为粗体字
}
}
},
{ //关书
id: 'beybey', //id
type: ['titlePush'], //是否需要有特殊效果 titlePush、video,不需要就空数组
time: ["", "", ""], //时间
title: '未完待续 ... ', //标题
detail: { //详情
word: [ //文字数组,如果需要一字一字弹出的效果,只能第一个元素
{
css: {
width: '750rpx',
height: '300rpx',
top: '300rpx',
left: '',
right: '',
bottom: '',
color: '',
backColor: '',
fontSize: '60rpx',
fontWeight: '900',
textShadow: '3rpx 3rpx 3rpx #fff',
fontStyle: 'font', //是否使用特殊字体(class:font、font2、font3)
textAlign: 'center',
},
content: `❤️我们的故事❤️\n❤️还没有完结❤️\n❤️敬请期待 ~ ❤️`, //段落缩进打七个空格 、换行为 \n
}
],
background: { //背景图数据
bacImg: 'https://cdn.nlark.com/yuque/0/2022/jpeg/25607170/1669648738488-b417a44b-af8a-498e-b420-586428fd49d5.jpeg',
navigationColor: '#00000000', //导航栏背景颜色
navigationFontColor: '#000000', //导航栏文字颜色
navigationFontWeight: '900', //导航栏文字粗细
}
}
},
//#endregion
],
music: { //特殊需求--歌曲播放器
isPlaying: false,
},
},
//打开书本
bookOpen(e, time) {
if (this.data.bookLoading) return; //正在打开/关闭书本的话
let pageTime = time || 3000 //翻书时间,一般是3s //不传参则为3000
// console.log(pageTime,time);
this.setData({
bookLoading: true, //是否正在开关书
bookClick: true, //打开书本封面
nowBookImg: this.data.anniversary[0].detail.background.bacImg, //显示的是封面
})
setTimeout(() => { //翻走第一页:2018
this.setData({
page0Open: true
})
setTimeout(() => { //翻走第二页:2019
this.setData({
page1Open: true
})
setTimeout(() => { //翻走第三页:2020
this.setData({
page2Open: true
})
// return
setTimeout(() => { //翻走第四页:2021
this.setData({
page3Open: true
})
setTimeout(() => { //翻走第五页:2022(第五页虽然不用翻开,但是需要等上一页动画结束)
this.setData({
page4Open: true
})
// return
this.setData({
bookPageBig: true, //书页变大
})
setTimeout(() => { //三秒后书页最大,显示轮播图
this.setData({
anniversaryShow: true, //显示轮播图
bookLoading: false, //是否正在开关书
})
}, 2500); //放大书本的动画时长是2s
}, pageTime);
}, pageTime);
}, pageTime);
}, pageTime);
}, pageTime);
},
//关上书本
closeBook() {
if (this.data.bookLoading) return; //正在打开/关闭书本的话
this.setData({
bookLoading: true, //是否正在开关书
anniversaryShow: false, //轮播图变书页
nowBookImg: this.data.anniversary[this.data.anniversary.length - 1].detail.background.bacImg //显示的是最后一页
})
setTimeout(() => { //1s后书页开始变小
this.setData({
bookPageBig: false //书页变小
})
setTimeout(() => { //三秒后书关书
this.setData({
bookClick: false, //合上书本封面
page0Open: false, //合上第1页
page1Open: false, //合上第2页
page2Open: false, //合上第3页
page3Open: false, //合上第4页
page4Open: false, //合上第5页
})
setTimeout(() => { //完全合上书本后才退出开关书状态
this.setData({
bookLoading: false, //是否正在开关书
})
}, 3000);
}, 3000);
}, 1000);
},
//快速打开书本
speedLook(e) {
wx.showModal({
title: '快速查看',
content: '是否跳过翻书过程,快速查看?',
success: (res) => {
if (res.confirm) { //点了确认按钮
this.bookOpen(e, 10)
}
}
})
},
//关书按钮
closeBookBtn() {
wx.showModal({
title: '手绘结束啦',
content: '是否合上手账?',
cancelText: '继续浏览',
confirmText: '合上手账',
success: (res) => {
if (res.confirm) { //点了确认按钮
this.closeBook()
}
}
})
},
//点击图片,查看图片详情
lookPic(e) {
let data = e.currentTarget.dataset.data //本页面的所有图片数据
let item = e.currentTarget.dataset.item //当前点击的图片是哪个
let urls = []
for (let i = 0; i < data.length; i++) {
urls.push(data[i].src)
}
wx.previewImage({
current: item.src, //当前展示的图片
urls, // 需要预览的图片 http 链接数组
})
},
//#region ————————————————————轮播图滚动出现特定事件
//轮播图滚动
swiperChange(e) {
// console.log(e.detail.current, e.detail.source);//第一个参数是index,第二个参数是轮播图滚动方式
//特定情况做特定的事.用type来判断
if (this.data.anniversary[e.detail.current].type && this.data.anniversary[e.detail.current].type.length != 0) {
for (let i = 0; i < this.data.anniversary[e.detail.current].type.length; i++) {
const element = this.data.anniversary[e.detail.current].type[i];
switch (element) {
case 'music': //如果是歌曲页面,就播放
this.musicStart()
break;
case 'start':
case 'end':
this.wordPush(e.detail.current); //需要一字一字弹出的效果的页面
break;
case 'titlePush': //仅第一组文字 一字一字弹出的效果的页面
this.wordPush(e.detail.current);
this.nbsp(e.detail.current); //空格换成
break;
default: //其他普通情况
this.nbsp(e.detail.current); //空格换成
break;
}
}
}
},
//空格换成
nbsp(index) {
// console.log('序号是', index);
// console.log('type是', this.data.anniversary[index].type);
let first = 0; //循环的开始
if (this.data.anniversary[index].type) {
for (let i = 0; i < this.data.anniversary[index].type.length; i++) {
const element = this.data.anniversary[index].type[i];
if (element == 'titlePush') {
first = 1; //跳过第一个(一字一字弹出的页面)
}
}
}
// console.log('循环开始是', first);
for (let i = first; i < this.data.anniversary[index].detail.word.length; i++) {
const element = this.data.anniversary[index].detail.word[i];
let contentSetData = `anniversary[${index}].detail.word[${i}].content` //文字,这里用于setData
let content = element.content
while (content.indexOf(' ') != '-1') { //所有空格替换为
content = content.replace(' ', ' ')
}
this.setData({
[contentSetData]: content
})
}
},
//播放按钮+
musicBtn() {
if (this.data.music.isPlaying) {
this.back.pause();
this.setData({
stopMusic: true //如果手动点击了暂停,就不要自动打开了
})
} else {
this.back.play();
}
this.setData({
'music.isPlaying': !this.data.music.isPlaying
})
},
//定时器放歌
musicStart() {
clearTimeout(this.musicTimer)
this.musicTimer = setTimeout(() => {
if (this.data.stopMusic == true) return //如果手动点击了暂停,就不自动打开了
this.setData({
'music.isPlaying': true
})
this.back.play();
}, 1000);
},
//一个个播放文字 参数是当前页面的序号
wordPush(index) {
clearInterval(this.timer) //清除原本的定时器
clearInterval(this.timer2) //清除原本的定时器
//如果该页面播放成功了,就不再重新播放
if (this.data.anniversary[index].id == 'start' && this.data.startUp == true) return
let wordPush = `anniversary[${index}].detail.word[0].wordPush` //要展示的文字,这里用于setData
let word = this.data.anniversary[index].detail.word[0].content; //原始文字
this.setData({ //先设为第一个字,避免页面闪现
[wordPush]: word.slice(0, 1)
})
let push = 1 //一字一字出现,的序号
//开始定时器
this.timer = setInterval(() => {
let temp = word.slice(0, push)
while (temp.indexOf(' ') != '-1') { //所有空格替换为
temp = temp.replace(' ', ' ')
}
this.setData({
[wordPush]: temp + '_'
})
push++;
if (push > word.length) {
clearInterval(this.timer)
//特殊需求 - 如果是start页面,就让图片升起来 + 实现 __ 一闪一闪的效果
if (this.data.anniversary[index].id == 'start') {
//实现 __ 一闪一闪的效果
this.timer2 = setInterval(() => {
this.setData({
[wordPush]: temp
})
setTimeout(() => {
this.setData({
[wordPush]: temp + '_'
})
}, 500);
}, 1000);
this.setData({
startUp: true
})
} else {
this.setData({
[wordPush]: temp //文字末尾没有“_”
})
}
}
}, 100);
},
//#endregion
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
//设置背景音乐
this.back = wx.createInnerAudioContext();
this.back.src = "https://music.163.com/song/media/outer/url?id=85571.mp3"; //可以自己修改成别的音乐链接,这个是《我们俩》
this.setData({
book_box_opacity: true //让书本慢慢显示出来
})
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
if (this.back != undefined) {
//使用wx提供的接口预览图片,会使得音乐暂停,需要在这里重新开始
if (this.data.music.isPlaying) {
this.back.play()
} else {
this.back.pause()
}
}
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
this.back.pause(); //关闭页面就暂停音乐
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
},
})
这里是该页面的配置文件,主要是取消微信自带的导航栏
{
"usingComponents": {},
"navigationStyle": "custom"
}
这里是less文件,请使用vscode插件,转为wxss!!(wxss写代码过于繁琐,还是less香)
关于font字体,我担心会有版权问题,所以这里就不添加字体url了,有需要的就自己去设置(在本代码块的最下面)
//顶部导航栏
.top-box {
position: relative;
padding: 0 var(--trapezoidSize);
box-sizing: border-box;
width: 100vw;
// height: 600rpx;
margin-bottom: var(--trapezoidHeight);
padding: 0 52rpx;
// padding-bottom: 20rpx;
box-sizing: border-box;
.top-title {
text-align: center;
font-size: 36rpx;
font-weight: 500;
font-stretch: extra-expanded;
}
}
// 开始页面
.startPage {
position: absolute;
bottom: -200%;
transition: all 1.5s;
width: 750rpx;
height: 400rpx;
image {
width: 400rpx;
height: 400rpx;
position: absolute;
left: 50%;
transform: translate(-50%);
}
.startPageText {
color: #ffc052;
width: 750rpx;
font-size: 200rpx;
position: absolute;
top: -10%;
text-align: center;
transform: translateY(-100%);
text-shadow: 20rpx 20rpx 20rpx black;
.startPageYear {
color: #cecece;
font-size: 100rpx;
width: 750rpx;
position: absolute;
transform: translateY(-50%);
text-align: center;
}
}
}
.startPageUp {
bottom: 0;
}
//验证码页面
.code {
width: 750rpx;
height: 300rpx;
display: flex;
align-items: center;
justify-content: center;
input {
width: 180rpx;
height: 80rpx;
border: 1rpx solid black;
border-radius: 20rpx;
padding: 10rpx;
}
image {
margin-left: 20rpx;
width: 200rpx;
height: 100rpx;
}
}
canvas {
width: 100%;
height: 100%;
z-index: 999;
}
//翻书页面
.book-box {
width: 100%;
height: 100%;
position: relative;
top: 0;
perspective: 900rpx;
transform-style: preserve-3d;
transition: all 3s linear;
opacity: 1;
&.book-box-opacity {
top: -10%;
opacity: 0;
}
//书本
.book {
transform-style: preserve-3d;
position: absolute;
top: 50%;
left: 50%;
transform-origin: left center 0;
transform: translate(-50%, -50%) rotateY(-10deg);
width: 250rpx;
height: 450rpx;
box-shadow: 10rpx 10rpx 60rpx #00000080;
transition: all 2s linear; //书本放大动画时间
//点了书本之后,向右挪动点
&.bookRight {
left: 60%;
}
//书本放大效果
&.bookPageBig {
position: fixed;
width: 100%;
height: 100%;
left: 50%;
transform: translate(-50%, -50%) rotateY(0deg);
}
//边缘圆滑
>view {
border-top-right-radius: 10rpx;
border-bottom-right-radius: 10rpx;
}
// 封面
.startCover {
transform-style: preserve-3d;
transition: all 3s; //控制翻页速度
position: absolute;
top: 50%;
left: 0;
width: 104%;
height: 104%;
transform: translate(0, -50%) rotateY(-20deg);
background-color: antiquewhite;
transform-origin: left center 0;
box-shadow: 5rpx 5rpx 5rpx #00000036;
border-left: 1rpx solid antiquewhite;
&.startCoverHover {
transform: translate(0, -50%) rotateY(-160deg);
}
//封面的背面,防止透视
.coverBack {
width: 100%;
height: 100%;
background-color: antiquewhite;
position: absolute;
top: 0;
left: 0;
transform-origin: left center 0;
transform: translateZ(-1rpx);
overflow: hidden;
display: flex;
flex-direction: column;
border-top-right-radius: 10rpx;
border-bottom-right-radius: 10rpx;
.image {
width: 100%;
height: 33%;
}
}
//装饰
.back {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
border-top-right-radius: 10rpx;
border-bottom-right-radius: 10rpx;
overflow: hidden;
}
.earth {
width: 200rpx;
height: 200rpx;
position: absolute;
bottom: 5%;
left: 50%;
transform: translate(-50%, 0);
}
.title {
padding: 10rpx;
position: absolute;
top: 13%;
left: 10%;
color: pink;
font-size: 50rpx;
white-space: nowrap;
text-shadow: 2rpx 2rpx 2rpx rgba(0, 0, 0, 0.503);
}
}
// 书页
.bookPage {
width: 100%;
height: 100%;
transition: all 3s; //控制翻页速度
position: absolute;
top: 0;
left: 0;
background-color: #fbf7f2;
transform-origin: left center 0;
border-left: 2rpx solid rgba(0, 0, 0, 0.3);
box-shadow: 5rpx 5rpx 5rpx rgba(0, 0, 0, 0.116);
//2018
&.page0 {
transform-style: preserve-3d;
transform: rotateY(-15deg);
&.pageHover0 {
transform: rotateY(-150deg);
}
.page0Inner {
.time {
position: absolute;
top: 20rpx;
right: 5rpx;
display: flex;
.time1 {
width: 20rpx;
color: rgb(112, 112, 112);
font-size: 20rpx;
}
.time2 {
display: flex;
align-items: center;
color: rgb(112, 112, 112);
.left {
font-size: 50rpx;
}
.right {
font-size: 30rpx;
display: flex;
flex-direction: column;
align-items: center;
.day {
font-weight: 700;
}
.month {
font-size: 16rpx;
}
}
}
}
.word {
position: absolute;
top: 120rpx;
left: 10rpx;
width: 80%;
.word1 {
width: 100%;
text-align: left;
color: rgb(68, 68, 68);
}
.word2 {
width: 100%;
text-align: right;
font-size: 40rpx;
}
}
.bottomText {
position: absolute;
bottom: 30rpx;
left: 0;
width: 100%;
text-align: center;
font-size: 14rpx;
white-space: nowrap;
color: rgba(0, 0, 0, 0.445);
}
}
}
//2019
&.page1 {
transform-style: preserve-3d;
transform: rotateY(-10deg);
&.pageHover1 {
transform: rotateY(-140deg);
}
.page1Inner {
position: absolute;
top: 50%;
left: 0;
transform: translate(0, -50%);
width: 100%;
text-align: center;
}
}
//2020
&.page2 {
transform-style: preserve-3d;
transform: rotateY(-5deg);
&.pageHover2 {
transform: rotateY(-130deg);
}
}
//2021
&.page3 {
transform: rotateY(-3deg);
transform-style: preserve-3d;
&.pageHover3 {
transform: rotateY(-120deg);
}
}
//2022
&.page4 {
transform: rotateY(-2deg);
.page4Child {
//书签
.bookmark {
width: 4%;
height: 106%;
background-color: #fa3726;
position: absolute;
left: 1rpx;
top: -2%;
box-shadow: 2rpx 2rpx 2rpx rgba(0, 0, 0, 0.116);
border-top-right-radius: 3rpx;
border-top-left-radius: 3rpx;
.image {
width: 100%;
height: 80rpx;
position: absolute;
bottom: -20rpx;
left: 0;
}
// .left {
// width: 0;
// height: 0;
// border-top: 16rpx solid red;
// border-right: 8rpx solid transparent;
// border-bottom: 0 solid transparent;
// border-left: 0 solid transparent;
// position: absolute;
// bottom: -16rpx;
// left: 0;
// }
// .right {
// width: 0;
// height: 0;
// border-top: 16rpx solid red;
// border-right: 0 solid transparent;
// border-bottom: 0 solid transparent;
// border-left: 8rpx solid transparent;
// position: absolute;
// bottom: -16rpx;
// right: 0;
// box-shadow: 2rpx 0rpx 2rpx rgba(0, 0, 0, 0.116);
// }
}
}
&.pageHover4 {
transform: rotateY(-0.1deg);
}
}
//待定
&.page5 {
transform: rotateY(0deg);
&.pageHover5 {
transform: rotateY(0);
}
}
//正面 - 图片
.photo {
width: 100%;
height: 100%;
image {
width: 100%;
height: 100%;
border-top-right-radius: 10rpx;
border-bottom-right-radius: 10rpx;
overflow: hidden;
}
}
//背面
.pageBack {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
transform: translateZ(-2rpx) rotateY(180deg);
background-color: #fbf7f2;
border-radius: 10rpx;
overflow: hidden;
//背面的年份
.pageBackInner {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
height: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
.love {
width: 50%;
height: 50%;
}
.text {
color: #ffa70e;
font-size: 50rpx;
}
}
}
}
// 封底
.endCover {
transition: all 5s;
position: absolute;
top: 50%;
left: 0;
background-color: #a3a3a3;
width: 104%;
height: 104%;
transform: translate(0, -50%) rotateY(0deg);
background-color: antiquewhite;
transform-origin: left center 0;
box-shadow: 5rpx 5rpx 5rpx #00000036;
border-left: 1rpx solid antiquewhite;
}
//点我打开看看
.clickMe {
position: absolute;
top: 0;
left: 0;
transform: translate(-100%, -100%);
display: flex;
opacity: 0.5;
transition: all 2s;
&.clickMeHover {
opacity: 0;
}
.text {
color: rgba(0, 0, 0, 0.3);
margin-right: 15rpx;
}
.image {
width: 100rpx;
height: 100rpx;
}
}
}
//快速查看按钮
.speedLook {
padding: 10rpx;
background-color: pink;
border: 10rpx dashed rgb(122, 92, 92);
position: absolute;
bottom: 300rpx;
left: 50%;
transform: translate(-50%);
border-radius: 20rpx;
font-size: 30rpx;
box-shadow: 10rpx 10rpx 20rpx rgb(46, 46, 46);
}
}
//结束页面 关闭按钮
.closeBtn {
padding: 10rpx;
background-color: pink;
border: 10rpx dashed rgb(122, 92, 92);
position: absolute;
bottom: 400rpx;
left: 50%;
transform: translate(-50%);
border-radius: 30rpx;
font-size: 60rpx;
box-shadow: 10rpx 10rpx 20rpx rgb(46, 46, 46);
}
//下面是css代码,历史遗留问题,不是less
/* 滚筒 */
.swiper {
width: 100%;
height: 100%;
}
.swiper_item {
width: 100%;
height: 100%;
}
page {
width: 100%;
height: 100%;
}
.page {
width: 100%;
position: relative;
}
.position {
position: absolute;
}
.img {
// image {
// overflow: hidden;
// border-radius: 20rpx;
// }
.tip {
width: 100rpx;
height: 100rpx;
position: absolute;
}
.tip1 {
top: 10rpx;
left: 0;
transform: translate(-50%, -50%) rotate(-45deg);
}
.tip2 {
width: 80rpx;
height: 80rpx;
bottom: 15rpx;
right: 0;
transform: translate(50%, 50%);
}
}
.word {
overflow: auto;
border-radius: 20rpx;
padding: 10rpx;
// color: #553d3d;
}
.video {
video {
width: 100%;
height: 100%;
}
}
/* 音乐播放器 */
.music {
width: 100%;
height: 100%;
background-color: rgb(109, 109, 109);
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
position: relative;
}
.rocker {
width: 146rpx;
height: 236rpx;
position: absolute;
z-index: 999999;
top: 0;
left: 50%;
transition: all 0.5s linear;
transform: rotate(-10deg);
transform-origin: 20rpx 20rpx;
}
.rocker_start {
transform: rotate(30deg);
transform-origin: 20rpx 20rpx;
}
.music_image {
width: 500rpx;
height: 500rpx;
border-radius: 50%;
border: 0.2rem solid #fefefe18;
z-index: 99999;
position: relative;
margin: 200rpx 0;
}
.music_image image {
border-radius: 50%;
overflow: hidden;
}
/* 边缘扩散动画 */
.pulseAnimation {
animation: pulse 3s linear infinite;
}
view[class^="pulse"] {
position: absolute;
z-index: 99999;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 500rpx;
height: 500rpx;
box-shadow: 0 0 24rpx #e2e2e269;
border-radius: 50%;
}
.music .pulse2 {
animation-delay: 1.5s;
}
.music .pulse3 {
animation-delay: 3s;
}
@keyframes pulse {
0% {}
50% {
width: 600rpx;
height: 600rpx;
opacity: 1;
}
100% {
width: 700rpx;
height: 700rpx;
opacity: 0;
}
}
/* 旋转动画 */
.circular {
animation: rotate 30s linear infinite;
}
@keyframes rotate {
0% {
transform: rotateZ(0deg);
/*从0度开始*/
}
100% {
transform: rotateZ(360deg);
/*360度结束*/
}
}
.music_bottom {
display: flex;
flex-direction: column;
align-items: center;
color: white;
}
.music_title {
font-size: 50rpx;
margin-bottom: 20rpx;
}
.music_progress {
display: flex;
align-items: center;
}
.music_line {
width: 500rpx;
height: 10rpx;
background-color: #cecece;
border-radius: 15rpx;
position: relative;
margin: 0 20rpx;
}
.music_line_hover {
width: 33%;
height: 100%;
position: absolute;
border-radius: 15rpx;
top: 0;
left: -5rpx;
background-color: #fd544e;
}
.music_love {
position: absolute;
top: 50%;
right: 0;
transform: translate(50%, -50%);
width: 40rpx;
height: 40rpx;
}
.music_btn {
display: flex;
align-items: center;
justify-content: center;
margin-top: 20rpx;
}
.music_btn>view {
width: 70rpx;
height: 70rpx;
}
.music_btn .music_start {
width: 80rpx;
height: 80rpx;
padding: 20rpx;
border: 4rpx solid white;
border-radius: 50%;
margin: 0 50rpx;
}
/* 背景图 */
.bg-image {
width: 100%;
height: 100%;
position: fixed;
z-index: -98;
}
//字体 - 请自己输入url
// // 字体1
// @font-face {
// font-family: "iconfont";
// src: url('') format('truetype');
// }
// // 字体2
// @font-face {
// font-family: "iconfont2";
// src: url("") format("truetype");
// }
// // 字体3
// @font-face {
// font-family: "iconfont3";
// src: url("") format("truetype");
// }
// .font {
// font-family: "iconfont" !important;
// font-style: normal;
// -webkit-font-smoothing: antialiased;
// -moz-osx-font-smoothing: grayscale;
// }
// .font2 {
// font-family: "iconfont2" !important;
// font-style: normal;
// -webkit-font-smoothing: antialiased;
// -moz-osx-font-smoothing: grayscale;
// }
// .font3 {
// font-family: "iconfont3" !important;
// font-style: normal;
// -webkit-font-smoothing: antialiased;
// -moz-osx-font-smoothing: grayscale;
// }
image {
width: 100%;
height: 100%;
}
在项目根目录的app.js里,使用如下代码(主要是用于获取导航栏的高度,以便自定义导航栏)
// app.js
App({
onLaunch() {
this.getSystemInfo() //获取页面顶部高度
},
globalData: {
},
// 获取胶囊信息
getSystemInfo: function () {
const {
statusBarHeight,
platform
} = wx.getSystemInfoSync();
const {
left,
height,
top,
right,
width
} = wx.getMenuButtonBoundingClientRect();
this.globalData.top = top;
this.globalData.menuHeight = height;
this.globalData.barHeight = platform === "ios" ? statusBarHeight + height + (top - statusBarHeight) * 3 : statusBarHeight + height + (top - statusBarHeight) * 2;
this.globalData.right = left;
this.globalData.left = right;
this.globalData.width = width;
},
})
本文到这里就结束啦,初学不久,如果有哪些地方代码有问题、写的不好,多多指教!
关注我,后面会慢慢更新有用的源码哦。
最后附上我给女朋友做的小程序~

一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame
前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
@作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors 1、什么是behaviors 2、behaviors的工作方式 3、创建behavior 4、导入并使用behavior 5、behavior中所有可用的节点 6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors 1、什么是behaviorsbehaviors是小程序中,用于实现
1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>
参考文章搭建文章gitte源码在线体验可以注册两个号来测试演示图:一.整体介绍 介绍SignalR一种通讯模型Hub(中心模型,或者叫集线器模型),调用这个模型写好的方法,去发送消息。 内容有: ①:Hub模型的方法介绍 ②:服务器端代码介绍 ③:前端vue3安装并调用后端方法 ④:聊天室样例整体流程:1、进入网站->调用连接SignalR的方法2、与好友发送消息->调用SignalR的自定义方法 前端通过,signalR内置方法.invoke() 去请求接口3、监听接受方法(渲染消息)通过new signalR.HubConnectionBuilder().on
提供3种Ubuntu系统安装微信的方法,在Ubuntu20.04上验证都ok。1.WineHQ7.0安装微信:ubuntu20.04安装最新版微信--可以支持微信最新版,但是适配的不是特别好;比如WeChartOCR.exe报错。2.原生微信安装:linux系统下的微信安装(ubuntu20.04)--微信适配的最好,反应最快,但是微信版本只到2.1.1,版本太老,很多功能都没有。3.深度deepin-wine6安装微信:ubuntu20.04+系统deepin-wine6安装新版微信--综合比较好,当前个人使用此种方法1个月,微信版本3.4;没什么大问题,尚可。一、WineHQ7.0安装微信
对传统的餐饮商家来说,小程序很好地解决了餐厅线下线上连接的问题,在引流获客、节约人力、营销宣传、塑造会员体系、改善消费体验等方面都有很大帮助。小程序点餐可以帮助餐饮企业节省一大把人力开支。一个包含扫码点单、菜品管理、优惠券推送、外卖配送的小程序,商家花几万元就能完成开发测试并投入。商家为什么要开通“扫码点餐”1.解决服务员不够用的问题。2.不怕顾客跑单漏单。3.在微信就能管理菜品、查看营业额。4.订单小票显示顾客桌号和已点菜品。5.可在“附近的小程序”找到您的门店。如今餐饮业常用的三种经营模式:1堂食点单模式客人通过小程序堂食点单。商家可以在微信扫码点餐小程序管理后台根据自己店内情况来设置不同
技术选型1,前端小程序原生MINA框架cssJavaScriptWxml2,管理后台云开发Cms内容管理系统web网页3,数据后台小程序云开发云函数云开发数据库(基于MongoDB)云存储4,人脸识别算法基于百度智能云实现人脸识别一,用户端效果图预览老规矩我们先来看效果图,如果效果图符合你的需求,就继续往下看,如果不符合你的需求,可以跳过。1-1,登录注册页可以看到登录页有注册入口,注册页如下我们的注册,需要管理员审核,审核通过后才可以正常登录使用小程序1-2,个人中心页登录成功以后,我们会进入个人中心页我们在个人中心页可以注册人脸,因为我们做人脸识别签到,需要先注册人脸才可以进行人脸比对,进
快速导航(持续更新中…)Cesium源码解析一(terrain文件的加载、解析与渲染全过程梳理)Cesium源码解析二(metadataAvailability的含义)Cesium源码解析三(metadata元数据拓展中行列号的分块规则解析)Cesium源码解析四(Quantized-Mesh(.terrain)格式文件在CesiumJS和UE中加载情况的对比)目录1.前言2.本篇的由来3.terrain文件的加载3.1更新环境3.2更新和执行渲染命令3.3数据优化3.4结束当前帧4.总结1.前言 目前市场上三维比较火的实现方案主要有两种,b/s的方案主要是Cesium,c/s的方案主要是u