diff --git a/packages/varlet-vue2-eslint-config/index.js b/packages/varlet-vue2-eslint-config/index.js
index 4f4ecca..d715bde 100644
--- a/packages/varlet-vue2-eslint-config/index.js
+++ b/packages/varlet-vue2-eslint-config/index.js
@@ -74,5 +74,6 @@ module.exports = {
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-use-before-define': 'off',
+ 'vue/valid-v-bind': 'off',
},
}
diff --git a/packages/varlet-vue2-ui/src/index-anchor/IndexAnchor.vue b/packages/varlet-vue2-ui/src/index-anchor/IndexAnchor.vue
new file mode 100644
index 0000000..cd718c2
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-anchor/IndexAnchor.vue
@@ -0,0 +1,95 @@
+
+
+
+ {{ name }}
+
+
+
+
+
+
+
diff --git a/packages/varlet-vue2-ui/src/index-anchor/docs/zh-CN.md b/packages/varlet-vue2-ui/src/index-anchor/docs/zh-CN.md
new file mode 100644
index 0000000..5f1e947
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-anchor/docs/zh-CN.md
@@ -0,0 +1,13 @@
+## API
+
+### 属性
+
+| 参数 | 说明 | 类型 | 默认值 |
+| ----- | -------------- | -------- | ---------- |
+| `index` | 索引字符 | _number_ \| _string_ | - |
+
+### 插槽
+
+| 名称 | 说明 | 参数 |
+| --- | --- | --- |
+| `default` | 自定义索引字符 | - |
\ No newline at end of file
diff --git a/packages/varlet-vue2-ui/src/index-anchor/index.ts b/packages/varlet-vue2-ui/src/index-anchor/index.ts
new file mode 100644
index 0000000..7e5af86
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-anchor/index.ts
@@ -0,0 +1,10 @@
+import type { VueConstructor } from 'vue'
+import IndexAnchor from './IndexAnchor.vue'
+
+IndexAnchor.install = function (app: VueConstructor) {
+ app.component(IndexAnchor.name, IndexAnchor)
+}
+
+export const _IndexAnchorComponent = IndexAnchor
+
+export default IndexAnchor
diff --git a/packages/varlet-vue2-ui/src/index-anchor/props.ts b/packages/varlet-vue2-ui/src/index-anchor/props.ts
new file mode 100644
index 0000000..e65c87e
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-anchor/props.ts
@@ -0,0 +1,5 @@
+export const props = {
+ index: {
+ type: [Number, String],
+ },
+}
diff --git a/packages/varlet-vue2-ui/src/index-bar/IndexBar.vue b/packages/varlet-vue2-ui/src/index-bar/IndexBar.vue
new file mode 100644
index 0000000..1761e61
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-bar/IndexBar.vue
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+
diff --git a/packages/varlet-vue2-ui/src/index-bar/__tests__/__snapshots__/index.spec.js.snap b/packages/varlet-vue2-ui/src/index-bar/__tests__/__snapshots__/index.spec.js.snap
new file mode 100644
index 0000000..e43c124
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-bar/__tests__/__snapshots__/index.spec.js.snap
@@ -0,0 +1,795 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`test click anchor to trigger change event 1`] = `
+"
+
+
+
test
+
test
+
test
+
test
+
test
+
+
test
+
test
+
test
+
test
+
test
+
+
test
+
test
+
test
+
test
+
test
+
+
test
+
test
+
test
+
test
+
test
+
+
+
+
"
+`;
+
+exports[`test indexBar example 1`] = `
+"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+ A
+
+ -
+ B
+
+ -
+ C
+
+ -
+ D
+
+ -
+ E
+
+ -
+ F
+
+ -
+ G
+
+ -
+ H
+
+ -
+ I
+
+ -
+ J
+
+ -
+ K
+
+ -
+ L
+
+ -
+ M
+
+ -
+ N
+
+ -
+ O
+
+ -
+ P
+
+ -
+ Q
+
+ -
+ R
+
+ -
+ S
+
+ -
+ T
+
+ -
+ U
+
+ -
+ V
+
+ -
+ W
+
+ -
+ X
+
+ -
+ Y
+
+ -
+ Z
+
+
+
"
+`;
diff --git a/packages/varlet-vue2-ui/src/index-bar/__tests__/index.spec.js b/packages/varlet-vue2-ui/src/index-bar/__tests__/index.spec.js
new file mode 100644
index 0000000..b9c2a2b
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-bar/__tests__/index.spec.js
@@ -0,0 +1,174 @@
+import example from '../example'
+import IndexBar from '..'
+import IndexAnchor from '../../index-anchor'
+import VarIndexBar from '../IndexBar'
+import VarIndexAnchor from '../../index-anchor/IndexAnchor'
+import { mount } from '@vue/test-utils'
+import Vue from 'vue'
+import { delay, mockScrollTo } from '../../utils/jest'
+
+test('test indexBar example', async () => {
+ const wrapper = mount(example)
+
+ await delay(500)
+
+ expect(wrapper.html()).toMatchSnapshot()
+})
+
+test('test indexBar and indexAnchor plugin', () => {
+ Vue.use(IndexBar).use(IndexAnchor)
+
+ expect(Vue.component(IndexBar.name)).toBeTruthy()
+ expect(Vue.component(IndexAnchor.name)).toBeTruthy()
+})
+
+test('test sticky prop and it is value equal false', () => {
+ const template = `
+
+ test A
+ test B
+
+ `
+ const wrapper = mount(
+ {
+ components: {
+ [VarIndexBar.name]: VarIndexBar,
+ [VarIndexAnchor.name]: VarIndexAnchor,
+ },
+ template,
+ },
+ { attachTo: document.body }
+ )
+
+ expect(wrapper.find('.var-sticky').exists()).toBeFalsy()
+})
+
+test('test, hideList and z-index prop', () => {
+ const template = `
+
+ test A
+
+ `
+ const wrapper = mount(
+ {
+ components: {
+ [VarIndexBar.name]: VarIndexBar,
+ [VarIndexAnchor.name]: VarIndexAnchor,
+ },
+ template,
+ },
+ { attachTo: document.body }
+ )
+
+ expect(wrapper.find('.var-sticky').exists()).toBeTruthy()
+
+ expect(wrapper.find('.var-index-bar__anchor-list').attributes('style').includes('display: none')).toBeTruthy()
+
+ expect(wrapper.find('.var-sticky').attributes('style')).toBe('z-index: 2;')
+})
+
+test('test click anchor to trigger change event', async () => {
+ mockScrollTo(HTMLElement)
+
+ const template = `
+
+
+ test A
+ test
test
test
test
test
+ test B
+ test
test
test
test
test
+ test C
+ test
test
test
test
test
+ test D
+ test
test
test
test
test
+ test E
+
+
+ `
+ const clickHandle = jest.fn()
+ const changeHandle = jest.fn()
+
+ const wrapper = mount(
+ {
+ components: {
+ [VarIndexBar.name]: VarIndexBar,
+ [VarIndexAnchor.name]: VarIndexAnchor,
+ },
+ methods: {
+ clickHandle,
+ changeHandle,
+ },
+ template,
+ },
+ { attachTo: document.body }
+ )
+
+ await delay(200)
+
+ wrapper.vm.$refs.bar.scrollTo('A')
+
+ await delay(100)
+
+ const anchorItems = wrapper.findAll('.var-index-bar__anchor-item')
+
+ expect(anchorItems[0].classes()).toContain('var-index-bar__anchor-item--active')
+
+ await anchorItems[1].trigger('click')
+
+ await delay(100)
+
+ expect(anchorItems[1].classes()).toContain('var-index-bar__anchor-item--active')
+
+ expect(changeHandle).toHaveBeenCalledTimes(2)
+ expect(clickHandle).toHaveBeenCalledTimes(1)
+ expect(wrapper.html()).toMatchSnapshot()
+
+ wrapper.destroy()
+})
+
+test('test scroll indexBar to trigger change event', async () => {
+ const template = `
+
+
+ test A
+ test
test
test
test
test
+ test B
+ test
test
test
test
test
+ test C
+ test
test
test
test
test
+ test D
+ test
test
test
test
test
+ test E
+
+
+ `
+ const changeHandle = jest.fn()
+
+ const wrapper = mount(
+ {
+ components: {
+ [VarIndexBar.name]: VarIndexBar,
+ [VarIndexAnchor.name]: VarIndexAnchor,
+ },
+ methods: {
+ changeHandle,
+ },
+ template,
+ },
+ { attachTo: document.body }
+ )
+
+ await delay(200)
+
+ wrapper.vm.$refs.bar.scrollTo('A')
+
+ await delay(100)
+
+ wrapper.element.scrollTop = 150
+
+ await wrapper.trigger('scroll')
+
+ await delay(0)
+
+ expect(changeHandle).toHaveBeenCalled()
+})
diff --git a/packages/varlet-vue2-ui/src/index-bar/docs/en-US.md b/packages/varlet-vue2-ui/src/index-bar/docs/en-US.md
new file mode 100644
index 0000000..6c5ab20
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-bar/docs/en-US.md
@@ -0,0 +1,112 @@
+# IndexBar
+
+### Intro
+
+Hyperlinks to scroll on one page.
+
+### Install
+
+```js
+import Vue from 'vue'
+import { IndexBar, IndexAnchor } from '@varlet-vue2/ui'
+
+Vue.use(IndexBar).use(IndexAnchor)
+```
+
+### Basic Usage
+
+When you click the index bar, it will automatically jump to the corresponding `IndexAnchor` anchor position.
+
+```html
+
+
+
+ Title {{ item }}
+
+ {{ item }} Text
+ {{ item }} Text
+ {{ item }} Text
+
+
+```
+```javascript
+export default {
+ data: () => ({
+ list: []
+ }),
+ mounted() {
+ for (let i = 0; i < 26; i++) {
+ list.value.push(String.fromCharCode(65 + i))
+ }
+ },
+ methods: {
+ change(value) {
+ console.log(value)
+ }
+ }
+}
+```
+
+## API
+
+### Props
+
+#### IndexBar Props
+
+| Prop | Description | Type | Default |
+| ----- | -------------- | -------- | ---------- |
+| `sticky` | Whether to enable anchor sticky top | _boolean_ | `true` |
+| `sticky-offset-top` | Anchor offset top when sticky | _number_ | `0` |
+| `hide-list` | Whether to hide anchor list | _boolean_ | `false` |
+| `css-mode` | Enable native `css sticky` mode | _boolean_ | `false` |
+| `z-index` | z-index | _string \| number_ | `1` |
+| `highlight-color` | Index character highlight color | _string_ | `#ee0a24` |
+| `duration` | Animation duration | _string \| number_ | `0` |
+
+#### IndexAnchor Props
+
+| Prop | Description | Type | Default |
+| ----- | -------------- | -------- | ---------- |
+| `index` | Index | _string \| number_ | `-` |
+
+### Events
+
+#### IndexBar Events
+
+| Event | Description | arguments |
+| ----- | -------------- | -------- |
+| `click` | Emitted when an index is clicked | `index: number \| string` |
+| `change` | Emitted when active index changed | `index: number \| string` |
+
+### Slots
+
+#### IndexAnchor Slots
+
+| Name | Description | SlotProps |
+| --- | --- | --- |
+| `default` | Custom index character | `-` |
+
+### Methods
+Use ref to get IndexBar instance and call instance methods.
+
+| Method | Description | arguments |
+| ---- | ------- | -------- |
+| `scrollTo` | scroll to target element | `index: number \| string` |
+
+### Style Variables
+Here are the CSS variables used by the component, Styles can be customized using [StyleProvider](#/en-US/style-provider)
+
+| Variable | Default |
+| --- | --- |
+| `--index-bar-list-item-font-size` | `var(--font-size-xs)` |
+| `--index-bar-list-item-color` | `var(--color-primary)` |
+| `--index-bar-list-item-active-color` | `var(--color-danger)` |
+| `--index-bar-list-item-height` | `14px` |
+| `--index-bar-list-item-padding` | `0 10px` |
diff --git a/packages/varlet-vue2-ui/src/index-bar/docs/zh-CN.md b/packages/varlet-vue2-ui/src/index-bar/docs/zh-CN.md
new file mode 100644
index 0000000..11eb4b4
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-bar/docs/zh-CN.md
@@ -0,0 +1,112 @@
+# 索引栏
+
+### 介绍
+
+用于跳转到页面指定位置。
+
+### 引入
+
+```js
+import Vue from 'vue'
+import { IndexBar, IndexAnchor } from '@varlet-vue2/ui'
+
+Vue.use(IndexBar).use(IndexAnchor)
+```
+
+### 基本使用
+
+点击索引栏时,会自动跳转到对应的 `IndexAnchor` 锚点位置。
+
+```html
+
+
+
+ 标题 {{ item }}
+
+ {{ item }} 文本
+ {{ item }} 文本
+ {{ item }} 文本
+
+
+```
+```javascript
+export default {
+ data: () => ({
+ list: []
+ }),
+ mounted() {
+ for (let i = 0; i < 26; i++) {
+ this.list.push(String.fromCharCode(65 + i))
+ }
+ },
+ methods: {
+ change(value) {
+ console.log(value)
+ }
+ }
+}
+```
+
+## API
+
+### 属性
+
+#### IndexBar Props
+
+| 参数 | 说明 | 类型 | 默认值 |
+| ----- | -------------- | -------- | ---------- |
+| `sticky` | 是否开启锚点吸顶 | _boolean_ | `true` |
+| `sticky-offset-top` | 锚点吸顶时与顶部的距离 | _number_ | `0` |
+| `hide-list` | 是否隐藏锚点列表 | _boolean_ | `false` |
+| `css-mode` | 开启原生 `css sticky` 模式 | _boolean_ | `false` |
+| `z-index` | z-index 层级 | _number \| string_ | `1` |
+| `highlight-color` | 索引字符高亮颜色 | _string_ | `#ee0a24` |
+| `duration` | 动画持续时间 | _string \| number_ | `0` |
+
+#### IndexAnchor Props
+
+| 参数 | 说明 | 类型 | 默认值 |
+| ----- | -------------- | -------- | ---------- |
+| `index` | 索引字符 | _number \| string_ |`-` |
+
+### 事件
+
+#### IndexBar Events
+
+| 事件名 | 说明 | 回调参数 |
+| ----- | -------------- | -------- |
+| `click` | 点击索引栏的字符时触发 | `index: number \| string` |
+| `change` | 当前高亮的索引字符变化时触发| `index: number \| string` |
+
+### 插槽
+
+#### IndexAnchor Slots
+
+| 名称 | 说明 | 参数 |
+| --- | --- | --- |
+| `default` | 自定义索引字符 |`-` |
+
+### 方法
+通过 ref 可以获取到 IndexBar 实例并调用实例方法
+
+| 方法名 | 说明 | 参数 |
+| ---- | ------- | -------- |
+| `scrollTo` | 滚动到指定锚点 | `index: number \| string` |
+
+### 样式变量
+以下为组件使用的 css 变量,可以使用 [StyleProvider 组件](#/zh-CN/style-provider)进行样式定制
+
+| 变量名 | 默认值 |
+| --- | --- |
+| `--index-bar-list-item-font-size` | `var(--font-size-xs)` |
+| `--index-bar-list-item-color` | `var(--color-primary)` |
+| `--index-bar-list-item-active-color` | `var(--color-danger)` |
+| `--index-bar-list-item-height` | `14px` |
+| `--index-bar-list-item-padding` | `0 10px` |
diff --git a/packages/varlet-vue2-ui/src/index-bar/example/index.vue b/packages/varlet-vue2-ui/src/index-bar/example/index.vue
new file mode 100644
index 0000000..bd2dceb
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-bar/example/index.vue
@@ -0,0 +1,76 @@
+
+
+
+
+ {{ pack.title }} {{ item }}
+
+ {{ item }} {{ pack.text }}
+ {{ item }} {{ pack.text }}
+
+
+
+
+
+
+
diff --git a/packages/varlet-vue2-ui/src/index-bar/example/locale/en-US.ts b/packages/varlet-vue2-ui/src/index-bar/example/locale/en-US.ts
new file mode 100644
index 0000000..2461a46
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-bar/example/locale/en-US.ts
@@ -0,0 +1,4 @@
+export default {
+ title: 'Title',
+ text: 'Text',
+}
diff --git a/packages/varlet-vue2-ui/src/index-bar/example/locale/index.ts b/packages/varlet-vue2-ui/src/index-bar/example/locale/index.ts
new file mode 100644
index 0000000..d2e375e
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-bar/example/locale/index.ts
@@ -0,0 +1,23 @@
+// lib
+import _zhCN from '../../../locale/zh-CN'
+import _enCN from '../../../locale/en-US'
+// mobile example doc
+import zhCN from './zh-CN'
+import enUS from './en-US'
+import { useLocale, add as _add, use as _use } from '../../../locale'
+
+const { add, use: exampleUse, pack, packs, merge } = useLocale()
+
+const use = (lang: string) => {
+ _use(lang)
+ exampleUse(lang)
+}
+
+export { add, pack, packs, merge, use }
+
+// lib
+_add('zh-CN', _zhCN)
+_add('en-US', _enCN)
+// mobile example doc
+add('zh-CN', zhCN as any)
+add('en-US', enUS as any)
diff --git a/packages/varlet-vue2-ui/src/index-bar/example/locale/zh-CN.ts b/packages/varlet-vue2-ui/src/index-bar/example/locale/zh-CN.ts
new file mode 100644
index 0000000..46e3d26
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-bar/example/locale/zh-CN.ts
@@ -0,0 +1,4 @@
+export default {
+ title: '标题',
+ text: '文本',
+}
diff --git a/packages/varlet-vue2-ui/src/index-bar/index.ts b/packages/varlet-vue2-ui/src/index-bar/index.ts
new file mode 100644
index 0000000..6bb3559
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-bar/index.ts
@@ -0,0 +1,10 @@
+import type { VueConstructor } from 'vue'
+import IndexBar from './IndexBar.vue'
+
+IndexBar.install = function (app: VueConstructor) {
+ app.component(IndexBar.name, IndexBar)
+}
+
+export const _IndexBarComponent = IndexBar
+
+export default IndexBar
diff --git a/packages/varlet-vue2-ui/src/index-bar/indexBar.less b/packages/varlet-vue2-ui/src/index-bar/indexBar.less
new file mode 100644
index 0000000..5cb57c0
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-bar/indexBar.less
@@ -0,0 +1,43 @@
+@index-bar-list-item-font-size: var(--font-size-xs);
+@index-bar-list-item-color: var(--color-primary);
+@index-bar-list-item-active-color: var(--color-danger);
+@index-bar-list-item-height: 14px;
+@index-bar-list-item-padding: 0 10px;
+
+:root {
+ --index-bar-list-item-font-size: @index-bar-list-item-font-size;
+ --index-bar-list-item-color: @index-bar-list-item-color;
+ --index-bar-list-item-active-color: @index-bar-list-item-active-color;
+ --index-bar-list-item-height: @index-bar-list-item-height;
+ --index-bar-list-item-padding: @index-bar-list-item-padding;
+}
+
+.var-index-bar {
+ position: relative;
+
+ &__anchor-list {
+ position: fixed;
+ right: 0;
+ top: 50%;
+ transform: translate(0, -50%);
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ }
+
+ &__anchor-item {
+ font-size: var(--index-bar-list-item-font-size);
+ display: flex;
+ align-items: center;
+ height: var(--index-bar-list-item-height);
+ justify-content: center;
+ padding: var(--index-bar-list-item-padding);
+ color: var(--index-bar-list-item-color);
+ cursor: pointer;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+
+ &--active {
+ color: var(--index-bar-list-item-active-color);
+ }
+ }
+}
diff --git a/packages/varlet-vue2-ui/src/index-bar/props.ts b/packages/varlet-vue2-ui/src/index-bar/props.ts
new file mode 100644
index 0000000..f894bab
--- /dev/null
+++ b/packages/varlet-vue2-ui/src/index-bar/props.ts
@@ -0,0 +1,29 @@
+export const props = {
+ sticky: {
+ type: Boolean,
+ default: true,
+ },
+ stickyOffsetTop: {
+ type: Number,
+ default: 0,
+ },
+ cssMode: {
+ type: Boolean,
+ default: false,
+ },
+ hideList: {
+ type: Boolean,
+ default: false,
+ },
+ zIndex: {
+ type: [Number, String],
+ default: 1,
+ },
+ highlightColor: {
+ type: String,
+ },
+ duration: {
+ type: [Number, String],
+ default: 0,
+ },
+}
diff --git a/packages/varlet-vue2-ui/src/table/example/index.vue b/packages/varlet-vue2-ui/src/table/example/index.vue
index aa7952b..b845b40 100755
--- a/packages/varlet-vue2-ui/src/table/example/index.vue
+++ b/packages/varlet-vue2-ui/src/table/example/index.vue
@@ -107,7 +107,7 @@ export default {
methods: {
get(current, size) {
- this.list.value = gen(current, size)
+ this.list = gen(current, size)
},
},
}
diff --git a/packages/varlet-vue2-ui/types/index.d.ts b/packages/varlet-vue2-ui/types/index.d.ts
index 34687c0..9ff5640 100644
--- a/packages/varlet-vue2-ui/types/index.d.ts
+++ b/packages/varlet-vue2-ui/types/index.d.ts
@@ -47,5 +47,7 @@ export * from './tabs'
export * from './tab'
export * from './tabsItems'
export * from './tabItem'
+export * from './indexBar'
+export * from './indexAnchor'
export * from './varComponent'
export * from './varDirective'
diff --git a/packages/varlet-vue2-ui/types/indexAnchor.d.ts b/packages/varlet-vue2-ui/types/indexAnchor.d.ts
new file mode 100644
index 0000000..3692d2e
--- /dev/null
+++ b/packages/varlet-vue2-ui/types/indexAnchor.d.ts
@@ -0,0 +1,11 @@
+import { VarComponent } from './varComponent'
+
+export interface IndexAnchorProps {
+ index: string | number
+}
+
+export class IndexAnchor extends VarComponent {
+ $props: IndexAnchorProps
+}
+
+export class _IndexAnchorComponent extends IndexAnchor {}
diff --git a/packages/varlet-vue2-ui/types/indexBar.d.ts b/packages/varlet-vue2-ui/types/indexBar.d.ts
new file mode 100644
index 0000000..926eba9
--- /dev/null
+++ b/packages/varlet-vue2-ui/types/indexBar.d.ts
@@ -0,0 +1,21 @@
+import { VarComponent } from './varComponent'
+
+export interface IndexBarProps {
+ sticky?: boolean
+ stickyOffsetTop?: number
+ hideList?: boolean
+ cssMode?: boolean
+ zIndex?: number | string
+ highlightColor?: string
+ duration?: number | string
+ onClick?: (value: string | number) => void
+ onChange?: (value: string | number) => void
+}
+
+export class IndexBar extends VarComponent {
+ $props: IndexBarProps
+
+ scrollTo: (index: number | string) => void
+}
+
+export class _IndexBarComponent extends IndexBar {}