refactor(affix): composition api + new theme

This commit is contained in:
07akioni 2020-12-31 20:59:26 +08:00
parent b7cabf901a
commit 66a2fa2353
9 changed files with 191 additions and 206 deletions

View File

@ -51,7 +51,11 @@ export default function useTheme (
} = {}
} = NConfigProvider
const mergedCommon = merge(
common || injectedCommon || injectedGlobalCommon || defaultTheme.common,
common ||
injectedCommon ||
injectedGlobalCommon ||
defaultTheme.common ||
{},
injectedGlobalCommonOverrides,
injectedCommonOverrides,
commonOverrides
@ -59,7 +63,7 @@ export default function useTheme (
return {
common: mergedCommon,
self: merge(
(self || injectedSelf || defaultTheme.self)(mergedCommon),
(self || injectedSelf || defaultTheme.self || {})(mergedCommon),
injectedSelfOverrides,
selfOverrides
),

View File

@ -1,25 +1,27 @@
<template>
<div
ref="selfRef"
class="n-affix"
:class="{
[`n-affix--affixed`]: affixed,
[`n-affix--absolute-positioned`]: position === 'absolute'
}"
:style="style"
:style="mergedstyle"
>
<slot />
</div>
</template>
<script>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import { getScrollParent, unwrapElement } from 'seemly'
import { configurable, themeable, withCssr } from '../../_mixins'
import styles from './styles/index.js'
import { useConfig, useTheme } from '../../_mixins'
import { warn } from '../../_utils'
import { affixLight } from '../styles'
import style from './styles/index.cssr'
export default {
name: 'Affix',
mixins: [configurable, themeable, withCssr(styles)],
props: {
listenTo: {
type: [String, Object],
@ -54,54 +56,35 @@ export default {
default: undefined
}
},
data () {
return {
scrollElement: null,
stickToTop: false,
stickToBottom: false,
bottomAffixedTriggerScrollTop: null,
topAffixedTriggerScrollTop: null
}
},
computed: {
affixed () {
return this.stickToBottom || this.stickToTop
},
mergedOffsetTop () {
return this.offsetTop === undefined ? this.top : this.offsetTop
},
mergedTop () {
return this.top === undefined ? this.offsetTop : this.top
},
mergedBottom () {
return this.bottom === undefined ? this.offsetBottom : this.bottom
},
mergedOffsetBottom () {
return this.offsetBottom === undefined ? this.bottom : this.offsetBottom
},
style () {
const style = {}
if (this.stickToTop && this.mergedOffsetTop !== undefined) {
style.top = `${this.mergedTop}px`
}
if (this.stickToBottom && this.mergedOffsetBottom !== undefined) {
style.bottom = `${this.mergedBottom}px`
}
return style
}
},
mounted () {
this.init()
},
beforeUnmount () {
const { scrollElement } = this
if (scrollElement) {
scrollElement.removeEventListener('scroll', this.handleScroll)
}
},
methods: {
init () {
const { target: getScrollTarget, listenTo } = this
setup (props) {
useTheme('Affix', 'Affix', style, affixLight, props)
const scrollElementRef = ref(null)
const stickToTopRef = ref(false)
const stickToBottomRef = ref(false)
const bottomAffixedTriggerScrollTopRef = ref(null)
const topAffixedTriggerScrollTopRef = ref(null)
const affixedRef = computed(() => {
return stickToBottomRef.value || stickToTopRef.value
})
const mergedOffsetTopRef = computed(() => {
const { offsetTop, top } = props
return offsetTop === undefined ? top : offsetTop
})
const mergedTopRef = computed(() => {
const { offsetTop, top } = props
return top === undefined ? offsetTop : top
})
const mergedBottomRef = computed(() => {
const { offsetBottom, bottom } = props
return bottom === undefined ? offsetBottom : bottom
})
const mergedOffsetBottomRef = computed(() => {
const { offsetBottom, bottom } = props
return offsetBottom === undefined ? bottom : offsetBottom
})
const selfRef = ref(null)
const init = () => {
const { target: getScrollTarget, listenTo } = props
let scrollElement
if (getScrollTarget) {
// deprecated
@ -109,56 +92,89 @@ export default {
} else if (listenTo) {
scrollElement = unwrapElement(listenTo)
} else {
scrollElement = getScrollParent(this.$el)
scrollElement = getScrollParent(selfRef.value)
}
if (scrollElement) {
this.scrollElement = scrollElement
scrollElementRef.value = scrollElement
} else if (__DEV__) {
warn('affix', 'Target to be listened to is not valid.')
}
if (scrollElement) {
scrollElement.addEventListener('scroll', this.handleScroll)
this.handleScroll()
scrollElement.addEventListener('scroll', handleScroll)
handleScroll()
}
},
handleScroll (e) {
const containerEl = this.scrollElement
if (this.affixed) {
if (containerEl.scrollTop < this.topAffixedTriggerScrollTop) {
this.stickToTop = false
this.topAffixedTriggerScrollTop = null
}
const handleScroll = (e) => {
const containerEl = scrollElementRef.value
if (affixedRef.value) {
if (containerEl.scrollTop < topAffixedTriggerScrollTopRef.value) {
stickToTopRef.value = false
topAffixedTriggerScrollTopRef.value = null
}
if (containerEl.scrollTop > this.bottomAffixedTriggerScrollTop) {
this.stickToBottom = false
this.bottomAffixedTriggerScrollTop = null
if (containerEl.scrollTop > bottomAffixedTriggerScrollTopRef.value) {
stickToBottomRef.value = false
bottomAffixedTriggerScrollTopRef.value = null
}
return
}
const containerRect = containerEl.getBoundingClientRect()
const affixRect = this.$el.getBoundingClientRect()
const affixRect = selfRef.value.getBoundingClientRect()
const pxToTop = affixRect.top - containerRect.top
const pxToBottom = containerRect.bottom - affixRect.bottom
const { mergedOffsetTop, mergedOffsetBottom } = this
const mergedOffsetTop = mergedOffsetTopRef.value
const mergedOffsetBottom = mergedOffsetBottomRef.value
if (mergedOffsetTop !== undefined && pxToTop <= mergedOffsetTop) {
this.stickToTop = true
this.topAffixedTriggerScrollTop =
stickToTopRef.value = true
topAffixedTriggerScrollTopRef.value =
containerEl.scrollTop - (mergedOffsetTop - pxToTop)
} else {
this.stickToTop = false
this.topAffixedTriggerScrollTop = null
stickToTopRef.value = false
topAffixedTriggerScrollTopRef.value = null
}
if (
mergedOffsetBottom !== undefined &&
pxToBottom <= mergedOffsetBottom
) {
this.stickToBottom = true
this.bottomAffixedTriggerScrollTop =
stickToBottomRef.value = true
bottomAffixedTriggerScrollTopRef.value =
containerEl.scrollTop + mergedOffsetBottom - pxToBottom
} else {
this.stickToBottom = false
this.bottomAffixedTriggerScrollTop = null
stickToBottomRef.value = false
bottomAffixedTriggerScrollTopRef.value = null
}
}
onMounted(() => {
init()
})
onBeforeUnmount(() => {
const scrollElement = scrollElementRef.value
if (scrollElement) {
scrollElement.removeEventListener('scroll', handleScroll)
}
})
return {
...useConfig(props),
selfRef,
scrollElement: scrollElementRef,
stickToTop: stickToTopRef,
stickToBottom: stickToBottomRef,
bottomAffixedTriggerScrollTop: bottomAffixedTriggerScrollTopRef,
topAffixedTriggerScrollTop: topAffixedTriggerScrollTopRef,
affixed: affixedRef,
mergedstyle: computed(() => {
const style = {}
if (stickToTopRef.value && mergedOffsetTopRef.value !== undefined) {
style.top = `${mergedTopRef.value}px`
}
if (
stickToBottomRef.value &&
mergedOffsetBottomRef.value !== undefined
) {
style.bottom = `${mergedBottomRef.value}px`
}
return style
})
}
}
}
</script>

View File

@ -1,18 +0,0 @@
import { c, cB, cM } from '../../../_utils/cssr'
export default c([
() => {
return cB(
'affix',
[
cM('affixed', {
position: 'fixed'
}, [
cM('absolute-positioned', {
position: 'absolute'
})
])
]
)
}
])

View File

@ -0,0 +1,14 @@
import { cB, cM } from '../../../_utils/cssr'
export default cB(
'affix',
[
cM('affixed', {
position: 'fixed'
}, [
cM('absolute-positioned', {
position: 'absolute'
})
])
]
)

View File

@ -1,9 +0,0 @@
import baseStyle from './base.cssr.js'
export default [
{
key: 'mergedTheme',
watch: ['mergedTheme'],
CNode: baseStyle
}
]

View File

@ -1,11 +1 @@
import create from '../../_styles/utils/create-component-base'
import { baseDark } from '../../_styles/base'
export default create({
theme: 'dark',
name: 'Affix',
peer: [baseDark],
getLocalVars () {
return {}
}
})
export default {}

View File

@ -1,11 +1 @@
import create from '../../_styles/utils/create-component-base'
import { baseLight } from '../../_styles/base'
export default create({
theme: 'light',
name: 'Affix',
peer: [baseLight],
getLocalVars () {
return {}
}
})
export default {}

View File

@ -1,92 +1,90 @@
import { c, cB, cNotM, cE, cM } from '../../../_utils/cssr'
import { cB, cNotM, cE, cM } from '../../../_utils/cssr'
// vars:
// --bezier
// --color
// --text-color
// --font-weight
export default c([
cB(
'divider', `
position: relative;
display: flex;
width: 100%;
box-sizing: border-box;
font-size: 16px;
color: var(--text-color);
transition:
color .3s var(--bezier),
background-color .3s var(--bezier);
export default cB(
'divider', `
position: relative;
display: flex;
width: 100%;
box-sizing: border-box;
font-size: 16px;
color: var(--text-color);
transition:
color .3s var(--bezier),
background-color .3s var(--bezier);
`,
[
cNotM('vertical', `
margin-top: 24px;
margin-bottom: 24px;
`,
[
cNotM('vertical', `
margin-top: 24px;
margin-bottom: 24px;
`,
[
cNotM('no-title', `
display: flex;
align-items: center;
`)
]),
cE('title', `
cNotM('no-title', `
display: flex;
align-items: center;
margin-left: 12px;
margin-right: 12px;
white-space: nowrap;
font-weight: var(--font-weight);
`),
cM('title-position-left', [
cE('line', [
cM('left', {
width: '28px'
})
])
]),
cM('title-position-right', [
cE('line', [
cM('right', {
width: '28px'
})
])
]),
cM('dashed', [
cE('line', `
background-color: transparent;
height: 0px;
width: 100%;
border-style: dashed;
border-width: 1px 0 0;
`)
]),
cM('vertical', `
display: inline-block;
height: 1em;
margin: 0 8px;
vertical-align: middle;
width: 1px;
`),
`)
]),
cE('title', `
display: flex;
align-items: center;
margin-left: 12px;
margin-right: 12px;
white-space: nowrap;
font-weight: var(--font-weight);
`),
cM('title-position-left', [
cE('line', [
cM('left', {
width: '28px'
})
])
]),
cM('title-position-right', [
cE('line', [
cM('right', {
width: '28px'
})
])
]),
cM('dashed', [
cE('line', `
border: none;
transition: background-color .3s var(--bezier), border-color .3s var(--bezier);
height: 1px;
background-color: transparent;
height: 0px;
width: 100%;
margin: 0;
`),
cNotM('dashed', [
cE('line', {
backgroundColor: 'var(--color)'
})
]),
cM('dashed', [
cE('line', {
borderColor: 'var(--color)'
})
]),
cM('vertical', {
border-style: dashed;
border-width: 1px 0 0;
`)
]),
cM('vertical', `
display: inline-block;
height: 1em;
margin: 0 8px;
vertical-align: middle;
width: 1px;
`),
cE('line', `
border: none;
transition: background-color .3s var(--bezier), border-color .3s var(--bezier);
height: 1px;
width: 100%;
margin: 0;
`),
cNotM('dashed', [
cE('line', {
backgroundColor: 'var(--color)'
})
]
)
])
]),
cM('dashed', [
cE('line', {
borderColor: 'var(--color)'
})
]),
cM('vertical', {
backgroundColor: 'var(--color)'
})
]
)

View File

@ -17,7 +17,7 @@ export {
export { baseWaveDark, baseWaveLight } from './_base/wave/styles'
// exposed style
export { baseDark, baseLight } from './_styles/base'
export { affixDark, affixLight } from './affix/styles'
// export { affixDark, affixLight } from './affix/styles'
export { alertDark, alertLight } from './alert/styles'
export { anchorDark, anchorLight } from './anchor/styles'
export { autoCompleteDark, autoCompleteLight } from './auto-complete/styles'