Skip to content

Commit a175d63

Browse files
committed
feat: Re-scratch vue-fixed-header
1 parent 5015c89 commit a175d63

12 files changed

+5656
-1685
lines changed

babel.config.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
presets: [
3+
'@vue/app'
4+
]
5+
}

package.json

+11-15
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@
1919
],
2020
"scripts": {
2121
"dev": "yarn serve",
22-
"serve": "parcel ./example/index.html -d docs",
23-
"build": "yarn clean;bili ./src/index.ts --format cjs --js typescript2",
24-
"clean": "rm -rf {.rpt2_cache,dist}",
22+
"serve": "vue-cli-service serve ./src/example.ts",
23+
"build": "vue-cli-service build --target lib src/components/vue-fixed-header.vue",
2524
"format": "prettier './{src,example}/**/*.{js,ts,vue}' --write",
2625
"test": "jest",
2726
"test:watch": "jest --watch",
@@ -32,35 +31,32 @@
3231
"name": "potato4d",
3332
"email": "[email protected]"
3433
},
35-
"bili": {
36-
"filename": "vue-fixed-header.js"
37-
},
3834
"devDependencies": {
3935
"@types/jest": "24.0.9",
36+
"@types/lodash.clonedeep": "^4.5.5",
4037
"@types/node": "10.12.27",
38+
"@vue/cli": "^3.0.3",
39+
"@vue/cli-plugin-babel": "^3.4.0",
40+
"@vue/cli-plugin-typescript": "^3.4.0",
41+
"@vue/cli-plugin-unit-jest": "^3.0.3",
42+
"@vue/cli-service": "^3.4.0",
4143
"@vue/component-compiler-utils": "2.6.0",
4244
"@vue/test-utils": "1.0.0-beta.29",
4345
"all-contributors-cli": "6.1.2",
44-
"bili": "4.4.0",
4546
"bulma": "0.7.4",
4647
"codecov": "3.2.0",
4748
"gh-pages": "2.0.1",
4849
"jest": "24.1.0",
4950
"jsdom": "13.2.0",
5051
"jsdom-global": "3.0.2",
51-
"parcel-bundler": "1.11.0",
52-
"prettier": "1.16.4",
53-
"rollup-plugin-typescript2": "0.19.3",
5452
"standard-version": "5.0.0",
5553
"ts-jest": "24.0.0",
56-
"typescript": "3.3.3333",
54+
"typescript": "3.0.1",
5755
"vue-template-compiler": "2.6.7"
5856
},
5957
"dependencies": {
60-
"vue": "^2.5.17",
61-
"vue-class-component": "^7.0.0",
62-
"vue-hot-reload-api": "^2.3.1",
63-
"vue-property-decorator": "^7.2.0"
58+
"lodash.clonedeep": "^4.5.0",
59+
"vue": "^2.5.17"
6460
},
6561
"prettier": {
6662
"semi": false,

src/components/ExampleApp.vue

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<template>
2+
<div id="app">
3+
<VueFixedHeader :threshold="100" fixedClass="fixed">
4+
<nav>
5+
<ul>
6+
<li>
7+
Header Item
8+
</li>
9+
</ul>
10+
</nav>
11+
</VueFixedHeader>
12+
</div>
13+
</template>
14+
15+
<script lang="ts">
16+
import Vue from 'vue'
17+
import VueFixedHeader from './vue-fixed-header'
18+
19+
export default Vue.extend({
20+
data() {
21+
return {
22+
aaa: false
23+
}
24+
},
25+
components: {
26+
VueFixedHeader
27+
}
28+
})
29+
</script>
30+
31+
<style>
32+
html,
33+
body,
34+
#app {
35+
width: 100vw;
36+
min-height: 150vh;
37+
margin: 0;
38+
padding: 0;
39+
background: #fafafa;
40+
overflow-x: hidden;
41+
}
42+
43+
nav {
44+
display: flex;
45+
width: 100vw;
46+
margin: 0;
47+
padding: 0;
48+
background: #fff;
49+
border-bottom: solid 1px #e5e5e5;
50+
}
51+
52+
nav.fixed {
53+
position: fixed;
54+
left: 0;
55+
top: 0;
56+
}
57+
58+
ul {
59+
flex: 1;
60+
display: flex;
61+
align-content: stretch;
62+
justify-content: flex-start;
63+
list-style: none;
64+
}
65+
66+
li {
67+
padding: 8px 16px;
68+
}
69+
</style>

