当前位置:首页>小程序源码>我用 AI 零代码撸了一个微信小程序:Dino Kids

我用 AI 零代码撸了一个微信小程序:Dino Kids

  • 2026-05-08 22:20:28
我用 AI 零代码撸了一个微信小程序:Dino Kids

我用 AI 零代码撸了一个微信小程序:Dino Kids

设计、素材、组件全部由 AI 完成,免费模型 + 生图模型真香

个人开发者 + 免费 AI 模型 + Gemini 生图 = 高效产出高质量小程序
附 · Dino Kids 真实产品截图 & 核心组件代码

最近我利用业余时间开发了一款少儿英语启蒙的微信小程序 Dino Kids
整个开发过程——从页面设计、素材背景图,到复杂的动效组件——几乎都由 AI 完成。
特别要提的是,所有图片素材(背景、彩带、按钮装饰等)均使用 Google 最新生图模型 gemini-3-pro-image-preview-2k 生成,风格统一、分辨率高,而且完全免费。

今天就把我的完整实践过程分享出来,带大家看看一个“AI 全包”的小程序长什么样。

一、产品长什么样?真实截图一览

先来看几张核心界面,感受一下 UI 和功能布局。

单词学习页绘本馆游戏中心绘画/创作页单词学习页:以动物主题分类(cat、bird、dog、pig……),卡片式设计,点击即发音。
绘本馆:2200+ 绘本,支持蓝思值 BR-70L、新课标等级筛选,还有“上次阅读”续读功能。
游戏中心:包含 Word King、Pic-Word Match、Flip Fun 等互动小游戏。

以上所有页面中的背景纹理、动物图标、彩带素材、按钮装饰,基本使用 gemini-3-pro-image-preview-2k 逐张生成或批量生成的。下文会细说。

体验入口

二、我用到的 AI 模型全家桶

2.1 聊天/代码生成模型(免费主力)

我主要使用 arena.ai 平台,右侧选择模型直接对话:

  • Gemini 3 Flash(免费,响应快)
  • GLM 5.1(免费,中文理解好)
  • GPT-5.2(免费,逻辑严谨)

这些模型帮我生成了 90% 的前端代码,包括两个核心动效组件(Lottie 和礼花粒子系统)。

2.2 图片生成模型(素材全靠它)

