refactor(Anchor): use composition api (#4054)
parent
1139aa5f87
commit
1877d66cc5
|
@ -1,12 +1,21 @@
|
|||
import { defineComponent, inject, nextTick, provide } from 'vue';
|
||||
import {
|
||||
defineComponent,
|
||||
inject,
|
||||
nextTick,
|
||||
onBeforeUnmount,
|
||||
onMounted,
|
||||
onUpdated,
|
||||
provide,
|
||||
reactive,
|
||||
ref,
|
||||
getCurrentInstance,
|
||||
} from 'vue';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import classNames from '../_util/classNames';
|
||||
import addEventListener from '../vc-util/Dom/addEventListener';
|
||||
import Affix from '../affix';
|
||||
import scrollTo from '../_util/scrollTo';
|
||||
import getScroll from '../_util/getScroll';
|
||||
import { findDOMNode } from '../_util/props-util';
|
||||
import BaseMixin from '../_util/BaseMixin';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
|
||||
function getDefaultContainer() {
|
||||
|
@ -77,76 +86,26 @@ export interface AnchorState {
|
|||
|
||||
export default defineComponent({
|
||||
name: 'AAnchor',
|
||||
mixins: [BaseMixin],
|
||||
inheritAttrs: false,
|
||||
props: AnchorProps,
|
||||
emits: ['change', 'click'],
|
||||
setup() {
|
||||
return {
|
||||
configProvider: inject('configProvider', defaultConfigProvider),
|
||||
};
|
||||
},
|
||||
data() {
|
||||
// this.links = [];
|
||||
// this.sPrefixCls = '';
|
||||
return {
|
||||
setup(props, { emit, attrs, slots }) {
|
||||
const configProvider = inject('configProvider', defaultConfigProvider);
|
||||
const instance = getCurrentInstance();
|
||||
const inkNodeRef = ref();
|
||||
const anchorRef = ref();
|
||||
const state = reactive<AnchorState>({
|
||||
activeLink: null,
|
||||
links: [],
|
||||
sPrefixCls: '',
|
||||
scrollContainer: null,
|
||||
scrollEvent: null,
|
||||
animating: false,
|
||||
} as AnchorState;
|
||||
},
|
||||
created() {
|
||||
provide('antAnchor', {
|
||||
registerLink: (link: string) => {
|
||||
if (!this.links.includes(link)) {
|
||||
this.links.push(link);
|
||||
}
|
||||
},
|
||||
unregisterLink: (link: string) => {
|
||||
const index = this.links.indexOf(link);
|
||||
if (index !== -1) {
|
||||
this.links.splice(index, 1);
|
||||
}
|
||||
},
|
||||
$data: this.$data,
|
||||
scrollTo: this.handleScrollTo,
|
||||
} as AntAnchor);
|
||||
provide('antAnchorContext', this);
|
||||
},
|
||||
mounted() {
|
||||
nextTick(() => {
|
||||
const { getContainer } = this;
|
||||
this.scrollContainer = getContainer();
|
||||
this.scrollEvent = addEventListener(this.scrollContainer, 'scroll', this.handleScroll);
|
||||
this.handleScroll();
|
||||
});
|
||||
},
|
||||
updated() {
|
||||
nextTick(() => {
|
||||
if (this.scrollEvent) {
|
||||
const { getContainer } = this;
|
||||
const currentContainer = getContainer();
|
||||
if (this.scrollContainer !== currentContainer) {
|
||||
this.scrollContainer = currentContainer;
|
||||
this.scrollEvent.remove();
|
||||
this.scrollEvent = addEventListener(this.scrollContainer, 'scroll', this.handleScroll);
|
||||
this.handleScroll();
|
||||
}
|
||||
}
|
||||
this.updateInk();
|
||||
});
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.scrollEvent) {
|
||||
this.scrollEvent.remove();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCurrentActiveLink(offsetTop = 0, bounds = 5) {
|
||||
const { getCurrentAnchor } = this;
|
||||
|
||||
// func...
|
||||
const getCurrentActiveLink = (offsetTop = 0, bounds = 5) => {
|
||||
const { getCurrentAnchor } = props;
|
||||
|
||||
if (typeof getCurrentAnchor === 'function') {
|
||||
return getCurrentAnchor();
|
||||
|
@ -157,9 +116,9 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
const linkSections: Array<Section> = [];
|
||||
const { getContainer } = this;
|
||||
const { getContainer } = props;
|
||||
const container = getContainer();
|
||||
this.links.forEach(link => {
|
||||
state.links.forEach(link => {
|
||||
const sharpLinkMatch = sharpMatcherRegx.exec(link.toString());
|
||||
if (!sharpLinkMatch) {
|
||||
return;
|
||||
|
@ -181,12 +140,18 @@ export default defineComponent({
|
|||
return maxSection.link;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
};
|
||||
const setCurrentActiveLink = (link: string) => {
|
||||
const { activeLink } = state;
|
||||
if (activeLink !== link) {
|
||||
state.activeLink = link;
|
||||
emit('change', link);
|
||||
}
|
||||
};
|
||||
const handleScrollTo = (link: string) => {
|
||||
const { offsetTop, getContainer, targetOffset } = props;
|
||||
|
||||
handleScrollTo(link: string) {
|
||||
const { offsetTop, getContainer, targetOffset } = this;
|
||||
|
||||
this.setCurrentActiveLink(link);
|
||||
setCurrentActiveLink(link);
|
||||
const container = getContainer();
|
||||
const scrollTop = getScroll(container, true);
|
||||
const sharpLinkMatch = sharpMatcherRegx.exec(link);
|
||||
|
@ -201,99 +166,129 @@ export default defineComponent({
|
|||
const eleOffsetTop = getOffsetTop(targetElement, container);
|
||||
let y = scrollTop + eleOffsetTop;
|
||||
y -= targetOffset !== undefined ? targetOffset : offsetTop || 0;
|
||||
this.animating = true;
|
||||
state.animating = true;
|
||||
|
||||
scrollTo(y, {
|
||||
callback: () => {
|
||||
this.animating = false;
|
||||
state.animating = false;
|
||||
},
|
||||
getContainer,
|
||||
});
|
||||
},
|
||||
setCurrentActiveLink(link: string) {
|
||||
const { activeLink } = this;
|
||||
|
||||
if (activeLink !== link) {
|
||||
this.setState({
|
||||
activeLink: link,
|
||||
});
|
||||
this.$emit('change', link);
|
||||
}
|
||||
},
|
||||
|
||||
handleScroll() {
|
||||
if (this.animating) {
|
||||
};
|
||||
const handleScroll = () => {
|
||||
if (state.animating) {
|
||||
return;
|
||||
}
|
||||
const { offsetTop, bounds, targetOffset } = this;
|
||||
const currentActiveLink = this.getCurrentActiveLink(
|
||||
const { offsetTop, bounds, targetOffset } = props;
|
||||
const currentActiveLink = getCurrentActiveLink(
|
||||
targetOffset !== undefined ? targetOffset : offsetTop || 0,
|
||||
bounds,
|
||||
);
|
||||
this.setCurrentActiveLink(currentActiveLink);
|
||||
},
|
||||
setCurrentActiveLink(currentActiveLink);
|
||||
};
|
||||
|
||||
updateInk() {
|
||||
const updateInk = () => {
|
||||
if (typeof document === 'undefined') {
|
||||
return;
|
||||
}
|
||||
const { sPrefixCls } = this;
|
||||
const linkNode = findDOMNode(this).getElementsByClassName(
|
||||
`${sPrefixCls}-link-title-active`,
|
||||
)[0];
|
||||
const { sPrefixCls } = state;
|
||||
const linkNode = anchorRef.value.getElementsByClassName(`${sPrefixCls}-link-title-active`)[0];
|
||||
if (linkNode) {
|
||||
(this.$refs.inkNode as HTMLElement).style.top = `${linkNode.offsetTop +
|
||||
(inkNodeRef.value as HTMLElement).style.top = `${linkNode.offsetTop +
|
||||
linkNode.clientHeight / 2 -
|
||||
4.5}px`;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
offsetTop,
|
||||
affix,
|
||||
showInkInFixed,
|
||||
activeLink,
|
||||
$slots,
|
||||
getContainer,
|
||||
} = this;
|
||||
const getPrefixCls = this.configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
|
||||
this.sPrefixCls = prefixCls;
|
||||
|
||||
const inkClass = classNames(`${prefixCls}-ink-ball`, {
|
||||
visible: activeLink,
|
||||
});
|
||||
|
||||
const wrapperClass = classNames(this.wrapperClass, `${prefixCls}-wrapper`);
|
||||
|
||||
const anchorClass = classNames(prefixCls, {
|
||||
fixed: !affix && !showInkInFixed,
|
||||
});
|
||||
|
||||
const wrapperStyle = {
|
||||
maxHeight: offsetTop ? `calc(100vh - ${offsetTop}px)` : '100vh',
|
||||
...this.wrapperStyle,
|
||||
};
|
||||
const anchorContent = (
|
||||
<div class={wrapperClass} style={wrapperStyle}>
|
||||
<div class={anchorClass}>
|
||||
<div class={`${prefixCls}-ink`}>
|
||||
<span class={inkClass} ref="inkNode" />
|
||||
</div>
|
||||
{$slots.default?.()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return !affix ? (
|
||||
anchorContent
|
||||
) : (
|
||||
<Affix {...this.$attrs} offsetTop={offsetTop} target={getContainer}>
|
||||
{anchorContent}
|
||||
</Affix>
|
||||
);
|
||||
// provide data
|
||||
provide('antAnchor', {
|
||||
registerLink: (link: string) => {
|
||||
if (!state.links.includes(link)) {
|
||||
state.links.push(link);
|
||||
}
|
||||
},
|
||||
unregisterLink: (link: string) => {
|
||||
const index = state.links.indexOf(link);
|
||||
if (index !== -1) {
|
||||
state.links.splice(index, 1);
|
||||
}
|
||||
},
|
||||
$data: state,
|
||||
scrollTo: handleScrollTo,
|
||||
} as AntAnchor);
|
||||
provide('antAnchorContext', instance);
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
const { getContainer } = props;
|
||||
state.scrollContainer = getContainer();
|
||||
state.scrollEvent = addEventListener(state.scrollContainer, 'scroll', handleScroll);
|
||||
handleScroll();
|
||||
});
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
if (state.scrollEvent) {
|
||||
state.scrollEvent.remove();
|
||||
}
|
||||
});
|
||||
onUpdated(() => {
|
||||
if (state.scrollEvent) {
|
||||
const { getContainer } = props;
|
||||
const currentContainer = getContainer();
|
||||
if (state.scrollContainer !== currentContainer) {
|
||||
state.scrollContainer = currentContainer;
|
||||
state.scrollEvent.remove();
|
||||
state.scrollEvent = addEventListener(state.scrollContainer, 'scroll', handleScroll);
|
||||
handleScroll();
|
||||
}
|
||||
}
|
||||
updateInk();
|
||||
});
|
||||
|
||||
return () => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
offsetTop,
|
||||
affix,
|
||||
showInkInFixed,
|
||||
getContainer,
|
||||
} = props;
|
||||
const getPrefixCls = configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
|
||||
state.sPrefixCls = prefixCls;
|
||||
|
||||
const inkClass = classNames(`${prefixCls}-ink-ball`, {
|
||||
visible: state.activeLink,
|
||||
});
|
||||
|
||||
const wrapperClass = classNames(props.wrapperClass, `${prefixCls}-wrapper`);
|
||||
|
||||
const anchorClass = classNames(prefixCls, {
|
||||
fixed: !affix && !showInkInFixed,
|
||||
});
|
||||
|
||||
const wrapperStyle = {
|
||||
maxHeight: offsetTop ? `calc(100vh - ${offsetTop}px)` : '100vh',
|
||||
...props.wrapperStyle,
|
||||
};
|
||||
const anchorContent = (
|
||||
<div class={wrapperClass} style={wrapperStyle} ref={anchorRef}>
|
||||
<div class={anchorClass}>
|
||||
<div class={`${prefixCls}-ink`}>
|
||||
<span class={inkClass} ref={inkNodeRef} />
|
||||
</div>
|
||||
{slots.default?.()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return !affix ? (
|
||||
anchorContent
|
||||
) : (
|
||||
<Affix {...attrs} offsetTop={offsetTop} target={getContainer}>
|
||||
{anchorContent}
|
||||
</Affix>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
import { ComponentPublicInstance, defineComponent, inject, nextTick } from 'vue';
|
||||
import {
|
||||
ComponentInternalInstance,
|
||||
defineComponent,
|
||||
inject,
|
||||
nextTick,
|
||||
onBeforeUnmount,
|
||||
onMounted,
|
||||
watch,
|
||||
} from 'vue';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import { getComponent } from '../_util/props-util';
|
||||
import { getPropsSlot } from '../_util/props-util';
|
||||
import classNames from '../_util/classNames';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import { AntAnchor } from './Anchor';
|
||||
|
@ -18,72 +26,72 @@ const AnchorLinkProps = {
|
|||
export default defineComponent({
|
||||
name: 'AAnchorLink',
|
||||
props: AnchorLinkProps,
|
||||
setup() {
|
||||
return {
|
||||
antAnchor: inject('antAnchor', {
|
||||
registerLink: noop,
|
||||
unregisterLink: noop,
|
||||
scrollTo: noop,
|
||||
$data: {},
|
||||
} as AntAnchor),
|
||||
antAnchorContext: inject('antAnchorContext', {}) as ComponentPublicInstance,
|
||||
configProvider: inject('configProvider', defaultConfigProvider),
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
href(val, oldVal) {
|
||||
nextTick(() => {
|
||||
this.antAnchor.unregisterLink(oldVal);
|
||||
this.antAnchor.registerLink(val);
|
||||
});
|
||||
},
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
const antAnchor = inject('antAnchor', {
|
||||
registerLink: noop,
|
||||
unregisterLink: noop,
|
||||
scrollTo: noop,
|
||||
$data: {},
|
||||
} as AntAnchor);
|
||||
const antAnchorContext = inject('antAnchorContext', {}) as ComponentInternalInstance;
|
||||
const configProvider = inject('configProvider', defaultConfigProvider);
|
||||
|
||||
mounted() {
|
||||
this.antAnchor.registerLink(this.href);
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
this.antAnchor.unregisterLink(this.href);
|
||||
},
|
||||
methods: {
|
||||
handleClick(e: Event) {
|
||||
this.antAnchor.scrollTo(this.href);
|
||||
const { scrollTo } = this.antAnchor;
|
||||
const { href, title } = this.$props;
|
||||
if (this.antAnchorContext.$emit) {
|
||||
this.antAnchorContext.$emit('click', e, { title, href });
|
||||
const handleClick = (e: Event) => {
|
||||
// antAnchor.scrollTo(props.href);
|
||||
const { scrollTo } = antAnchor;
|
||||
const { href, title } = props;
|
||||
if (antAnchorContext.emit) {
|
||||
antAnchorContext.emit('click', e, { title, href });
|
||||
}
|
||||
scrollTo(href);
|
||||
},
|
||||
},
|
||||
render() {
|
||||
const { prefixCls: customizePrefixCls, href, $slots, target } = this;
|
||||
};
|
||||
|
||||
const getPrefixCls = this.configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
|
||||
|
||||
const title = getComponent(this, 'title');
|
||||
const active = this.antAnchor.$data.activeLink === href;
|
||||
const wrapperClassName = classNames(`${prefixCls}-link`, {
|
||||
[`${prefixCls}-link-active`]: active,
|
||||
});
|
||||
const titleClassName = classNames(`${prefixCls}-link-title`, {
|
||||
[`${prefixCls}-link-title-active`]: active,
|
||||
});
|
||||
return (
|
||||
<div class={wrapperClassName}>
|
||||
<a
|
||||
class={titleClassName}
|
||||
href={href}
|
||||
title={typeof title === 'string' ? title : ''}
|
||||
target={target}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
{title}
|
||||
</a>
|
||||
{$slots.default?.()}
|
||||
</div>
|
||||
watch(
|
||||
() => props.href,
|
||||
(val, oldVal) => {
|
||||
nextTick(() => {
|
||||
antAnchor.unregisterLink(oldVal);
|
||||
antAnchor.registerLink(val);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
antAnchor.registerLink(props.href);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
antAnchor.unregisterLink(props.href);
|
||||
});
|
||||
|
||||
return () => {
|
||||
const { prefixCls: customizePrefixCls, href, target } = props;
|
||||
|
||||
const getPrefixCls = configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
|
||||
|
||||
const title = getPropsSlot(slots, props, 'title');
|
||||
const active = antAnchor.$data.activeLink === href;
|
||||
const wrapperClassName = classNames(`${prefixCls}-link`, {
|
||||
[`${prefixCls}-link-active`]: active,
|
||||
});
|
||||
const titleClassName = classNames(`${prefixCls}-link-title`, {
|
||||
[`${prefixCls}-link-title-active`]: active,
|
||||
});
|
||||
return (
|
||||
<div class={wrapperClassName}>
|
||||
<a
|
||||
class={titleClassName}
|
||||
href={href}
|
||||
title={typeof title === 'string' ? title : ''}
|
||||
target={target}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{title}
|
||||
</a>
|
||||
{slots.default?.()}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import * as Vue from 'vue';
|
||||
import { asyncExpect } from '@/tests/utils';
|
||||
import { ref } from 'vue';
|
||||
import Anchor from '..';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
@ -9,13 +8,20 @@ let idCounter = 0;
|
|||
const getHashUrl = () => `Anchor-API-${idCounter++}`;
|
||||
|
||||
describe('Anchor Render', () => {
|
||||
it('Anchor render perfectly', done => {
|
||||
it('Anchor render perfectly', async done => {
|
||||
const hash = getHashUrl();
|
||||
const anchor = ref(null);
|
||||
const activeLink = ref(null);
|
||||
const wrapper = mount(
|
||||
{
|
||||
render() {
|
||||
return (
|
||||
<Anchor ref="anchor">
|
||||
<Anchor
|
||||
ref={anchor}
|
||||
onChange={current => {
|
||||
activeLink.value = current;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>
|
||||
);
|
||||
|
@ -23,22 +29,28 @@ describe('Anchor Render', () => {
|
|||
},
|
||||
{ sync: false },
|
||||
);
|
||||
Vue.nextTick(() => {
|
||||
|
||||
wrapper.vm.$nextTick(() => {
|
||||
wrapper.find(`a[href="#${hash}`).trigger('click');
|
||||
wrapper.vm.$refs.anchor.handleScroll();
|
||||
|
||||
setTimeout(() => {
|
||||
expect(wrapper.vm.$refs.anchor.$data.activeLink).not.toBe(null);
|
||||
expect(activeLink.value).not.toBe(hash);
|
||||
done();
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - click', done => {
|
||||
it('Anchor render perfectly for complete href - click', async done => {
|
||||
const currentActiveLink = ref(null);
|
||||
const wrapper = mount(
|
||||
{
|
||||
render() {
|
||||
return (
|
||||
<Anchor ref="anchor">
|
||||
<Anchor
|
||||
ref="anchor"
|
||||
onChange={current => {
|
||||
currentActiveLink.value = current;
|
||||
}}
|
||||
>
|
||||
<Link href="http://www.example.com/#API" title="API" />
|
||||
</Anchor>
|
||||
);
|
||||
|
@ -46,160 +58,163 @@ describe('Anchor Render', () => {
|
|||
},
|
||||
{ sync: false },
|
||||
);
|
||||
Vue.nextTick(() => {
|
||||
|
||||
wrapper.vm.$nextTick(() => {
|
||||
wrapper.find('a[href="http://www.example.com/#API"]').trigger('click');
|
||||
expect(wrapper.vm.$refs.anchor.$data.activeLink).toBe('http://www.example.com/#API');
|
||||
|
||||
expect(currentActiveLink.value).toBe('http://www.example.com/#API');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - scroll', done => {
|
||||
const wrapper = mount(
|
||||
{
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div id="API">Hello</div>
|
||||
<Anchor ref="anchor">
|
||||
<Link href="http://www.example.com/#API" title="API" />
|
||||
</Anchor>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{ sync: false, attachTo: 'body' },
|
||||
);
|
||||
Vue.nextTick(() => {
|
||||
wrapper.vm.$refs.anchor.handleScroll();
|
||||
expect(wrapper.vm.$refs.anchor.$data.activeLink).toBe('http://www.example.com/#API');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - scrollTo', async () => {
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
const wrapper = mount(
|
||||
{
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div id="API">Hello</div>
|
||||
<Anchor ref="anchor">
|
||||
<Link href="##API" title="API" />
|
||||
</Anchor>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{ sync: false, attachTo: 'body' },
|
||||
);
|
||||
await asyncExpect(() => {
|
||||
wrapper.vm.$refs.anchor.handleScrollTo('##API');
|
||||
expect(wrapper.vm.$refs.anchor.$data.activeLink).toBe('##API');
|
||||
expect(scrollToSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
await asyncExpect(() => {
|
||||
expect(scrollToSpy).toHaveBeenCalled();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
it('should remove listener when unmount', async () => {
|
||||
const wrapper = mount(
|
||||
{
|
||||
render() {
|
||||
return (
|
||||
<Anchor ref="anchor">
|
||||
<Link href="#API" title="API" />
|
||||
</Anchor>
|
||||
);
|
||||
},
|
||||
},
|
||||
{ sync: false, attachTo: 'body' },
|
||||
);
|
||||
await asyncExpect(() => {
|
||||
const removeListenerSpy = jest.spyOn(wrapper.vm.$refs.anchor.scrollEvent, 'remove');
|
||||
wrapper.unmount();
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should unregister link when unmount children', async () => {
|
||||
const wrapper = mount(
|
||||
{
|
||||
props: {
|
||||
showLink: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
/*
|
||||
it('Anchor render perfectly for complete href - scroll', done => {
|
||||
const wrapper = mount(
|
||||
{
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div id="API">Hello</div>
|
||||
<Anchor ref="anchor">
|
||||
<Link href="http://www.example.com/#API" title="API" />
|
||||
</Anchor>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Anchor ref="anchor">{this.showLink ? <Link href="#API" title="API" /> : null}</Anchor>
|
||||
);
|
||||
},
|
||||
},
|
||||
{ sync: false, attachTo: 'body' },
|
||||
);
|
||||
await asyncExpect(() => {
|
||||
expect(wrapper.vm.$refs.anchor.links).toEqual(['#API']);
|
||||
wrapper.setProps({ showLink: false });
|
||||
{ sync: false, attachTo: 'body' },
|
||||
);
|
||||
wrapper.vm.$nextTick(() => {
|
||||
wrapper.vm.$refs.anchor.handleScroll();
|
||||
expect(wrapper.vm.$refs.anchor.$data.activeLink).toBe('http://www.example.com/#API');
|
||||
done();
|
||||
});
|
||||
});
|
||||
await asyncExpect(() => {
|
||||
expect(wrapper.vm.$refs.anchor.links).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should update links when link href update', async () => {
|
||||
const wrapper = mount(
|
||||
{
|
||||
props: ['href'],
|
||||
render() {
|
||||
return (
|
||||
<Anchor ref="anchor">
|
||||
<Link href={this.href} title="API" />
|
||||
</Anchor>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
sync: false,
|
||||
attachTo: 'body',
|
||||
props: {
|
||||
href: '#API',
|
||||
},
|
||||
},
|
||||
);
|
||||
await asyncExpect(() => {
|
||||
expect(wrapper.vm.$refs.anchor.links).toEqual(['#API']);
|
||||
wrapper.setProps({ href: '#API_1' });
|
||||
});
|
||||
await asyncExpect(() => {
|
||||
expect(wrapper.vm.$refs.anchor.links).toEqual(['#API_1']);
|
||||
});
|
||||
});
|
||||
|
||||
it('Anchor onClick event', () => {
|
||||
let event;
|
||||
let link;
|
||||
const handleClick = (...arg) => ([event, link] = arg);
|
||||
|
||||
const href = '#API';
|
||||
const title = 'API';
|
||||
|
||||
const wrapper = mount({
|
||||
render() {
|
||||
return (
|
||||
<Anchor ref="anchorRef" onClick={handleClick}>
|
||||
<Link href={href} title={title} />
|
||||
</Anchor>
|
||||
it('Anchor render perfectly for complete href - scrollTo', async () => {
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
const wrapper = mount(
|
||||
{
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div id="API">Hello</div>
|
||||
<Anchor ref="anchor">
|
||||
<Link href="##API" title="API" />
|
||||
</Anchor>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{ sync: false, attachTo: 'body' },
|
||||
);
|
||||
},
|
||||
});
|
||||
await asyncExpect(() => {
|
||||
wrapper.vm.$refs.anchor.handleScrollTo('##API');
|
||||
expect(wrapper.vm.$refs.anchor.$data.activeLink).toBe('##API');
|
||||
expect(scrollToSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
await asyncExpect(() => {
|
||||
expect(scrollToSpy).toHaveBeenCalled();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
wrapper.find(`a[href="${href}"]`).trigger('click');
|
||||
it('should remove listener when unmount', async () => {
|
||||
const wrapper = mount(
|
||||
{
|
||||
render() {
|
||||
return (
|
||||
<Anchor ref="anchor">
|
||||
<Link href="#API" title="API" />
|
||||
</Anchor>
|
||||
);
|
||||
},
|
||||
},
|
||||
{ sync: false, attachTo: 'body' },
|
||||
);
|
||||
await asyncExpect(() => {
|
||||
const removeListenerSpy = jest.spyOn(wrapper.vm.$refs.anchor.scrollEvent, 'remove');
|
||||
wrapper.unmount();
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
wrapper.vm.$refs.anchorRef.handleScroll();
|
||||
expect(event).not.toBe(undefined);
|
||||
expect(link).toEqual({ href, title });
|
||||
});
|
||||
it('should unregister link when unmount children', async () => {
|
||||
const wrapper = mount(
|
||||
{
|
||||
props: {
|
||||
showLink: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Anchor ref="anchor">{this.showLink ? <Link href="#API" title="API" /> : null}</Anchor>
|
||||
);
|
||||
},
|
||||
},
|
||||
{ sync: false, attachTo: 'body' },
|
||||
);
|
||||
await asyncExpect(() => {
|
||||
expect(wrapper.vm.$refs.anchor.links).toEqual(['#API']);
|
||||
wrapper.setProps({ showLink: false });
|
||||
});
|
||||
await asyncExpect(() => {
|
||||
expect(wrapper.vm.$refs.anchor.links).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should update links when link href update', async () => {
|
||||
const wrapper = mount(
|
||||
{
|
||||
props: ['href'],
|
||||
render() {
|
||||
return (
|
||||
<Anchor ref="anchor">
|
||||
<Link href={this.href} title="API" />
|
||||
</Anchor>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
sync: false,
|
||||
attachTo: 'body',
|
||||
props: {
|
||||
href: '#API',
|
||||
},
|
||||
},
|
||||
);
|
||||
await asyncExpect(() => {
|
||||
expect(wrapper.vm.$refs.anchor.links).toEqual(['#API']);
|
||||
wrapper.setProps({ href: '#API_1' });
|
||||
});
|
||||
await asyncExpect(() => {
|
||||
expect(wrapper.vm.$refs.anchor.links).toEqual(['#API_1']);
|
||||
});
|
||||
});
|
||||
|
||||
it('Anchor onClick event', () => {
|
||||
let event;
|
||||
let link;
|
||||
const handleClick = (...arg) => ([event, link] = arg);
|
||||
|
||||
const href = '#API';
|
||||
const title = 'API';
|
||||
|
||||
const anchorRef = Vue.ref(null);
|
||||
|
||||
const wrapper = mount({
|
||||
render() {
|
||||
return (
|
||||
<Anchor ref={anchorRef} onClick={handleClick}>
|
||||
<Link href={href} title={title} />
|
||||
</Anchor>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.find(`a[href="${href}"]`).trigger('click');
|
||||
anchorRef.value.handleScroll();
|
||||
expect(event).not.toBe(undefined);
|
||||
expect(link).toEqual({ href, title });
|
||||
}); */
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue