Skip to content

Commit ca72462

Browse files
author
jingwenzheng
committed
feat: layout 库 开发
1 parent 94656bd commit ca72462

29 files changed

+692
-218
lines changed

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
</head>
99
<body>
1010
<div id="app"></div>
11-
<script type="module" src="/src/main.ts"></script>
11+
<script type="module" src="/src/main.tsx"></script>
1212
</body>
1313
</html>

package.json

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,19 @@
55
],
66
"scripts": {
77
"dev": "vite",
8-
"build": "pnpm --dir ./packages/core build",
9-
"build-lib": "vue-tsc && vite build --config vite.config.lib.ts",
10-
"preview": "vite preview",
8+
"build-core": "pnpm --dir ./packages/core build",
9+
"build-layout": "pnpm --dir ./packages/layout build",
1110
"pub": "npm run build-lib && npm publish --registry https://registry.npmjs.org"
1211
},
1312
"devDependencies": {
14-
"@types/animejs": "^3.1.12",
1513
"@vitejs/plugin-vue-jsx": "^3.1.0",
1614
"typescript": "^4.9.5",
1715
"vite": "^5.0.10",
18-
"vite-plugin-dts": "^1.7.3",
1916
"vue-tsc": "^1.8.26"
2017
},
2118
"dependencies": {
2219
"@0x30/vue-navigation": "workspace:*",
23-
"animejs": "^3.2.2",
20+
"@0x30/vue-navigation-layout": "workspace:*",
2421
"vue": "^3.3.13"
2522
}
2623
}

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"type": "module",
33
"scripts": {
44
"build": "vue-tsc && vite build",
5-
"pub": "npm run build-lib && npm publish --registry https://registry.npmjs.org"
5+
"pub": "npm run build && npm publish --registry https://registry.npmjs.org"
66
},
77
"peerDependencies": {
88
"vue": "^3"

packages/core/src/state.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,8 @@ const backHooks: Record<string, () => void> = {}
2222
const setBackHook = (id: string, resolve: () => void) => {
2323
setLastBackHookId(id)
2424
backHooks[id] = () => {
25-
if (lastBackHookId) {
26-
delete backHooks[lastBackHookId]
27-
lastBackHookId = undefined
28-
}
25+
delete backHooks[id]
26+
lastBackHookId = undefined
2927
resolve()
3028
}
3129
}

packages/layout/package.json

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,43 @@
11
{
2-
"name": "layout",
2+
"name": "@0x30/vue-navigation-layout",
33
"version": "1.0.0",
4-
"description": "",
5-
"main": "index.js",
64
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1"
5+
"build": "vue-tsc && vite build",
6+
"pub": "npm run build && npm publish --registry https://registry.npmjs.org"
87
},
98
"keywords": [],
10-
"author": "",
119
"license": "ISC",
1210
"peerDependencies": {
13-
"@0x30/vue-navigation": "workspace:*"
14-
}
11+
"@0x30/vue-navigation": "workspace:*",
12+
"animejs": "^3.2.2"
13+
},
14+
"devDependencies": {
15+
"@types/animejs": "^3.1.12",
16+
"@vitejs/plugin-vue-jsx": "^3.1.0",
17+
"autoprefixer": "^10.4.16",
18+
"postcss": "^8.4.32",
19+
"sass": "^1.69.5",
20+
"typescript": "^4.9.5",
21+
"vite": "^5.0.10",
22+
"vite-plugin-css-injected-by-js": "^3.3.1",
23+
"vite-plugin-dts": "^1.7.3",
24+
"vue-tsc": "^1.8.26"
25+
},
26+
"main": "dist/vue-navigation-layout.umd.js",
27+
"module": "dist/vue-navigation-layout.mjs",
28+
"types": "dist/index.d.ts",
29+
"repository": {
30+
"type": "git",
31+
"url": "git+https://github.com/0x30/vue-navigation.git"
32+
},
33+
"author": "",
34+
"bugs": {
35+
"url": "https://github.com/0x30/vue-navigation/issues"
36+
},
37+
"homepage": "https://github.com/0x30/vue-navigation#readme",
38+
"description": "",
39+
"files": [
40+
"dist/*.js",
41+
"dist/index.d.ts"
42+
]
1543
}

packages/layout/postcss.config.cjs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const autoprefixer = require('autoprefixer');
2+
3+
module.exports = {
4+
plugins: [
5+
autoprefixer(),
6+
]
7+
};

packages/layout/src/Core.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { cloneVNode, type Slot, type VNodeProps } from 'vue'
2+
3+
export const cloneSlot = (
4+
slot?: Slot,
5+
extraProps?: (Record<string, unknown> & VNodeProps) | null,
6+
mergeRef?: boolean
7+
) => {
8+
const elements = slot?.()
9+
if (elements === undefined || elements.length > 1) return undefined
10+
const element = elements[0]
11+
return cloneVNode(element, extraProps, mergeRef)
12+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
.body {
2+
position: fixed;
3+
top: 0;
4+
right: 0;
5+
bottom: 0;
6+
left: 0;
7+
width: 100vw;
8+
height: 100vh;
9+
10+
display: flex;
11+
flex-direction: column;
12+
justify-content: flex-end;
13+
14+
display: flex;
15+
flex-direction: row;
16+
align-items: center;
17+
justify-content: stretch;
18+
19+
background-color: transparent;
20+
21+
.back {
22+
position: absolute;
23+
top: 0;
24+
right: 0;
25+
left: 0;
26+
bottom: 0;
27+
background-color: rgba($color: #000000, $alpha: 0.6);
28+
}
29+
30+
.main {
31+
position: relative;
32+
flex: 1;
33+
}
34+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { useTransitionEnter, useTransitionLeave } from '@0x30/vue-navigation'
2+
import { defineComponent } from 'vue'
3+
4+
import styles from './index.module.scss'
5+
import anime from 'animejs'
6+
import { cloneSlot } from '../Core'
7+
8+
const ModalPage = defineComponent({
9+
name: 'ModalPage',
10+
setup: (_, { slots }) => {
11+
useTransitionEnter(({ to }, complete) => {
12+
const back = to?.querySelector(`.${styles.back}`)
13+
const body = to?.querySelector(`.${styles.main}`)
14+
15+
const an = anime.timeline({ duration: 450, complete })
16+
an.add({ targets: back, opacity: [0.5, 1], easing: 'linear' })
17+
an.add({ targets: body, scale: [0.1, 1], opacity: 1 }, 0)
18+
})
19+
useTransitionLeave(({ from }, complete) => {
20+
const back = from?.querySelector(`.${styles.back}`)
21+
const body = from?.querySelector(`.${styles.main}`)
22+
23+
const an = anime.timeline({ duration: 150, complete, easing: 'linear' })
24+
an.add({ targets: [back, body], opacity: 0 })
25+
})
26+
27+
return () => {
28+
const element = cloneSlot(slots.default, {
29+
class: styles.main,
30+
})
31+
if (element === undefined) return null
32+
return (
33+
<div class={styles.body}>
34+
<div class={styles.back}></div>
35+
{element}
36+
</div>
37+
)
38+
}
39+
},
40+
})
41+
42+
export default ModalPage
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import {
2+
back,
3+
useTransitionEnter,
4+
useTransitionLeave,
5+
useProgressExitAnimated,
6+
} from '@0x30/vue-navigation'
7+
import anime from 'animejs'
8+
import { defineComponent } from 'vue'
9+
import Page from '../Page'
10+
11+
const PageBodyClassName = 'vue-navigation-layout-body'
12+
13+
const NavPage = defineComponent({
14+
name: 'NavPage',
15+
setup: (props, { slots }) => {
16+
const animeProps = { duration: 500, easing: 'easeOutExpo' }
17+
18+
useTransitionEnter(({ to, from }, complete) => {
19+
const an = anime.timeline({ ...animeProps, complete })
20+
an.add({ targets: to, translateX: ['100%', '0'] })
21+
if (from?.classList.contains(PageBodyClassName)) {
22+
an.add(
23+
{
24+
targets: from,
25+
translateX: ['0%', '-50%'],
26+
complete: (anim) => anim.seek(0),
27+
},
28+
0
29+
)
30+
}
31+
})
32+
33+
let justBack = false
34+
useTransitionLeave(({ from, to }, complete) => {
35+
/// 如果该值 设置为 true 表明,当前是通过 滑动返回的方式关闭的
36+
/// 那么不需要执行任何动画 直接完成即可
37+
if (justBack) {
38+
complete()
39+
return
40+
}
41+
42+
const an = anime.timeline({ ...animeProps, complete })
43+
if (to?.classList.contains(PageBodyClassName)) {
44+
an.add({ targets: to, translateX: ['-50%', '0%'] })
45+
}
46+
an.add({ targets: from, translateX: ['0', '100%'] }, 0)
47+
})
48+
49+
useProgressExitAnimated(({ from, to }, progress, isFinish) => {
50+
if (isFinish === undefined) {
51+
if (to?.classList.contains(PageBodyClassName)) {
52+
anime.set(to, { translateX: -50 * (1 - progress) + '%' })
53+
}
54+
if (from) {
55+
anime.set(from, { translateX: 100 * progress + '%' })
56+
}
57+
} else {
58+
/// 如果 滑动返回成功结束
59+
if (isFinish) {
60+
const animated = anime.timeline({
61+
duration: 300,
62+
easing: 'easeOutExpo',
63+
})
64+
if (to?.classList.contains(PageBodyClassName)) {
65+
animated.add({ targets: to, translateX: '0' })
66+
}
67+
animated.add({ targets: from, translateX: '100%' }, 0)
68+
69+
animated.complete = () => {
70+
justBack = true
71+
back()
72+
}
73+
} else {
74+
const animated = anime.timeline({
75+
duration: 300,
76+
easing: 'easeOutExpo',
77+
})
78+
if (to?.classList.contains(PageBodyClassName)) {
79+
animated.add({ targets: to, translateX: '-50%' })
80+
}
81+
animated.add({ targets: from, translateX: '0%' }, 0)
82+
}
83+
}
84+
})
85+
86+
return () => <Page>{slots.default?.()}</Page>
87+
},
88+
})
89+
90+
export default NavPage

0 commit comments

Comments
 (0)