gemini-3-pro-image-preview-2k
这是 Google 目前最强的图像生成模型,支持 2K 分辨率,提示词遵循度极高。
我用它生成了:

  • 单词卡片上的动物形象(保持一致的扁平可爱风格)
  • 绘本馆的装饰 banner 和 2200+ 绘本的封面占位图(批量生成)
  • 礼花组件里的 30 张彩带 PNG 序列帧
  • 底部导航的纯图标(ABC / word / book / game / create

生成示例提示词:

“Generate a cute cartoon bee, simple flat style, isolated on transparent background, 2K resolution, suitable for a kids’ language learning app.”

输出直接是带透明通道的 PNG,省去了抠图的麻烦。

2.3 国内调用国外模型 API(可选需付费)

如果你需要批量生成代码(比如生成所有列表页的骨架),可以使用 api.bananan.cn/pricing
价格约 0.02 元/次调用,支持 GPT-5.2、Gemini 等。


三、AI 帮我写的三个个“高颜值”组件(附完整代码)

3.1 Lottie 动画组件(支持 JSON 动效,自动管理生命周期)

微信小程序原生集成 Lottie 比较麻烦,需要处理 canvas 2d 上下文、页面隐藏/显示、内存释放。我把需求扔给 AI,它直接生成了一套完整的组件。

<!-- 组件名:GlLottie -->
<template>
<viewclass="gl-lottie">
<canvas:id="canvasId"type="2d"class="gl-lottie-canvas" @click="handleCanvasClick"></canvas>
</view>
</template>

<scriptsetup>
import { nextTick, onUnmounted, getCurrentInstance, watch, markRaw } from'vue'
import { onPageShow, onPageHide } from'@dcloudio/uni-app';
import { getNodeEL } from'@/utils/index.js';
import lottie from"lottie-miniprogram";

const instance = getCurrentInstance();
const emit = defineEmits(['load''click']);
const props = defineProps({
url: { typeStringrequiredtrue },
options: { typeObjectdefault: {} },
data: { typeObjectdefault: {} }
});

const canvasId = `lottie-${instance.uid}-${Math.floor(Math.random() * 1000)}`;
let control = null, isDestroyed = false, indexId = 0;

watch(() => props.url, (newUrl) => {
  destroy();
if (newUrl) nextTick(() => init());
}, { immediatetrue });

asyncfunctioninit() {
if (!props.url) return;
const initId = ++indexId;
  isDestroyed = false;

let animationData = null;
if (props.url.toLowerCase().includes('http')) {
const res = await uni.request({ url: props.url });
if (res.statusCode === 200 && res.data) animationData = JSON.parse(JSON.stringify(res.data));
  }
if (isDestroyed || initId !== indexId) return;

let canvasEl = await getNodeEL(`#${canvasId}`, instance);
if (!canvasEl) return;
const canvas = canvasEl.node;
const context = canvas.getContext('2d');
const dpr = wx.getWindowInfo().pixelRatio;
  canvas.width = canvasEl.width * dpr;
  canvas.height = canvasEl.height * dpr;
  context.scale(dpr, dpr);

const config = {
renderer'canvas',
rendererSettings: { clearCanvastrue, context, canvas, scale1 },
loop: props.options.loop ?? true,
autoplay: props.options.autoplay ?? true,
  };
if (animationData) config.animationData = markRaw(animationData);
else config.url = props.url;

if (isDestroyed || initId !== indexId) return;
  lottie.setup(canvas);
  control = lottie.loadAnimation(config);
  control.setSubframe(false);
  emit('load', canvasEl, { control: markRaw(control), url: props.url, data: props.data });
}

functiondestroy() {
  isDestroyed = true;
if (control) {
    control.stop();
    control.destroy();
    control = null;
  }
}

onPageHide(() => control && control.pause());
onPageShow(() => control && props.options.autoplay !== false && control.play());
onUnmounted(() => destroy());
</script>

<stylescoped>
.gl-lottie { width100%height100%position: relative; }
.gl-lottie-canvas { width100%height100%will-change: transform; transformtranslateZ(0); }
</style>

3.2 Svga 加载组件

<template>
<viewclass="gu-svga">
<canvas:id="canvasId"type="2d"class="gu-svga-canvas" @click="handleCanvasClick" ></canvas>
</view>
</template>

<scriptsetup>
defineOptions({
name"GuSvga"
})
import { nextTick, onUnmounted, getCurrentInstance, watch, markRaw} from'vue'
import { getNodeEL } from'@/utils/index.js';
import {Parser,Player} from'svgaplayer-weapp'
const instance = getCurrentInstance(); // 获取当前组件实例

const emit = defineEmits(['load''click''finished']);

const props = defineProps({
// svga网络地址/相对地址(只能是svg)
url: {
typeString,
default'',
requiredtrue
  },
options: {
typeObject,
default: {}
 },
// 数据对象
data: {
typeObject,
default: {}
  }
});

// 生成唯一ID防止组件冲突
const canvasId = `svga-${instance.uid}-${Math.floor(Math.random() * 1000)}`;

let canvas = null// canvas容器
let player = null// 动画控制对象
let parser = null// 加载器
let video = null// 媒体数据
let isDestroyed = false// 标志位
let indexId = 0
watch(
() => props.url,
 (newUrl, oldUrl) => {
// 先销毁旧动画(避免内存泄漏)
  destroy();
// 确保 url 有效(非空)再初始化
if (newUrl) {
// 延迟初始化,确保 DOM 已更新
   nextTick(() => {
    init()
   });
  }
 },
 {
immediatetrue// 初始加载时立即执行一次(关键)
deepfalse// url 是字符串,无需深度监听
 }
);

asyncfunctioninit() {
if (!props.url) {
console.error('未设置url!');
return;
  }

const initId = ++indexId // 记录当前初始化的版本
 isDestroyed = false// 每次初始化重置状态

// 同步获取-canvas节点设置对应属性
let canvasEl = await getNodeEL(`#${canvasId}`, instance)
if (!canvasEl) {
console.error('canvas 元素未找到!');
return;
  }
 canvas = canvasEl.node

// 如果组件销毁则不继续执行
if(isDestroyed || initId !== indexId) return

// 动画配置
const config = {
loop: props.options.loop || true// 默认循环播放
autoplay: props.options.autoplay || true// 默认自动播放
path: props.url, // svga地址
clearsAfterStop: props.options.clearsAfterStop || false// 默认值为false,动画结束时,是否清空画布。
fillMode: props.options.fillMode || 'Forward'// 默认值为 Forward,当clearsAfterStop为 false 时,Forward 表示动画会在结束后停留在最后一帧,Backward 则会在动画结束后停留在第一帧。
contentMode: props.options.contentMode || 'AspectFit',
  }

// 初始化加载器Parser
 parser = new Parser()
try {
const data = await parser.load(config.path)

// 如果组件销毁则不继续执行
if(isDestroyed || initId !== indexId) return

  video = markRaw(data)
 } catch (e) {
console.error('SVGA加载失败', e)
return
 }

// 初始化播放器player
  player = new Player()
await player.setCanvas(`#${canvasId}`, instance)
  player.loops = config.loop ? 0 : 1// 默认循环播放
  player.clearsAfterStop = config.clearsAfterStop // 播放完成是否清空
  player.fillMode = config.fillMode // 默认值为 Forward,当clearsAfterStop为 false 时,Forward 表示动画会在结束后停留在最后一帧,Backward 则会在动画结束后停留在第一帧
  player.setContentMode(config.contentMode)

// 如果组件销毁则不继续执行
if(isDestroyed || initId !== indexId) {
  player.clear()
return
 }

await player.setVideoItem(video);

// 如果组件销毁则不继续执行
if(isDestroyed || initId !== indexId) {
  player.clear()
return
 }

if (config.autoplay) {
    player.startAnimation()
  }
  player.onFinished(() => { //只有在loop不为0时候触发
    emit('finished')
  })
  emit('load', canvasEl, {player: markRaw(player), url: props.url, data: props.data})
}

functionhandleCanvasClick(e){
 emit('click', e); // 将事件参数传递出去
}

// 辅助函数,用于安全地清理对象属性
functionsafeClearObjectProperties(obj{
if (!obj || typeof obj !== 'object'return;
for (let key in obj) {
if (obj.hasOwnProperty(key)) { // 确保是对象自身的属性
// 避免删除原型链上的属性
if (typeof obj[key] === 'object' && obj[key] !== null) {
// 如果是数组,清空它
if (Array.isArray(obj[key])) {
     obj[key].length = 0;
    } else {
// 如果是普通对象,递归清理或直接置空
     obj[key] = null;
    }
   } else {
    obj[key] = null// 直接置空
   }
  }
 }
}

functiondestroy(){
 isDestroyed = true// 标记销毁
if (player) {
  player.stopAnimation();
// 1. 彻底清空所有回调,防止闭包锁死
  player.onFinished(() => {});
  player.onFrame(() => {});
  player.onPercentage(() => {});
// 2. 尝试手动断开播放器对数据源的引用(私有属性清理)
if (player._videoItem) player._videoItem = null
if (player._canvas) player._canvas = null
if (player.images) player.images = null
  player.clear();
  player = null;
 }
 parser = null
// 手动清理 VideoItem 里的图片
if (video) {
if(video.decodedImages){
   safeClearObjectProperties(video.decodedImages)
   video.decodedImages = {}
  }
if(video.spec && video.spec.images){
   safeClearObjectProperties(video.spec.images)
   video.spec.images = {}
  }
if(video.spec && video.spec.sprites){
   video.spec.sprites.length = 0
  }
if(video.sprites){
   video.sprites.length = 0
  }
  video = null;
 }
if(canvas){
  canvas.width = 0
  canvas.height = 0
  canvas = null
 }
}

onUnmounted(()=>{
 destroy()
})
</script>

<stylescopedlang="scss">
.gu-svga{
 width: 100%;
 height: 100%;
 position: relative; /* 关键:确保在文档流中,随滚动移动 */
 .gu-svga-canvas{
  width: 100%;
  height: 100%;
  will-change: transform; /* 提示浏览器优化渲染 */
  transform: translateZ(0); /* 触发 GPU 加速 */
 }
}
</style>

3.3 礼花/飘落特效组件(三种粒子模式)

完成学习任务后,需要强烈的正向反馈。AI 为我生成了一个粒子系统组件,支持三种模式:

  • fan-explosion(扇形喷射) – 默认底部中心向四周炸开
  • volcano-eruption(火山喷发) – 底部左中右三点持续 3 秒喷射彩带
  • slow-falling-rain(缓慢飘落) – 羽毛般从上往下飘,适合做氛围
<template>
<viewclass="gu-scatter">
<canvasid="gu-scatter"type="2d"class="gu-scatter-canvas"></canvas>
</view>
</template>

<scriptsetup>
import {getNodeEL} from"@/utils/index.js";
import {getCurrentInstance, nextTick, onMounted, defineProps, defineExpose} from'vue'

defineOptions({name"GuScatter"})

const instance = getCurrentInstance()

const props = defineProps({
// 默认模式
mode: {typeStringdefault'fan-explosion'}
})

const page = {screenWidth0screenHeight0pixelRatio3}
const canvas = {instancenullctxnullwidth0height0speedScale1.0}

let imageAssets = [];
let isImagesLoaded = false;
let currentLoadedMode = ''// 记录当前已加载图片的模式,避免重复加载

let particles = [];
let animationFrameId = null;
let isActive = false;
// 新增:记录持续喷发的开始时间
let eruptionStartTime = 0;
let isErupting = false// 标记当前是否处于3秒爆发期

// ==========================================
// 策略配置字典:新增烟花方案只需要在这里添加配置
// ==========================================
const EFFECT_STRATEGIES = {
// 模式1:底部网格化扇形喷射
'fan-explosion': {
particleCount400,
// 定义该模式需要的图片素材
getImagePaths() => {
const paths = [];
for (let i = 1; i <= 30; i++) {
        paths.push(`/static/images/caidai/caidai${i}.png`);
      }
return paths;
    },
// 定义该模式的粒子运动逻辑
ParticleClassclassFanPetal{
constructor(index, totalCount, ctxInfo) {
const {width, height, images, speedScale} = ctxInfo;
this.img = images.length > 0 ? images[Math.floor(Math.random() * images.length)] : null;

const baseWidth = Math.random() * 6 + 14;
this.width = baseWidth;
this.height = this.img && this.img.width ? baseWidth * (this.img.height / this.img.width) : baseWidth;

// 发射点:底部中心
this.x = width / 2 + (Math.random() - 0.5) * 40;
this.y = height;

const gridSize = Math.ceil(Math.sqrt(totalCount));
const col = index % gridSize;
const row = Math.floor(index / gridSize);

const angleStep = 160 / gridSize;
const angleJitter = (Math.random() - 0.5) * angleStep * 1.5;
const angleRad = ((-80 + (col * angleStep) + angleJitter) * Math.PI) / 180;

const speedStep = 20 / gridSize;
const speedJitter = (Math.random() - 0.5) * speedStep * 0.8;
const velocity = (3.5 + (row * speedStep)) + speedJitter;

this.vx = Math.sin(angleRad) * velocity * speedScale;
this.vy = -Math.cos(angleRad) * velocity * speedScale;

this.friction = 0.97// 原来是 0.95
this.gravity = 0.02;  // 原来是 0.12,大幅降低,保证慢速下依然能飞得高
this.rotation = Math.random() * 360;
this.rotationSpeed = (Math.random() - 0.5) * 3// 原来是 8,调慢
this.flip = Math.random() * Math.PI;
this.flipSpeed = Math.random() * 0.08// 原来是 0.2,调慢
this.opacity = 1;
this.canvasHeight = height; // 保存画布高度用于边界判定
      }

      update() {
this.vy += this.gravity;
this.vx *= this.friction;
this.vy *= this.friction;

if (this.vy > 0.9) {
this.vy = 0.9;
        }

this.x += this.vx;
this.y += this.vy;
this.rotation += this.rotationSpeed;
this.flip += this.flipSpeed;

if (this.vy > 0 && this.vy < 2) {
this.x += Math.sin(this.y * 0.05) * 0.5;
        }
if (this.y > this.canvasHeight + 50this.opacity -= 0.05;
      }

      draw(ctx) {
if (this.opacity <= 0 || !this.img) return;
        ctx.save();
        ctx.translate(this.x, this.y);
        ctx.scale(1Math.sin(this.flip));
        ctx.rotate((this.rotation * Math.PI) / 180);
        ctx.globalAlpha = Math.max(0this.opacity);
        ctx.drawImage(this.img, -this.width / 2, -this.height / 2this.width, this.height);
        ctx.restore();
      }
    }
  },

//模式2: 火山喷发
'volcano-eruption': {
isContinuoustrue// 👈 新增这一行
duration3000,     // 👈 可以顺便把你想要的持续时间配置在这里
particleCount200,
// 加载 caidai2 目录下的 1-26 图
getImagePaths() => {
const paths = [];
for (let i = 1; i <= 26; i++) {
        paths.push(`/static/images/caidai2/caidai${i}.png`);
      }
return paths;
    },
ParticleClassclassVolcanoParticle{
constructor(index, totalCount, ctxInfo) {
const {width, height, images, speedScale} = ctxInfo;
this.img = images.length > 0 ? images[Math.floor(Math.random() * images.length)] : null;

const baseWidth = Math.random() * 8 + 16;
this.width = baseWidth;
this.height = this.img && this.img.width ? baseWidth * (this.img.height / this.img.width) : baseWidth;

// ================= 修复:三个发射点均匀分布在屏幕内 =================
const emitterType = Math.random();
// 将屏幕平均分为三分,分别在 20%、50%、80% 的 x 坐标处喷射
if (emitterType < 0.33) {
// 左侧喷发点 (屏幕 20% 处,允许 10% 的左右随机抖动)
this.x = width * 0.2 + (Math.random() - 0.5) * (width * 0.1);
this.y = height; // 紧贴屏幕底部内侧
        } elseif (emitterType < 0.66) {
// 中间喷发点 (屏幕 50% 处,允许 15% 的左右随机抖动)
this.x = width * 0.5 + (Math.random() - 0.5) * (width * 0.15);
this.y = height;
        } else {
// 右侧喷发点 (屏幕 80% 处,允许 10% 的左右随机抖动)
this.x = width * 0.8 + (Math.random() - 0.5) * (width * 0.1);
this.y = height;
        }

// ================= 初始速度 =================
// 因为横屏高度不大,初速度给 20 左右,配合空气阻力,刚好能冲到屏幕顶端悬停
const vPower = Math.random() * 15 + 15;
this.vx = (Math.random() - 0.5) * 15 * speedScale;
this.vy = -vPower * speedScale; // 负数代表猛烈向上喷射

this.lifeTime = 0;
this.gravity = 0;
this.friction = 0.95// 加上空气阻力,粒子冲到高空后会自然减速

this.terminalVelocity = Math.random() * 2 + 1// 最终飘落的速度
this.isFalling = false;

// 形态变化
this.rotation = Math.random() * 360;
this.rotationSpeed = (Math.random() - 0.5) * 12;
this.flip = Math.random() * Math.PI;
this.flipSpeed = Math.random() * 0.3;
this.opacity = 1;
this.canvasHeight = height;
      }

      update() {
this.lifeTime += 16.67;

// ================= 状态机控制 =================
// 当3秒爆发期结束,或者粒子向上冲刺的速度快耗尽时 (vy > -1 代表到顶点了),切入飘落模式
if (!isErupting || this.lifeTime > 3000 || this.vy > -1) {
if (!this.isFalling) {
this.isFalling = true;
this.gravity = 0.1// 开启重力
this.friction = 0.98// 飘落阻力
          }
        }

// ================= 物理更新 =================
this.vy += this.gravity;

// 无论是冲刺阶段还是飘落阶段,都需要一点空气阻力
this.vx *= this.friction;
this.vy *= this.friction;

if (this.isFalling) {
// 终端速度限制,维持羽毛般的飘落感
this.vy = Math.min(this.vy, this.terminalVelocity);
        }

this.x += this.vx;
this.y += this.vy;

this.rotation += this.rotationSpeed;
this.flip += this.flipSpeed;

// 只有在下落阶段,且掉出屏幕底部后才渐渐消失
if (this.isFalling && this.y > this.canvasHeight + 50) {
this.opacity -= 0.05;
        }
      }

      draw(ctx) {
if (this.opacity <= 0 || !this.img) return;
        ctx.save();
        ctx.translate(this.x, this.y);
        ctx.scale(1Math.sin(this.flip));
        ctx.rotate((this.rotation * Math.PI) / 180);
        ctx.globalAlpha = Math.max(0this.opacity);
        ctx.drawImage(this.img, -this.width / 2, -this.height / 2this.width, this.height);
        ctx.restore();
      }
    }
  },

// 模式3:满屏缓慢下落
'slow-falling-rain': {
isContinuoustrue,
duration8000,
particleCount200,
// 加载 caidai3 目录下的 1-13 图
getImagePaths() => {
const paths = [];
for (let i = 1; i <= 13; i++) {
        paths.push(`/static/images/caidai3/caidai${i}.png`);
      }
return paths;
    },
ParticleClassclassRainParticle{
constructor(index, totalCount, ctxInfo) {
const {width, height, images, speedScale} = ctxInfo;
this.img = images.length > 0 ? images[Math.floor(Math.random() * images.length)] : null;

const baseWidth = Math.random() * 8 + 16;
this.width = baseWidth;
this.height = this.img && this.img.width ? baseWidth * (this.img.height / this.img.width) : baseWidth;

// ================= 极简发射点:屏幕顶部外侧随机铺开 =================
this.x = Math.random() * width;
this.y = -Math.random() * 50 - 20// 都在屏幕顶端上方一点,避免突然闪现

// ================= 初始速度:缓慢均匀向下 =================
// vy 为正数代表向下掉落,范围在 1.5 ~ 3.5 之间,非常缓慢
this.vy = (Math.random() * 2 + 1.5) * speedScale;
// vx 给一个极小的基础左右随机速度
this.vx = (Math.random() - 0.5) * 1 * speedScale;

// 记录一个随机的摆动相位,用于产生左右摇摆的落叶感
this.swingPhase = Math.random() * Math.PI * 2;

// 形态变化(旋转速度也调慢一点,配合缓慢飘落的氛围)
this.rotation = Math.random() * 360;
this.rotationSpeed = (Math.random() - 0.5) * 4;
this.flip = Math.random() * Math.PI;
this.flipSpeed = Math.random() * 0.1;
this.opacity = 1;
this.canvasHeight = height;
      }

      update() {
// ================= 物理更新 =================
// 不需要状态机,一直往下匀速掉落即可
this.y += this.vy;

// 核心:加上正弦波计算,产生类似羽毛/纸片飘落时的左右摇曳感
this.x += this.vx + Math.sin(this.y * 0.02 + this.swingPhase) * 0.6;

this.rotation += this.rotationSpeed;
this.flip += this.flipSpeed;

// 掉出屏幕底部后渐渐消失
if (this.y > this.canvasHeight + 50) {
this.opacity -= 0.05;
        }
      }

      draw(ctx) {
if (this.opacity <= 0 || !this.img) return;
        ctx.save();
        ctx.translate(this.x, this.y);
        ctx.scale(1Math.sin(this.flip));
        ctx.rotate((this.rotation * Math.PI) / 180);
        ctx.globalAlpha = Math.max(0this.opacity);
        ctx.drawImage(this.img, -this.width / 2, -this.height / 2this.width, this.height);
        ctx.restore();
      }
    }
  }

};
// ==========================================


onMounted(() => {
  nextTick(() => {
const windowInfo = wx.getWindowInfo()
    page.screenWidth = windowInfo.windowWidth
    page.screenHeight = windowInfo.screenHeight
    page.pixelRatio = windowInfo.pixelRatio
    initCanvas()
  })
})

asyncfunctioninitCanvas() {
  canvas.width = page.screenWidth
  canvas.height = page.screenHeight
let canvasEl = await getNodeEL('
#gu-scatter', instance)
if (!canvasEl) return;

  canvas.instance = canvasEl.node
  canvas.ctx = canvas.instance.getContext('2d')
if (!canvas.ctx) return;

const dpr = page.pixelRatio
  canvas.instance.width = canvasEl.width * dpr
  canvas.instance.height = canvasEl.height * dpr
  canvas.ctx.scale(dpr, dpr)
}

// 动态加载对应模式的图片素材
asyncfunctionpreloadImagesForMode(modeName{
const strategy = EFFECT_STRATEGIES[modeName];
if (!strategy) returnfalse;

const paths = strategy.getImagePaths();
  imageAssets = [];
const loadPromises = paths.map(src => {
returnnewPromise((resolve) => {
const img = canvas.instance.createImage();
      img.onload = () => { imageAssets.push(img); resolve(); };
      img.onerror = () => { resolve(); };
      img.src = src;
    });
  });

awaitPromise.all(loadPromises);
  isImagesLoaded = true;
  currentLoadedMode = modeName;
returntrue;
}

const requestAnimFrame = (cb) => canvas.instance.requestAnimationFrame(cb);
const cancelAnimFrame = (id) => canvas.instance.cancelAnimationFrame(id);

const loop = () => {
if (!isActive) return;
  canvas.ctx.clearRect(00, canvas.width, canvas.height);

const strategy = EFFECT_STRATEGIES[currentLoadedMode];
if(!strategy) { isActive = falsereturn; }

// === 核心修复:只有被标记为“持续喷发”的模式,才会在循环中造粒子 ===
if (strategy.isContinuous) {
const currentTime = Date.now();
const duration = strategy.duration || 5000// 读取配置的时间,默认5秒
if (currentTime - eruptionStartTime < duration) {
      isErupting = true;
    } else {
      isErupting = false;
    }

if (isErupting) {
const ctxInfo = { width: canvas.width, height: canvas.height, images: imageAssets, speedScale: canvas.speedScale };
for (let i = 0; i < 3; i++) {
        particles.push(new strategy.ParticleClass(particles.length, 0, ctxInfo));
      }
    }
  } else {
// 一次性模式不需要爆发状态机
    isErupting = false;
  }

// 更新和绘制所有粒子
let activeCount = 0;
for (let i = 0; i < particles.length; i++) {
    particles[i].update();
    particles[i].draw(canvas.ctx);
if (particles[i].opacity > 0) activeCount++;
  }

// 彻底结束的判定
if (activeCount === 0 && !isErupting) {
    isActive = false;
    animationFrameId = null;
    particles = [];
    canvas.ctx.clearRect(00, canvas.width, canvas.height);
  } else {
    animationFrameId = requestAnimFrame(loop);
  }
};

const startFalling = async (targetMode) => {
const modeToUse = targetMode || props.mode;
const strategy = EFFECT_STRATEGIES[modeToUse];

if (!strategy) {
console.error(`未找到对应烟花模式: ${modeToUse}`);
return;
  }

if (!canvas.instance) return;
if (!isImagesLoaded || currentLoadedMode !== modeToUse) {
await preloadImagesForMode(modeToUse);
  }

  isActive = true;
if (animationFrameId) cancelAnimFrame(animationFrameId);
  particles = [];
  eruptionStartTime = Date.now();
  isErupting = true;

// === 核心修复:如果是“一次性炸开”的模式(如默认扇形),在这里瞬间生成所有粒子 ===
if (!strategy.isContinuous) {
const ctxInfo = { width: canvas.width, height: canvas.height, images: imageAssets, speedScale: canvas.speedScale };
const count = strategy.particleCount;
for (let i = 0; i < count; i++) {
      particles.push(new strategy.ParticleClass(i, count, ctxInfo));
    }
  }

  loop();
};

defineExpose({
  startFalling
})
</script>

<stylescopedlang="scss">
.gu-scatter {
  position: absolute;
  width: 100vw;
  height: 100vh;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 9999;

  .gu-scatter-canvas {
    width: 100%;
    height: 100%;
  }
}
</style>

四、如何用 Gemini 生成全套素材(实操流程)

4.1 生成背景图

提示词示例:“A soft pastel gradient background for a children's language learning app, light yellow to mint green, no text, 2K, flat design.”

输出直接作为页面基底。

4.2 生成彩带动画序列帧

为礼花组件生成 30 张 PNG:“Generate 30 different colorful ribbon/confetti sprites, each isolated on transparent background, varied shapes and colors, high resolution, cartoon style.”

Gemini 支持批量风格锁定,一次生成多张,保持风格一致。

4.3 生成单词卡片插图

例如生成“猫”、“狗”、“蜜蜂”:“Cute cartoon cat, simple flat illustration, pastel colors, transparent background, 2K, no shadow.”

注意:gemini-3-pro-image-preview-2k 目前免费,但有每天请求次数限制,建议合理分配。

五、开发心得与避坑指南

AI 生成代码 ≠ 直接上线
要检查生命周期(如微信小程序 onPageHide 暂停动画、onUnmounted 释放 canvas),AI 有时会遗漏,须人工补全。

生图提示词要“啰嗦”
必须加上“transparent background”、“2K”、“consistent style”等关键词,否则容易跑偏。

组件按需暴露方法
礼花组件要用 defineExpose({ startFalling }),父组件才能调用,AI 默认不会加,记得手动补充。

性能优化
粒子数量控制(200~400 足够),requestAnimationFrame 在页面隐藏时必须取消,否则后台耗电。

六、总结与体验入口

借助 arena.ai 的免费聊天模型 + gemini-3-pro-image-preview-2k 生图模型,我一个后端开发者,零 UI 设计能力,快速就完成了 Dino Kids 小程序的完整开发与素材制作。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-05-12 22:20:20 HTTP/2.0 GET : https://g.sjds.net/a/458490.html
  2. 运行时间 : 0.653525s [ 吞吐率:1.53req/s ] 内存消耗:4,487.44kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=1533397ebbe864f271167fe5eaa577e1
  1. /yingpanguazai/ssd/ssd1/www/g.sjds.net/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/g.sjds.net/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/g.sjds.net/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/g.sjds.net/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/g.sjds.net/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/g.sjds.net/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/g.sjds.net/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/g.sjds.net/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/g.sjds.net/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/g.sjds.net/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/g.sjds.net/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/g.sjds.net/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/g.sjds.net/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/g.sjds.net/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/g.sjds.net/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/g.sjds.net/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/g.sjds.net/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/g.sjds.net/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/g.sjds.net/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/g.sjds.net/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/g.sjds.net/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/g.sjds.net/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/g.sjds.net/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/g.sjds.net/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/g.sjds.net/runtime/temp/8321bd4d2de6fe7dffb246d4ae0c61fd.php ( 12.06 KB )
  140. /yingpanguazai/ssd/ssd1/www/g.sjds.net/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000602s ] mysql:host=127.0.0.1;port=3306;dbname=g_sjds;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000802s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.100802s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.100775s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000653s ]
  6. SELECT * FROM `set` [ RunTime:0.100532s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000730s ]
  8. SELECT * FROM `article` WHERE `id` = 458490 LIMIT 1 [ RunTime:0.014687s ]
  9. UPDATE `article` SET `lasttime` = 1778595620 WHERE `id` = 458490 [ RunTime:0.059428s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.036128s ]
  11. SELECT * FROM `article` WHERE `id` < 458490 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.016925s ]
  12. SELECT * FROM `article` WHERE `id` > 458490 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.005026s ]
  13. SELECT * FROM `article` WHERE `id` < 458490 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.088034s ]
  14. SELECT * FROM `article` WHERE `id` < 458490 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.048672s ]
  15. SELECT * FROM `article` WHERE `id` < 458490 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.006085s ]
0.656158s