feat: add emoji to pot animation

This commit is contained in:
YunYouJun
2022-04-17 03:27:55 +08:00
parent 7163fd350b
commit bbd9f840b5
5 changed files with 86 additions and 21 deletions

1
src/components.d.ts vendored
View File

@@ -5,6 +5,7 @@ import '@vue/runtime-core'
declare module '@vue/runtime-core' { declare module '@vue/runtime-core' {
export interface GlobalComponents { export interface GlobalComponents {
AnimateStuff: typeof import('./components/AnimateStuff.vue')['default']
BaseFooter: typeof import('./components/BaseFooter.vue')['default'] BaseFooter: typeof import('./components/BaseFooter.vue')['default']
ChooseFood: typeof import('./components/ChooseFood.vue')['default'] ChooseFood: typeof import('./components/ChooseFood.vue')['default']
Counter: typeof import('./components/Counter.vue')['default'] Counter: typeof import('./components/Counter.vue')['default']

View File

@@ -0,0 +1,18 @@
<template>
<span class="animate-stuff" w="4" h="4">
<slot />
</span>
</template>
<style>
.animate-stuff {
visibility: hidden;
position: absolute;
z-index: 10;
top: 0;
left: 0;
border-radius: 50%;
background: #02b6fd;
transition: left .6s linear, top .6s cubic-bezier(0.5, -0.5, 1, 1);
}
</style>

View File

@@ -1,5 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useGtm } from '@gtm-support/vue-gtm' import { useGtm } from '@gtm-support/vue-gtm'
import AnimateStuff from './AnimateStuff.vue'
import type { StuffItem } from '~/data/food' import type { StuffItem } from '~/data/food'
import { meat, staple, tools, vegetable } from '~/data/food' import { meat, staple, tools, vegetable } from '~/data/food'
import recipeData from '~/data/recipe.json' import recipeData from '~/data/recipe.json'
@@ -32,17 +33,52 @@ const displayedRecipe = computed(() => {
}) })
}) })
const { x, y } = usePointer()
const animateStuff = ref()
const recipeBtn = ref<HTMLButtonElement>()
const { top, left } = useElementBounding(recipeBtn)
const playAnimation = () => {
if (animateStuff.value) {
const el = animateStuff.value.$el
el.style.visibility = 'visible'
el.style.top = `${y.value}px`
el.style.left = `${x.value}px`
el.style.transition = 'none'
setTimeout(() => {
el.style.visibility = 'visible'
el.style.top = `${top.value}px`
el.style.left = `${left.value}px`
el.style.transition = 'left .4s linear, top .4s cubic-bezier(0.5, -0.5, 1, 1)'
}, 0)
el.ontransitionend = () => {
el.style.visibility = 'hidden'
}
}
}
const gtm = useGtm() const gtm = useGtm()
const toggleStuff = (item: StuffItem, category = '') => { const curEmoji = ref('')
const toggleStuff = (item: StuffItem, category = '', e?: Event) => {
rStore.toggleStuff(item.name)
if (curStuff.value.includes(item.name)) {
playAnimation()
curEmoji.value = item.emoji
}
gtm?.trackEvent({ gtm?.trackEvent({
event: 'click', event: 'click',
category: `${category}_${item.name}`, category: `${category}_${item.name}`,
action: 'click_stuff', action: 'click_stuff',
label: '食材', label: '食材',
}) })
rStore.toggleStuff(item.name)
} }
/** /**
@@ -53,6 +89,11 @@ const clickTool = (item: StuffItem) => {
const value = item.name const value = item.name
rStore.toggleTools(value) rStore.toggleTools(value)
if (curTools.value.includes(value)) {
playAnimation()
curEmoji.value = item.emoji
}
gtm?.trackEvent({ gtm?.trackEvent({
event: 'click', event: 'click',
category: `tool_${value}`, category: `tool_${value}`,
@@ -66,16 +107,26 @@ const { isVisible, show } = useInvisibleElement(recipePanel)
</script> </script>
<template> <template>
<Transition>
<AnimateStuff ref="animateStuff">
{{ curEmoji }}
</AnimateStuff>
</Transition>
<Transition> <Transition>
<button <button
v-if="displayedRecipe.length !== recipe.length && displayedRecipe.length && !isVisible" v-if="displayedRecipe.length !== recipe.length && isVisible"
class="fixed inline-flex justify-center items-center rounded rounded-full shadow hover:shadow-md" ref="recipeBtn"
class="cursor-pointer fixed inline-flex justify-center items-center rounded rounded-full shadow hover:shadow-md"
bg="green-50" w="10" h="10" bottom="4" right="4" bg="green-50" w="10" h="10" bottom="4" right="4"
text="green-600" text="green-600"
@click="show" @click="show"
> >
<!-- <div i-mdi-bowl-mix-outline /> --> <span v-if="displayedRecipe.length">
🍲 <div i-mdi-bowl-mix-outline />
</span>
<span v-else>
<div i-mdi-bowl-outline />
</span>
</button> </button>
</Transition> </Transition>
@@ -89,7 +140,7 @@ const { isVisible, show } = useInvisibleElement(recipePanel)
<VegetableTag <VegetableTag
v-for="item, i in vegetable" :key="i" v-for="item, i in vegetable" :key="i"
:active="curStuff.includes(item.name)" :active="curStuff.includes(item.name)"
@click="toggleStuff(item, 'vegetable')" @click="() => toggleStuff(item, 'vegetable')"
> >
<span v-if="item.emoji" class="inline-flex">{{ item.emoji }}</span> <span v-if="item.emoji" class="inline-flex">{{ item.emoji }}</span>
<span v-else-if="item.image" class="inline-flex"> <span v-else-if="item.image" class="inline-flex">
@@ -177,11 +228,6 @@ const { isVisible, show } = useInvisibleElement(recipePanel)
大胆尝试一下或者<a href="#" @click="rStore.reset()"> 大胆尝试一下或者<a href="#" @click="rStore.reset()">
<strong>换个组合</strong></a> <strong>换个组合</strong></a>
</span> </span>
<br>
<a m="t-4" border="b-1 dashed" class="inline-flex text-sm text-blue-600 dark:text-blue-400" href="https://docs.qq.com/sheet/DZUpJS0tQZm1YYWlt?referrer=1&tab=mwn1v5" target="_blank">
更多囤货水培攻略隔离食用手册大全
</a>
</div> </div>
</Transition> </Transition>
</div> </div>

View File

@@ -1,6 +1,5 @@
import { useElementBounding, useIntersectionObserver } from '@vueuse/core' import { useElementBounding } from '@vueuse/core'
import type { Ref } from 'vue' import type { Ref } from 'vue'
import { ref } from 'vue'
/** /**
* trigger show invisible element * trigger show invisible element
@@ -8,15 +7,13 @@ import { ref } from 'vue'
* @returns * @returns
*/ */
export function useInvisibleElement(target: Ref<HTMLElement>) { export function useInvisibleElement(target: Ref<HTMLElement>) {
const isVisible = ref(false)
const { top } = useElementBounding(target) const { top } = useElementBounding(target)
useIntersectionObserver(target, ([{ isIntersecting }]) => {
isVisible.value = isIntersecting const isVisible = computed(() => {
return window.scrollY < top.value
}) })
const show = () => { const show = () => {
// scroll when collapse is not visible
if (!isVisible.value)
window.scrollTo(0, top.value) window.scrollTo(0, top.value)
} }

View File

@@ -19,6 +19,9 @@ const rStore = useRecipeStore()
</p> </p>
<p> <p>
<ChooseFood /> <ChooseFood />
<a m="t-2" border="b-1 dashed" class="inline-flex text-sm text-blue-600 dark:text-blue-400" href="https://docs.qq.com/sheet/DZUpJS0tQZm1YYWlt?referrer=1&tab=mwn1v5" target="_blank">
更多囤货水培攻略隔离食用手册大全
</a>
</p> </p>
</div> </div>
</template> </template>