mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-03-31 14:20:53 +08:00
refactor(affix): composition api + new theme
This commit is contained in:
parent
b7cabf901a
commit
66a2fa2353
@ -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
|
||||
),
|
||||
|
@ -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>
|
||||
|
@ -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'
|
||||
})
|
||||
])
|
||||
]
|
||||
)
|
||||
}
|
||||
])
|
14
src/affix/src/styles/index.cssr.js
Normal file
14
src/affix/src/styles/index.cssr.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { cB, cM } from '../../../_utils/cssr'
|
||||
|
||||
export default cB(
|
||||
'affix',
|
||||
[
|
||||
cM('affixed', {
|
||||
position: 'fixed'
|
||||
}, [
|
||||
cM('absolute-positioned', {
|
||||
position: 'absolute'
|
||||
})
|
||||
])
|
||||
]
|
||||
)
|
@ -1,9 +0,0 @@
|
||||
import baseStyle from './base.cssr.js'
|
||||
|
||||
export default [
|
||||
{
|
||||
key: 'mergedTheme',
|
||||
watch: ['mergedTheme'],
|
||||
CNode: baseStyle
|
||||
}
|
||||
]
|
@ -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 {}
|
||||
|
@ -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 {}
|
||||
|
@ -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)'
|
||||
})
|
||||
]
|
||||
)
|
||||
|
@ -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'
|
||||
|
Loading…
x
Reference in New Issue
Block a user