src/components/vue-fixed-header.tsx

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import Vue, { CreateElement, VNode } from 'vue'
2+
import { getTargetTag } from '../utils/getTargetTag'
3+
4+
type LocalData = {
5+
qs: any,
6+
check: any,
7+
tag: any,
8+
isFixed: boolean
9+
}
10+
11+
export default Vue.extend({
12+
props: {
13+
threshold: {
14+
required: false,
15+
type: Number,
16+
default: 0
17+
},
18+
headerClass: {
19+
required: false,
20+
type: String,
21+
default: 'vue-fixed-header',
22+
},
23+
fixedClass: {
24+
required: false,
25+
type: String,
26+
default: 'vue-fixed-header--isFixed'
27+
}
28+
},
29+
30+
data() {
31+
return {
32+
qs: null,
33+
check: null,
34+
tag: null,
35+
isFixed: false
36+
} as LocalData
37+
},
38+
39+
mounted() {
40+
this.main()
41+
this.registerEvent()
42+
},
43+
44+
beforeDestroy() {
45+
this.removeEvent()
46+
},
47+
48+
methods: {
49+
main() {
50+
this.qs = (e: string) => document.querySelector(e)
51+
this.tag = getTargetTag(navigator.userAgent)
52+
this.check = () => {
53+
const { qs, tag, threshold } = this
54+
if (!tag) {
55+
return
56+
}
57+
if (this.isFixed !== qs(tag).scrollTop > threshold) {
58+
this.isFixed = qs(tag).scrollTop > threshold
59+
// console.log(this.$slots.default![0])
60+
// this.$slots.default![0] = copy(this.$slots.default![0])
61+
this.$forceUpdate()
62+
}
63+
}
64+
},
65+
registerEvent() {
66+
window.addEventListener('scroll', this.check)
67+
},
68+
removeEvent() {
69+
window.removeEventListener('scroll', this.check)
70+
}
71+
},
72+
73+
render(h: CreateElement): VNode {
74+
const children = this.$slots.default
75+
if (!children) {
76+
return h()
77+
}
78+
79+
const _child = [...children][0] as VNode
80+
const child = h(_child.tag, _child.data, _child.children || _child.text)
81+
82+
if (!child) {
83+
return h()
84+
}
85+
86+
child.data = child.data || { class: '' }
87+
88+
// string to string[]
89+
if (typeof child.data.class === 'string') {
90+
child.data.class = child.data.class.split(' ')
91+
}
92+
93+
// string[] to { K: V }
94+
if (Array.isArray(child.data.class)) {
95+
child.data.class = [...child.data.class].reduce((a, b) => {
96+
return {
97+
...a,
98+
[b]: true
99+
}
100+
}, {})
101+
}
102+
103+
child.data.class[this.headerClass] = true
104+
child.data.class[this.fixedClass] = !!this.isFixed
105+
106+
child.data.class = Object.entries(child.data.class).map(([k, v]) => {
107+
return v ? k : null
108+
}).filter((v) => v).join(' ')
109+
110+
return child
111+
}
112+
})

src/example.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Vue from 'vue'
2+
// import ExampleApp from './components/ExampleApp.vue'
3+
import ExampleApp from './components/ExampleApp.vue'
4+
5+
new Vue({
6+
render: h => h(ExampleApp)
7+
}).$mount('#app')

src/index.spec.ts

-19
This file was deleted.

src/index.ts

-57
This file was deleted.

src/types/shims-tsx.d.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import Vue, { VNode } from 'vue'
2+
3+
declare global {
4+
namespace JSX {
5+
// tslint:disable no-empty-interface
6+
interface Element extends VNode {}
7+
// tslint:disable no-empty-interface
8+
interface ElementClass extends Vue {}
9+
interface IntrinsicElements {
10+
[elem: string]: any
11+
}
12+
}
13+
}

src/types/shims-vue.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare module '*.vue' {
2+
import Vue from 'vue'
3+
export default Vue
4+
}

src/utils/getTargetTag.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export function getTargetTag(userAgent: string): 'html' | 'body' {
2+
if (userAgent.includes('Edge')) {
3+
return 'body'
4+
}
5+
if (userAgent.includes('Firefox/') && +userAgent.split('Firefox/')[1] >= 62) {
6+
return 'html'
7+
}
8+
if (
9+
!(window as any).chrome &&
10+
'WebkitAppearance' in (document.documentElement as any).style
11+
) {
12+
return 'body'
13+
}
14+
return 'html'
15+
}

0 commit comments

Comments
 (0)