mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-18 20:09:27 +08:00
临界信息
This commit is contained in:
parent
8517dbdabf
commit
9771247b79
2
components.d.ts
vendored
2
components.d.ts
vendored
@ -8,7 +8,7 @@ export {}
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface GlobalComponents {
|
||||
ADivider: typeof import('ant-design-vue/es')['Divider']
|
||||
BookOne: typeof import('./src/components/bookOne.vue')['default']
|
||||
ASlider: typeof import('ant-design-vue/es')['Slider']
|
||||
BoxAnimate: typeof import('./src/components/boxAnimate.vue')['default']
|
||||
EnemyOne: typeof import('./src/components/enemyOne.vue')['default']
|
||||
Scroll: typeof import('./src/components/scroll.vue')['default']
|
||||
|
@ -15,7 +15,7 @@
|
||||
<meta name="x5-orientation" content="portrait">
|
||||
<meta name="x5-fullscreen" content="true">
|
||||
<meta name="x5-page-mode" content="app">
|
||||
<link type='text/css' href='styles.css' rel='stylesheet'>
|
||||
<link type='text/css' href='/styles.css' rel='stylesheet'>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -14,6 +14,7 @@
|
||||
"@ant-design/icons-vue": "^6.1.0",
|
||||
"ant-design-vue": "^3.2.13",
|
||||
"axios": "^1.1.3",
|
||||
"chart.js": "^4.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"lz-string": "^1.4.4",
|
||||
"mutate-animate": "^0.1.0",
|
||||
|
@ -12,6 +12,7 @@ specifiers:
|
||||
'@vitejs/plugin-vue-jsx': ^2.1.1
|
||||
ant-design-vue: ^3.2.13
|
||||
axios: ^1.1.3
|
||||
chart.js: ^4.0.1
|
||||
compressing: ^1.6.2
|
||||
fontmin: ^0.9.9
|
||||
form-data: ^4.0.0
|
||||
@ -32,6 +33,7 @@ dependencies:
|
||||
'@ant-design/icons-vue': 6.1.0_vue@3.2.45
|
||||
ant-design-vue: 3.2.15_vue@3.2.45
|
||||
axios: 1.1.3
|
||||
chart.js: 4.0.1
|
||||
lodash: 4.17.21
|
||||
lz-string: 1.4.4
|
||||
mutate-animate: 0.1.0
|
||||
@ -1069,6 +1071,11 @@ packages:
|
||||
supports-color: 5.5.0
|
||||
dev: true
|
||||
|
||||
/chart.js/4.0.1:
|
||||
resolution: {integrity: sha512-5/8/9eBivwBZK81mKvmIwTb2Pmw4D/5h1RK9fBWZLLZ8mCJ+kfYNmV9rMrGoa5Hgy2/wVDBMLSUDudul2/9ihA==}
|
||||
engines: {pnpm: ^7.0.0}
|
||||
dev: false
|
||||
|
||||
/chokidar/3.5.3:
|
||||
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
||||
engines: {node: '>= 8.10.0'}
|
||||
|
File diff suppressed because it is too large
Load Diff
3910
public/libs/ui.js
3910
public/libs/ui.js
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@ var enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 =
|
||||
"blackSlime": {"name":"青头怪","hp":170,"atk":20,"def":8,"money":0,"exp":3,"point":0,"special":[]},
|
||||
"slimelord": {"name":"粘液王","hp":200,"atk":58,"def":24,"money":0,"exp":8,"point":0,"special":[]},
|
||||
"bat": {"name":"小蝙蝠","hp":60,"atk":15,"def":0,"money":0,"exp":2,"point":0,"special":[4]},
|
||||
"bigBat": {"name":"大蝙蝠","hp":150,"atk":17,"def":5,"money":0,"exp":4,"point":0,"special":[4]},
|
||||
"bigBat": {"name":"大蝙蝠","hp":150,"atk":17,"def":5,"money":0,"exp":4,"point":0,"special":[4,5,6],"crit":0,"charge":0,"courage":0,"together":0,"hungry":0,"value":100,"n":1000},
|
||||
"redBat": {"name":"恐怖蝙蝠","hp":1200,"atk":260,"def":110,"money":1,"exp":32,"point":0,"special":[5]},
|
||||
"vampire": {"name":"冥灵魔王","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
||||
"skeleton": {"name":"骷髅人","hp":300,"atk":80,"def":10,"money":0,"exp":9,"point":0,"special":[1],"crit":300},
|
||||
|
@ -9311,5 +9311,10 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
}
|
||||
return res;
|
||||
}
|
||||
},
|
||||
"uiChange": function () {
|
||||
ui.prototype.drawBook = function () {
|
||||
return core.plugin.bookOpened.value = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -33,12 +33,13 @@ onMounted(() => {
|
||||
c.height *= scale;
|
||||
ctx.scale(scale, scale);
|
||||
|
||||
const fn = (time: number) => {
|
||||
const fn = () => {
|
||||
core.clearMap(ctx);
|
||||
const frame = core.status.globalAnimateStatus % frames;
|
||||
core.drawIcon(ctx, props.id, 0, 0, props.width, props.height, frame);
|
||||
};
|
||||
|
||||
fn();
|
||||
addAnimate(fn);
|
||||
|
||||
onUnmounted(() => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="enemy-container">
|
||||
<div class="enemy-container" @click="select">
|
||||
<div class="info">
|
||||
<div class="leftbar">
|
||||
<span class="name">{{ enemy.name }}</span>
|
||||
@ -24,7 +24,7 @@
|
||||
<a-divider
|
||||
type="vertical"
|
||||
dashed
|
||||
style="height: 100%; margin: 0 3% 0 3%; border-color: #ddd4"
|
||||
style="height: 100%; margin: 0 3% 0 1%; border-color: #ddd4"
|
||||
></a-divider>
|
||||
<div class="rightbar">
|
||||
<div class="detail">
|
||||
@ -66,9 +66,9 @@
|
||||
<div class="detail-info">
|
||||
<span style="color: cyan"
|
||||
>{{
|
||||
core.status.thisMap.ratio
|
||||
core.formatBigNumber(core.status.thisMap.ratio)
|
||||
}}防 {{
|
||||
core.formatBigNumber(enemy.money)
|
||||
core.formatBigNumber(enemy.defDamage)
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
@ -120,7 +120,18 @@ const props = defineProps<{
|
||||
enemy: Enemy & DetailedEnemy;
|
||||
}>();
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'select'): void;
|
||||
}>();
|
||||
|
||||
const core = window.core;
|
||||
|
||||
/**
|
||||
* 选择这个怪物时
|
||||
*/
|
||||
function select(e: MouseEvent) {
|
||||
emits('select');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@ -146,13 +157,14 @@ const core = window.core;
|
||||
}
|
||||
|
||||
.leftbar {
|
||||
width: 10%;
|
||||
width: 15%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.3vw;
|
||||
font-size: 2vh;
|
||||
padding-left: 1%;
|
||||
}
|
||||
|
||||
.name {
|
||||
@ -168,11 +180,14 @@ const core = window.core;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: block;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-items: space-between;
|
||||
}
|
||||
|
||||
.rightbar {
|
||||
font-size: 1.3vw;
|
||||
font-size: 2.5vh;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 1.5vh 0 1.5vh 0;
|
||||
@ -184,7 +199,7 @@ const core = window.core;
|
||||
height: 100%;
|
||||
|
||||
.detail-info {
|
||||
flex-basis: 33%;
|
||||
flex-basis: 33.3%;
|
||||
line-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -192,4 +207,14 @@ const core = window.core;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.rightbar {
|
||||
font-size: 4vw;
|
||||
}
|
||||
|
||||
.leftbar {
|
||||
font-size: 2vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -11,10 +11,17 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, onUnmounted, onUpdated } from 'vue';
|
||||
import { useDrag, useWheel } from '../plugin/use';
|
||||
import { cancelGlobalDrag, isMobile, useDrag, useWheel } from '../plugin/use';
|
||||
|
||||
const props = defineProps<{
|
||||
now?: number;
|
||||
type?: 'vertical' | 'horizontal';
|
||||
drag?: boolean;
|
||||
}>();
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'update:now', value: number): void;
|
||||
(e: 'update:drag', value: boolean): void;
|
||||
}>();
|
||||
|
||||
let now = 0;
|
||||
@ -44,6 +51,7 @@ function draw() {
|
||||
} else if (now < 0) {
|
||||
now = 0;
|
||||
}
|
||||
emits('update:now', now);
|
||||
const length =
|
||||
Math.min(ctx.canvas[canvasAttr] / total / scale, 1) *
|
||||
ctx.canvas[canvasAttr];
|
||||
@ -52,12 +60,12 @@ function draw() {
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||
ctx.beginPath();
|
||||
if (props.type === 'horizontal') {
|
||||
ctx.moveTo(Math.max(py + 5, 5), 20 * scale);
|
||||
ctx.lineTo(Math.min(py + length - 5, ctx.canvas.width - 5), 20 * scale);
|
||||
ctx.moveTo(Math.max(py + 5, 5), 10 * scale);
|
||||
ctx.lineTo(Math.min(py + length - 5, ctx.canvas.width - 5), 10 * scale);
|
||||
} else {
|
||||
ctx.moveTo(20 * scale, Math.max(py + 5, 5));
|
||||
ctx.moveTo(10 * scale, Math.max(py + 5, 5));
|
||||
ctx.lineTo(
|
||||
20 * scale,
|
||||
10 * scale,
|
||||
Math.min(py + length - 5, ctx.canvas.height - 5)
|
||||
);
|
||||
}
|
||||
@ -81,10 +89,35 @@ function scroll() {
|
||||
}
|
||||
|
||||
onUpdated(() => {
|
||||
now = props.now ?? now;
|
||||
calHeight();
|
||||
draw();
|
||||
});
|
||||
|
||||
let last: number;
|
||||
let contentLast: number;
|
||||
|
||||
function canvasDrag(x: number, y: number) {
|
||||
emits('update:drag', true);
|
||||
const d = props.type === 'horizontal' ? x : y;
|
||||
const dy = d - last;
|
||||
last = d;
|
||||
if (ctx.canvas[canvasAttr] < total * scale)
|
||||
now += ((dy * total) / ctx.canvas[canvasAttr]) * scale;
|
||||
content.style.transition = '';
|
||||
scroll();
|
||||
}
|
||||
|
||||
function contentDrag(x: number, y: number) {
|
||||
emits('update:drag', true);
|
||||
const d = props.type === 'horizontal' ? x : y;
|
||||
const dy = d - contentLast;
|
||||
contentLast = d;
|
||||
if (ctx.canvas[canvasAttr] < total * scale) now -= dy;
|
||||
content.style.transition = '';
|
||||
scroll();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const div = document.getElementById(`scroll-div-${id}`) as HTMLDivElement;
|
||||
const canvas = document.getElementById(`scroll-${id}`) as HTMLCanvasElement;
|
||||
@ -96,7 +129,7 @@ onMounted(() => {
|
||||
content.addEventListener('resize', resize);
|
||||
|
||||
const style = getComputedStyle(canvas);
|
||||
canvas.width = 40 * scale;
|
||||
canvas.width = 20 * scale;
|
||||
canvas.height = parseFloat(style.height) * scale;
|
||||
|
||||
if (props.type === 'horizontal') {
|
||||
@ -105,59 +138,44 @@ onMounted(() => {
|
||||
canvas.style.width = '98%';
|
||||
canvas.style.margin = '0 1% 0 1%';
|
||||
canvas.width = parseFloat(style.width) * scale;
|
||||
canvas.height = 40 * scale;
|
||||
canvas.height = 20 * scale;
|
||||
}
|
||||
|
||||
draw();
|
||||
|
||||
let last: number;
|
||||
let contentLast: number;
|
||||
|
||||
// 绑定滚动条拖拽事件
|
||||
useDrag(
|
||||
canvas,
|
||||
(x, y) => {
|
||||
const d = props.type === 'horizontal' ? x : y;
|
||||
const dy = d - last;
|
||||
last = d;
|
||||
if (canvas[canvasAttr] < total * scale)
|
||||
now += ((dy * total) / canvas[canvasAttr]) * scale;
|
||||
content.style.transition = '';
|
||||
scroll();
|
||||
},
|
||||
canvasDrag,
|
||||
(x, y) => {
|
||||
last = props.type === 'horizontal' ? x : y;
|
||||
},
|
||||
() => {
|
||||
setTimeout(() => emits('update:drag', false));
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
// 绑定文本拖拽事件
|
||||
useDrag(
|
||||
content,
|
||||
(x, y) => {
|
||||
const d = props.type === 'horizontal' ? x : y;
|
||||
const dy = d - contentLast;
|
||||
contentLast = d;
|
||||
if (canvas[canvasAttr] < total * scale) now -= dy;
|
||||
content.style.transition = '';
|
||||
scroll();
|
||||
},
|
||||
contentDrag,
|
||||
(x, y) => {
|
||||
contentLast = props.type === 'horizontal' ? x : y;
|
||||
},
|
||||
() => {
|
||||
setTimeout(() => emits('update:drag', false));
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
useWheel(content, (x, y) => {
|
||||
const d = x !== 0 ? x : y;
|
||||
if (!core.domStyle.isVertical) {
|
||||
if (Math.abs(d) > 50) {
|
||||
content.style.transition = `${cssTarget} 0.2s ease-out`;
|
||||
}
|
||||
if (Math.abs(d) > 50) {
|
||||
content.style.transition = `${cssTarget} 0.2s ease-out`;
|
||||
} else {
|
||||
content.style.transition = '';
|
||||
}
|
||||
|
||||
now += d;
|
||||
scroll();
|
||||
});
|
||||
@ -165,16 +183,15 @@ onMounted(() => {
|
||||
|
||||
onUnmounted(() => {
|
||||
content.removeEventListener('resize', resize);
|
||||
cancelGlobalDrag(canvasDrag);
|
||||
cancelGlobalDrag(contentDrag);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.scroll {
|
||||
opacity: 0.2;
|
||||
width: 40px;
|
||||
height: 98%;
|
||||
margin-top: 1%;
|
||||
margin-bottom: 1%;
|
||||
width: 20px;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
|
||||
|
193
src/panel/enemyCritical.vue
Normal file
193
src/panel/enemyCritical.vue
Normal file
@ -0,0 +1,193 @@
|
||||
<template>
|
||||
<div id="critical-main">
|
||||
<div id="critical">
|
||||
<div class="des">加攻伤害</div>
|
||||
<canvas ref="critical" class="chart"></canvas>
|
||||
<div class="slider-div">
|
||||
<span>加攻数值 {{ addAtk }}</span>
|
||||
<a-slider
|
||||
class="slider"
|
||||
v-model:value="addAtk"
|
||||
:max="(originCri.at(-1)?.[0] ?? 2) - 1"
|
||||
></a-slider>
|
||||
<span
|
||||
>最大值 {{
|
||||
(originCri.at(-1)?.[0] ?? 2) - 1
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<a-divider
|
||||
dashed
|
||||
style="width: 100%; border-color: #ddd4; margin: 1vh 0 1vh 0"
|
||||
></a-divider>
|
||||
<div id="def">
|
||||
<div class="des">加防伤害</div>
|
||||
<canvas ref="def" class="chart"></canvas>
|
||||
<div class="slider-div">
|
||||
<span>加防数值 {{ addDef }}</span>
|
||||
<a-slider
|
||||
class="slider"
|
||||
v-model:value="addDef"
|
||||
:max="(originDef.at(-1)?.[0] ?? 2) - 1"
|
||||
></a-slider>
|
||||
<span
|
||||
>最大值 {{
|
||||
(originDef.at(-1)?.[0] ?? 2) - 1
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div id="now-damage">
|
||||
<span
|
||||
>当前加攻 {{
|
||||
format(addAtk * ratio)
|
||||
}}</span
|
||||
>
|
||||
<span
|
||||
>当前加防 {{
|
||||
format(addDef * ratio)
|
||||
}}</span
|
||||
>
|
||||
<span
|
||||
>当前减伤 {{
|
||||
format(nowDamage[0], false, nowDamage[0] < 0)
|
||||
}}</span
|
||||
>
|
||||
<span
|
||||
>当前伤害 {{
|
||||
format(nowDamage[1])
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { getCriticalDamage, getDefDamage } from '../plugin/book';
|
||||
import Chart, { ChartConfiguration } from 'chart.js/auto';
|
||||
import { has, setCanvasSize } from '../plugin/utils';
|
||||
|
||||
const critical = ref<HTMLCanvasElement>();
|
||||
const def = ref<HTMLCanvasElement>();
|
||||
|
||||
const enemy = core.plugin.bookDetailEnemy;
|
||||
|
||||
const originCri = getCriticalDamage(enemy);
|
||||
const originDef = getDefDamage(enemy);
|
||||
|
||||
// 当前数据
|
||||
const allCri = ref(originCri);
|
||||
const allDef = ref(originDef);
|
||||
|
||||
// 加攻加防数量
|
||||
const addAtk = ref(0);
|
||||
const addDef = ref(0);
|
||||
|
||||
const originDamage = core.getDamageInfo(enemy);
|
||||
|
||||
// 转发core上的内容至当前作用域
|
||||
const format = core.formatBigNumber;
|
||||
const ratio = core.status.thisMap.ratio;
|
||||
|
||||
const nowDamage = computed(() => {
|
||||
const dam = core.getDamageInfo(enemy, {
|
||||
atk: core.status.hero.atk + addAtk.value,
|
||||
def: core.status.hero.def + addDef.value
|
||||
});
|
||||
if (!has(dam)) return ['???', '???'];
|
||||
if (!has(originDamage)) return [-dam.damage, dam.damage];
|
||||
return [originDamage.damage - dam.damage, dam.damage];
|
||||
});
|
||||
|
||||
function generateChart(ele: HTMLCanvasElement, data: [number, number][]) {
|
||||
const config: ChartConfiguration = {
|
||||
type: 'line',
|
||||
data: generateData(data)
|
||||
};
|
||||
return new Chart(ele, config);
|
||||
}
|
||||
|
||||
function generateData(data: [number, number][]) {
|
||||
return {
|
||||
datasets: [
|
||||
{
|
||||
label: '怪物伤害',
|
||||
data: data.map(v => v[1])
|
||||
}
|
||||
],
|
||||
labels: data.map(v => v[0])
|
||||
};
|
||||
}
|
||||
|
||||
function update(atk: Chart, def: Chart) {
|
||||
allCri.value = getCriticalDamage(enemy, addAtk.value, addDef.value);
|
||||
allDef.value = getDefDamage(enemy, addDef.value, addAtk.value);
|
||||
|
||||
atk.data = generateData(allCri.value);
|
||||
def.data = generateData(allDef.value);
|
||||
atk.update('resize');
|
||||
def.update('resize');
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const div = document.getElementById('critical-main') as HTMLDivElement;
|
||||
const style = getComputedStyle(div);
|
||||
|
||||
const width = parseFloat(style.width);
|
||||
const height = window.innerHeight / 5;
|
||||
const c = critical.value!;
|
||||
const d = def.value!;
|
||||
|
||||
setCanvasSize(c, width, height);
|
||||
setCanvasSize(d, width, height);
|
||||
|
||||
const criChart = generateChart(c, allCri.value);
|
||||
const defChart = generateChart(d, allDef.value);
|
||||
|
||||
watch(addAtk, n => {
|
||||
update(criChart, defChart);
|
||||
});
|
||||
|
||||
watch(addDef, n => {
|
||||
update(criChart, defChart);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#critical-main {
|
||||
width: 100%;
|
||||
height: 50vh;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.des {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 2.5vh;
|
||||
}
|
||||
|
||||
.slider-div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
font-size: 1.1vw;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.slider {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
#now-damage {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
font-size: 3vh;
|
||||
}
|
||||
</style>
|
94
src/panel/enemySpecial.vue
Normal file
94
src/panel/enemySpecial.vue
Normal file
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<div id="special-main">
|
||||
<Scroll id="special-scroll">
|
||||
<div id="special">
|
||||
<component :is="info"></component>
|
||||
</div>
|
||||
</Scroll>
|
||||
<a-divider
|
||||
dashed
|
||||
style="margin: 2vh 0 2vh 0; border-color: #ddd4"
|
||||
></a-divider>
|
||||
<div id="critical">
|
||||
<div style="font-size: 2.5vh; width: 100%; text-align: center">
|
||||
临界表
|
||||
</div>
|
||||
<div id="critical-main">
|
||||
<div id="critical-des">
|
||||
<span>加攻</span>
|
||||
<span>减伤</span>
|
||||
</div>
|
||||
<div v-for="[atk, dam] of criticals" class="critical">
|
||||
<span class="critical-atk">{{ format(atk) }}</span>
|
||||
<span>{{
|
||||
dam < 0 ? `-> ${format(-dam)}` : format(dam)
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { isMobile } from '../plugin/use';
|
||||
import { getSpecialHint } from '../plugin/book';
|
||||
|
||||
const enemy = core.plugin.bookDetailEnemy;
|
||||
|
||||
const info = getSpecialHint(enemy);
|
||||
|
||||
const criticals = core.nextCriticals(enemy, isMobile ? 4 : 8);
|
||||
|
||||
const format = core.formatBigNumber;
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#special-main {
|
||||
width: 100%;
|
||||
user-select: none;
|
||||
font-size: 2em;
|
||||
position: absolute;
|
||||
top: 20vh;
|
||||
}
|
||||
|
||||
#critical-main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#critical-des,
|
||||
.critical {
|
||||
font-size: 1.6vw;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.critical-atk {
|
||||
border-bottom: 1px solid #ddd4;
|
||||
}
|
||||
|
||||
.critical {
|
||||
border-left: 1px solid #ddd4;
|
||||
padding-left: 1%;
|
||||
}
|
||||
|
||||
#special-scroll {
|
||||
height: 40vh;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
#detail-main {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
#special-scroll {
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
#critical-des,
|
||||
.critical {
|
||||
font-size: 3.6vw;
|
||||
}
|
||||
}
|
||||
</style>
|
121
src/plugin/book.tsx
Normal file
121
src/plugin/book.tsx
Normal file
@ -0,0 +1,121 @@
|
||||
import { has } from './utils';
|
||||
|
||||
/**
|
||||
* 获取怪物的特殊技能描述
|
||||
* @param enemy 怪物实例
|
||||
*/
|
||||
export function getSpecialHint(enemy: Enemy & DetailedEnemy) {
|
||||
const all = core
|
||||
.getSpecials()
|
||||
.filter(v => enemy.special.includes(v[0]))
|
||||
.sort((a, b) => a[0] - b[0]);
|
||||
|
||||
const des = all.map(v => {
|
||||
const des = v[2];
|
||||
if (des instanceof Function) {
|
||||
return des(enemy);
|
||||
}
|
||||
return des;
|
||||
});
|
||||
const name = all.map(v => {
|
||||
const name = v[1];
|
||||
if (name instanceof Function) {
|
||||
return name(enemy);
|
||||
}
|
||||
return name;
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
{all.map((v, i) => {
|
||||
return (
|
||||
<div class="special">
|
||||
<span style={{ color: core.arrayToRGBA(v[3]) }}>
|
||||
{name[i]}:
|
||||
</span>
|
||||
<span innerHTML={des[i]}></span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得怪物的最近100个加防减伤
|
||||
* @param enemy 怪物实例
|
||||
*/
|
||||
export function getDefDamage(
|
||||
enemy: Enemy & DetailedEnemy,
|
||||
addDef: number = 0,
|
||||
addAtk: number = 0
|
||||
) {
|
||||
const ratio = core.status.thisMap.ratio;
|
||||
const res: [number, number][] = [];
|
||||
|
||||
let origin: number | undefined;
|
||||
let last = 0;
|
||||
|
||||
for (let i = 0; i <= 100; i++) {
|
||||
const dam = core.getDamageInfo(enemy, {
|
||||
def: core.status.hero.def + ratio * i + addDef,
|
||||
atk: core.status.hero.atk + addAtk
|
||||
});
|
||||
|
||||
if (i === 0) {
|
||||
origin = dam?.damage;
|
||||
if (has(origin)) {
|
||||
res.push([addDef, origin]);
|
||||
last = origin;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!has(dam)) continue;
|
||||
if (dam.damage === origin) continue;
|
||||
if (dam.damage === res.at(-1)?.[1]) continue;
|
||||
if (last <= 0) break;
|
||||
last = dam.damage;
|
||||
res.push([ratio * i + addDef, dam.damage]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取怪物的临界信息
|
||||
* @param enemy 怪物实例
|
||||
*/
|
||||
export function getCriticalDamage(
|
||||
enemy: Enemy & DetailedEnemy,
|
||||
addAtk: number = 0,
|
||||
addDef: number = 0
|
||||
): [number, number][] {
|
||||
const ratio = core.status.thisMap.ratio;
|
||||
const res: [number, number][] = [];
|
||||
|
||||
let origin: number | undefined;
|
||||
let last = 0;
|
||||
|
||||
for (let i = 0; i <= 100; i++) {
|
||||
const dam = core.getDamageInfo(enemy, {
|
||||
atk: core.status.hero.atk + ratio * i + addAtk,
|
||||
def: core.status.hero.def + addDef
|
||||
});
|
||||
|
||||
if (i === 0) {
|
||||
origin = dam?.damage;
|
||||
if (has(origin)) {
|
||||
res.push([addAtk, origin]);
|
||||
last = origin;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!has(dam)) continue;
|
||||
if (dam.damage === origin) continue;
|
||||
if (dam.damage === res.at(-1)?.[1]) continue;
|
||||
if (dam.damage <= 0) break;
|
||||
last = dam.damage;
|
||||
res.push([ratio * i + addAtk, dam.damage]);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
@ -1,17 +1,13 @@
|
||||
import { sleep } from 'mutate-animate';
|
||||
import { Component, markRaw, ref, Ref, watch } from 'vue';
|
||||
import Book from '../ui/book.vue';
|
||||
import BookDetail from '../ui/bookDetail.vue';
|
||||
|
||||
export const bookOpened = ref(false);
|
||||
export const bookDetail = ref(false);
|
||||
|
||||
let app: HTMLDivElement;
|
||||
|
||||
/** ui声明列表 */
|
||||
const UI_LIST: [Ref<boolean>, Component][] = [
|
||||
[bookOpened, Book],
|
||||
[bookDetail, BookDetail]
|
||||
];
|
||||
const UI_LIST: [Ref<boolean>, Component][] = [[bookOpened, Book]];
|
||||
|
||||
/** ui栈 */
|
||||
export const uiStack = ref<Component[]>([]);
|
||||
@ -32,15 +28,19 @@ export default function init() {
|
||||
}
|
||||
});
|
||||
});
|
||||
return { uiStack, bookDetail, bookOpened };
|
||||
return { uiStack, bookOpened };
|
||||
}
|
||||
|
||||
function showApp() {
|
||||
async function showApp() {
|
||||
app.style.display = 'flex';
|
||||
await sleep(50);
|
||||
app.style.opacity = '1';
|
||||
core.lockControl();
|
||||
}
|
||||
|
||||
function hideApp() {
|
||||
async function hideApp() {
|
||||
app.style.opacity = '0';
|
||||
await sleep(600);
|
||||
app.style.display = 'none';
|
||||
core.unlockControl();
|
||||
}
|
||||
|
@ -1,7 +1,23 @@
|
||||
export default function init() {
|
||||
return { useDrag, useWheel, isMobile };
|
||||
return { useDrag, useWheel, useUp, isMobile };
|
||||
}
|
||||
|
||||
type DragFn = (x: number, y: number, e: MouseEvent | TouchEvent) => void;
|
||||
|
||||
type DragMap = [
|
||||
(e: MouseEvent) => void,
|
||||
(e: TouchEvent) => void,
|
||||
((e: MouseEvent) => void)?,
|
||||
((e: TouchEvent) => void)?
|
||||
];
|
||||
|
||||
const dragFnMap = new Map<DragFn, DragMap>();
|
||||
|
||||
/**
|
||||
* 是否是移动设备
|
||||
*/
|
||||
export const isMobile = matchMedia('(max-width: 600px)').matches;
|
||||
|
||||
/**
|
||||
* 向一个元素添加拖拽事件
|
||||
* @param ele 目标元素
|
||||
@ -11,8 +27,9 @@ export default function init() {
|
||||
*/
|
||||
export function useDrag(
|
||||
ele: HTMLElement,
|
||||
fn: (x: number, y: number, e: MouseEvent | TouchEvent) => void,
|
||||
ondown?: (x: number, y: number, e: MouseEvent | TouchEvent) => void,
|
||||
fn: DragFn,
|
||||
ondown?: DragFn,
|
||||
onUp?: (e: MouseEvent | TouchEvent) => void,
|
||||
global: boolean = false
|
||||
) {
|
||||
let down = false;
|
||||
@ -25,21 +42,66 @@ export function useDrag(
|
||||
if (ondown) ondown(e.touches[0].clientX, e.touches[0].clientY, e);
|
||||
});
|
||||
|
||||
document.addEventListener('mouseup', () => (down = false));
|
||||
document.addEventListener('touchend', () => (down = false));
|
||||
|
||||
const target = global ? document : ele;
|
||||
|
||||
target.addEventListener('mousemove', e => {
|
||||
const mouseFn = (e: MouseEvent) => {
|
||||
if (!down) return;
|
||||
const ee = e as MouseEvent;
|
||||
fn(ee.clientX, ee.clientY, ee);
|
||||
});
|
||||
target.addEventListener('touchmove', e => {
|
||||
fn(e.clientX, e.clientY, e);
|
||||
};
|
||||
|
||||
const touchFn = (e: TouchEvent) => {
|
||||
if (!down) return;
|
||||
const ee = e as TouchEvent;
|
||||
fn(ee.touches[0].clientX, ee.touches[0].clientY, ee);
|
||||
});
|
||||
fn(e.touches[0].clientX, e.touches[0].clientY, e);
|
||||
};
|
||||
|
||||
const mouseUp = (e: MouseEvent) => {
|
||||
if (!down) return;
|
||||
onUp && onUp(e);
|
||||
down = false;
|
||||
};
|
||||
|
||||
const touchUp = (e: TouchEvent) => {
|
||||
if (!down) return;
|
||||
onUp && onUp(e);
|
||||
down = false;
|
||||
};
|
||||
|
||||
target.addEventListener(
|
||||
'mouseup',
|
||||
mouseUp as EventListenerOrEventListenerObject
|
||||
);
|
||||
target.addEventListener(
|
||||
'touchend',
|
||||
touchUp as EventListenerOrEventListenerObject
|
||||
);
|
||||
|
||||
dragFnMap.set(fn, [mouseFn, touchFn, mouseUp, touchUp]);
|
||||
|
||||
target.addEventListener(
|
||||
'mousemove',
|
||||
mouseFn as EventListenerOrEventListenerObject
|
||||
);
|
||||
target.addEventListener(
|
||||
'touchmove',
|
||||
touchFn as EventListenerOrEventListenerObject
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除一个全局拖拽函数
|
||||
* @param fn 要去除的函数
|
||||
*/
|
||||
export function cancelGlobalDrag(fn: DragFn): void {
|
||||
const fns = dragFnMap.get(fn);
|
||||
dragFnMap.delete(fn);
|
||||
if (!fns)
|
||||
throw new ReferenceError(
|
||||
'The drag function to be canceled does not exist.'
|
||||
);
|
||||
document.removeEventListener('mousemove', fns[0]);
|
||||
document.removeEventListener('touchmove', fns[1]);
|
||||
document.removeEventListener('mouseup', fns[0]);
|
||||
document.removeEventListener('touchend', fns[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,6 +119,15 @@ export function useWheel(
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是移动设备
|
||||
* 当鼠标或手指松开时执行函数
|
||||
* @param ele 目标元素
|
||||
* @param fn 当鼠标或手指松开时执行的函数
|
||||
*/
|
||||
export const isMobile = matchMedia('(max-width: 600px)').matches;
|
||||
export function useUp(ele: HTMLElement, fn: DragFn): void {
|
||||
ele.addEventListener('mouseup', e => {
|
||||
fn(e.clientX, e.clientY, e);
|
||||
});
|
||||
ele.addEventListener('touchend', e => {
|
||||
fn(e.touches[0].clientX, e.touches[0].clientY, e);
|
||||
});
|
||||
}
|
||||
|
@ -25,3 +25,20 @@ export function getDamageColor(damage: number): string {
|
||||
if (damage < core.status.hero.hp) return '#f22';
|
||||
return '#f00';
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置画布的长宽
|
||||
* @param canvas 画布
|
||||
* @param w 宽度
|
||||
* @param h 高度
|
||||
*/
|
||||
export function setCanvasSize(
|
||||
canvas: HTMLCanvasElement,
|
||||
w: number,
|
||||
h: number
|
||||
): void {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
canvas.style.width = `${w}px`;
|
||||
canvas.style.height = `${h}px`;
|
||||
}
|
||||
|
@ -7,4 +7,7 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
transition: all 0.6s linear;
|
||||
opacity: 0;
|
||||
background-color: #000d;
|
||||
}
|
||||
|
4
src/types/enemy.d.ts
vendored
4
src/types/enemy.d.ts
vendored
@ -105,7 +105,7 @@ declare class enemys {
|
||||
x?: number,
|
||||
y?: number,
|
||||
floorId?: string
|
||||
): number[][];
|
||||
): [atk: number, dam: number][];
|
||||
|
||||
/**
|
||||
* 计算再加若干点防御能使某只敌人对主角的总伤害降低多少
|
||||
@ -198,5 +198,5 @@ declare class enemys {
|
||||
turn: number;
|
||||
damage: number;
|
||||
[x: string]: any;
|
||||
};
|
||||
} | null;
|
||||
}
|
||||
|
29
src/types/plugin.d.ts
vendored
29
src/types/plugin.d.ts
vendored
@ -4,6 +4,8 @@ type Ref<T> = {
|
||||
value: T;
|
||||
};
|
||||
|
||||
type DragFn = (x: number, y: number, e: MouseEvent | TouchEvent) => void;
|
||||
|
||||
interface PluginDeclaration extends PluginUtils {
|
||||
/**
|
||||
* 添加函数 例:添加弹出文字,像这个就可以使用core.addPop或core.plugin.addPop调用
|
||||
@ -16,12 +18,15 @@ interface PluginDeclaration extends PluginUtils {
|
||||
/** 添加变量 例:所有的正在弹出的文字,像这个就可以使用core.plugin.pop获取 */
|
||||
pop: any[];
|
||||
|
||||
/** 怪物手册的怪物详细信息的初始位置 */
|
||||
bookDetailPos: number;
|
||||
|
||||
/** 怪物手册详细信息展示的怪物 */
|
||||
bookDetailEnemy: Enemy & DetailedEnemy;
|
||||
|
||||
/** 手册是否打开 */
|
||||
readonly bookOpened: Ref<boolean>;
|
||||
|
||||
/** 手册详细信息 */
|
||||
readonly bookDetail: Ref<boolean>;
|
||||
|
||||
/** ui栈 */
|
||||
readonly uiStack: Ref<Component[]>;
|
||||
|
||||
@ -37,11 +42,18 @@ interface PluginDeclaration extends PluginUtils {
|
||||
*/
|
||||
useDrag(
|
||||
ele: HTMLElement,
|
||||
fn: (x: number, y: number, e: MouseEvent | TouchEvent) => void,
|
||||
ondown?: (x: number, y: number, e: MouseEvent | TouchEvent) => void,
|
||||
fn: DragFn,
|
||||
ondown?: DragFn,
|
||||
onUp?: (e: MouseEvent | TouchEvent) => void,
|
||||
global: boolean = false
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 去除一个全局拖拽函数
|
||||
* @param fn 要去除的函数
|
||||
*/
|
||||
cancelGlobalDrag(fn: DragFn): void;
|
||||
|
||||
/**
|
||||
* 当触发滚轮时执行函数
|
||||
* @param ele 目标元素
|
||||
@ -52,6 +64,13 @@ interface PluginDeclaration extends PluginUtils {
|
||||
fn: (x: number, y: number, z: number, e: WheelEvent) => void
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 当鼠标或手指松开时执行函数
|
||||
* @param ele 目标元素
|
||||
* @param fn 当鼠标或手指松开时执行的函数
|
||||
*/
|
||||
useUp(ele: HTMLElement, fn: DragFn): void;
|
||||
|
||||
/**
|
||||
* 添加一个动画
|
||||
* @param fn 要添加的函数
|
||||
|
8
src/types/util.d.ts
vendored
8
src/types/util.d.ts
vendored
@ -100,7 +100,11 @@ declare class utils {
|
||||
* @param onMap 可选,true表示用于地图显伤,结果总字符数最多为5,否则最多为6
|
||||
* @returns 格式化结果
|
||||
*/
|
||||
formatBigNumber(x: number, onMap?: boolean, onCritical?: boolean): string;
|
||||
formatBigNumber(
|
||||
x: number | string,
|
||||
onMap?: boolean,
|
||||
onCritical?: boolean
|
||||
): string;
|
||||
|
||||
/** 变速移动 */
|
||||
applyEasing(mode?: string): (number) => number;
|
||||
@ -119,7 +123,7 @@ declare class utils {
|
||||
* @param color 一行三列或一行四列的数组,前三个元素必须为不大于255的自然数。第四个元素(如果有)必须为0或不大于1的数字,第四个元素不填视为1
|
||||
* @returns 该颜色的字符串表示
|
||||
*/
|
||||
arrayToRGBA(color: [number, number, number, number]): string;
|
||||
arrayToRGBA(color: [number, number, number, number?] | string): string;
|
||||
|
||||
/**
|
||||
* 录像一压,其结果会被再次base64压缩
|
||||
|
@ -4,9 +4,14 @@
|
||||
<div v-if="enemy.length === 0" id="none">
|
||||
<div>本层无怪物</div>
|
||||
</div>
|
||||
<Scroll v-else style="width: 100%; height: 100%; font-family: normal">
|
||||
<div v-for="e of enemy" class="enemy">
|
||||
<EnemyOne :enemy="e"></EnemyOne>
|
||||
<Scroll
|
||||
v-else
|
||||
style="width: 100%; height: 100%; font-family: normal"
|
||||
v-model:now="scroll"
|
||||
v-model:drag="drag"
|
||||
>
|
||||
<div v-for="(e, i) of enemy" class="enemy">
|
||||
<EnemyOne :enemy="e" @select="select(e, i)"></EnemyOne>
|
||||
<a-divider
|
||||
dashed
|
||||
style="width: 100%; border-color: #ddd4"
|
||||
@ -14,18 +19,25 @@
|
||||
</div>
|
||||
</Scroll>
|
||||
</div>
|
||||
<BookDetail v-if="detail" @close="closeDetail()"></BookDetail>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { onMounted } from 'vue';
|
||||
import { sleep } from 'mutate-animate';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import EnemyOne from '../components/enemyOne.vue';
|
||||
import Scroll from '../components/scroll.vue';
|
||||
import { getDamageColor } from '../plugin/utils';
|
||||
import BookDetail from './bookDetail.vue';
|
||||
|
||||
const floorId = core.floorIds[core.status.event?.ui] ?? core.status.floorId;
|
||||
const enemy = core.getCurrentEnemys(floorId);
|
||||
|
||||
const scroll = ref(0);
|
||||
const drag = ref(false);
|
||||
const detail = ref(false);
|
||||
|
||||
// 解析
|
||||
enemy.forEach(v => {
|
||||
const l = v.specialText.length;
|
||||
@ -46,18 +58,52 @@ onMounted(() => {
|
||||
const div = document.getElementById('book') as HTMLDivElement;
|
||||
div.style.opacity = '1';
|
||||
});
|
||||
|
||||
/**
|
||||
* 选择怪物,展示详细信息
|
||||
* @param enemy 选择的怪物
|
||||
* @param index 选择的怪物索引
|
||||
*/
|
||||
function select(enemy: Enemy & DetailedEnemy, index: number) {
|
||||
if (drag.value) return;
|
||||
const h = window.innerHeight;
|
||||
const y = index * h * 0.2 - scroll.value;
|
||||
core.plugin.bookDetailEnemy = enemy;
|
||||
core.plugin.bookDetailPos = y;
|
||||
detail.value = true;
|
||||
hide();
|
||||
}
|
||||
|
||||
async function hide() {
|
||||
const div = document.getElementById('book') as HTMLDivElement;
|
||||
div.style.opacity = '0';
|
||||
await sleep(600);
|
||||
div.style.display = 'none';
|
||||
}
|
||||
|
||||
async function closeDetail() {
|
||||
show();
|
||||
await sleep(600);
|
||||
detail.value = false;
|
||||
}
|
||||
|
||||
async function show() {
|
||||
const div = document.getElementById('book') as HTMLDivElement;
|
||||
div.style.display = 'block';
|
||||
await sleep(50);
|
||||
div.style.opacity = '1';
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#book {
|
||||
opacity: 0;
|
||||
background-color: #000d;
|
||||
transition: opacity 0.6s linear;
|
||||
user-select: none;
|
||||
width: 80%;
|
||||
height: 100%;
|
||||
font-family: 'normal';
|
||||
overflow: hidden;
|
||||
transition: opacity 0.6s linear;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
|
@ -1,7 +1,175 @@
|
||||
<!-- 怪物详细信息 -->
|
||||
<template>
|
||||
<div id="detail">
|
||||
<div id="info" :style="{ top: `${top}px` }">
|
||||
<EnemyOne :enemy="enemy"></EnemyOne>
|
||||
<a-divider
|
||||
dashed
|
||||
style="margin: 2vh 0 2vh 0; border-color: #ddd4; width: 100%"
|
||||
></a-divider>
|
||||
</div>
|
||||
<Transition name="detail">
|
||||
<EnemySpecial v-if="panel === 'special'"></EnemySpecial>
|
||||
<EnemyCritical v-else-if="panel === 'critical'"></EnemyCritical>
|
||||
</Transition>
|
||||
<div id="detail-more">
|
||||
<Transition name="detail">
|
||||
<div
|
||||
id="special-more"
|
||||
class="detial-more"
|
||||
v-if="panel === 'special'"
|
||||
>
|
||||
<span id="enemy-pos" class="more"
|
||||
><left-outlined /> 怪物分布情况</span
|
||||
>
|
||||
<span
|
||||
id="critical-more"
|
||||
class="more"
|
||||
@click="changePanel($event, 'critical')"
|
||||
>详细临界信息 <right-outlined
|
||||
/></span>
|
||||
</div>
|
||||
<div
|
||||
id="special-more"
|
||||
class="detial-more"
|
||||
v-else-if="panel === 'critical'"
|
||||
>
|
||||
<span
|
||||
id="enemy-pos"
|
||||
class="more"
|
||||
@click="changePanel($event, 'special')"
|
||||
><left-outlined /> 怪物特殊属性</span
|
||||
>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template></template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import EnemyOne from '../components/enemyOne.vue';
|
||||
import { useDrag } from '../plugin/use';
|
||||
import EnemySpecial from '../panel/enemySpecial.vue';
|
||||
import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
|
||||
import EnemyCritical from '../panel/enemyCritical.vue';
|
||||
|
||||
<script lang="tsx" setup></script>
|
||||
const enemy = core.plugin.bookDetailEnemy;
|
||||
const top = ref(core.plugin.bookDetailPos);
|
||||
const panel = ref('special');
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
const emits = defineEmits<{
|
||||
(e: 'close'): void;
|
||||
}>();
|
||||
|
||||
function changePanel(e: MouseEvent, to: string) {
|
||||
e.stopPropagation();
|
||||
panel.value = to;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
top.value = 0;
|
||||
const div = document.getElementById('detail') as HTMLDivElement;
|
||||
div.style.opacity = '1';
|
||||
|
||||
const style = getComputedStyle(div);
|
||||
|
||||
let moved = false;
|
||||
useDrag(
|
||||
div,
|
||||
() => {
|
||||
moved = true;
|
||||
},
|
||||
(x, y) => {
|
||||
if (y > (parseFloat(style.height) * 4) / 5) moved = true;
|
||||
},
|
||||
() => {
|
||||
if (moved === false) {
|
||||
top.value = core.plugin.bookDetailPos;
|
||||
div.style.opacity = '0';
|
||||
emits('close');
|
||||
}
|
||||
moved = false;
|
||||
}
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#info {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
transition: all 0.6s ease;
|
||||
height: 20vh;
|
||||
padding: 0 1% 0 1%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#detail {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
left: 14%;
|
||||
font-family: 'normal';
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 72%;
|
||||
height: 90%;
|
||||
transition: all 0.6s ease;
|
||||
}
|
||||
|
||||
#detail-more {
|
||||
position: absolute;
|
||||
margin-top: 3%;
|
||||
width: 100%;
|
||||
font-size: 3vh;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.detial-more {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.more {
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s linear;
|
||||
}
|
||||
|
||||
.more:hover {
|
||||
color: aqua;
|
||||
}
|
||||
|
||||
.more:active {
|
||||
color: aquamarine;
|
||||
}
|
||||
|
||||
.detail-enter-active,
|
||||
.detail-leave-active {
|
||||
transition: all 0.6s ease;
|
||||
}
|
||||
|
||||
.detail-enter-from,
|
||||
.detail-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@media screen and(max-width:600px) {
|
||||
#detail {
|
||||
width: 95%;
|
||||
height: 100%;
|
||||
padding: 5% 0 5% 5%;
|
||||
left: 0%;
|
||||
}
|
||||
|
||||
#detail-more {
|
||||
font-size: 4vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -26,7 +26,7 @@ export default defineConfig({
|
||||
output: {
|
||||
manualChunks: {
|
||||
antdv: ['ant-design-vue', '@ant-design/icons-vue'],
|
||||
common: ['lodash', 'axios', 'lz-string', 'vue']
|
||||
common: ['lodash', 'axios', 'lz-string']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user