diff --git a/breaking-changes.md b/breaking-changes.md index 50ca14445..844e014b9 100644 --- a/breaking-changes.md +++ b/breaking-changes.md @@ -1,9 +1,24 @@ # 不兼容更新 -## Popup +## 重命名徽标属性 -- `v-model` 调整为 `v-model:show` +在之前的版本中,我们通过 info 属性来展示图标右上角的徽标信息,为了表达更符合社区的命名习惯,我们将这个属性重命名为 badge,影响以下组件: -## Switch +- Tab +- Icon +- GridItem +- TreeSelect +- TabbarItem +- SidebarItem +- GoodsActionIcon -- v-model 对应的属性名和事件名由 `value/input` 调整为 `modelValue/update:modelValue` +同时内部使用的 Info 组件也会重命名为 Badge。 + +## v-model API 变更 + +- Popup: `v-model` 调整为 `v-model:show` +- Switch: v-model 对应的属性名和事件名由 `value/input` 调整为 `modelValue/update:modelValue` + +## 废弃个别组件 + +- SwitchCell: 移除此组件,可以直接使用 Cell 和 Switch 组件代替 diff --git a/src-next/nav-bar/README.md b/src-next/nav-bar/README.md new file mode 100644 index 000000000..0a6e7fe44 --- /dev/null +++ b/src-next/nav-bar/README.md @@ -0,0 +1,80 @@ +# NavBar + +### Install + +```js +import Vue from 'vue'; +import { NavBar } from 'vant'; + +Vue.use(NavBar); +``` + +## Usage + +### Basic Usage + +```html + +``` + +```js +import { Toast } from 'vant'; + +export default { + methods: { + onClickLeft() { + Toast('Back'); + }, + onClickRight() { + Toast('Button'); + }, + }, +}; +``` + +### Use Slot + +```html + + + +``` + +## API + +### Props + +| Attribute | Description | Type | Default | +| --- | --- | --- | --- | +| title | Title | _string_ | `''` | +| left-text | Left Text | _string_ | `''` | +| right-text | Right Text | _string_ | `''` | +| left-arrow | Whether to show left arrow | _boolean_ | `false` | +| border | Whether to show bottom border | _boolean_ | `true` | +| fixed | Whether to fixed top | _boolean_ | `false` | +| placeholder `v2.5.9` | Whether to generage a placeholder element when fixed | _boolean_ | `false` | +| z-index | Z-index | _number \| string_ | `1` | + +### Slots + +| Name | Description | +| ----- | ------------------------- | +| title | Custom title | +| left | Custom left side content | +| right | Custom right side content | + +### Events + +| Event | Description | Arguments | +| ----------- | --------------------------------- | --------- | +| click-left | Triggered when click left button | - | +| click-right | Triggered when click right button | - | diff --git a/src-next/nav-bar/README.zh-CN.md b/src-next/nav-bar/README.zh-CN.md new file mode 100644 index 000000000..100999759 --- /dev/null +++ b/src-next/nav-bar/README.zh-CN.md @@ -0,0 +1,82 @@ +# NavBar 导航栏 + +### 引入 + +```js +import Vue from 'vue'; +import { NavBar } from 'vant'; + +Vue.use(NavBar); +``` + +## 代码演示 + +### 基础用法 + +```html + +``` + +```js +import { Toast } from 'vant'; + +export default { + methods: { + onClickLeft() { + Toast('返回'); + }, + onClickRight() { + Toast('按钮'); + }, + }, +}; +``` + +### 使用插槽 + +通过插槽自定义导航栏两侧的内容 + +```html + + + +``` + +## API + +### Props + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| title | 标题 | _string_ | `''` | +| left-text | 左侧文案 | _string_ | `''` | +| right-text | 右侧文案 | _string_ | `''` | +| left-arrow | 是否显示左侧箭头 | _boolean_ | `false` | +| border | 是否显示下边框 | _boolean_ | `true` | +| fixed | 是否固定在顶部 | _boolean_ | `false` | +| placeholder `v2.5.9` | 固定在顶部时,是否在标签位置生成一个等高的占位元素 | _boolean_ | `false` | +| z-index | 元素 z-index | _number \| string_ | `1` | + +### Slots + +| 名称 | 说明 | +| ----- | ------------------ | +| title | 自定义标题 | +| left | 自定义左侧区域内容 | +| right | 自定义右侧区域内容 | + +### Events + +| 事件名 | 说明 | 回调参数 | +| ----------- | ------------------ | -------- | +| click-left | 点击左侧按钮时触发 | - | +| click-right | 点击右侧按钮时触发 | - | diff --git a/src-next/nav-bar/demo/index.vue b/src-next/nav-bar/demo/index.vue new file mode 100644 index 000000000..cededbc20 --- /dev/null +++ b/src-next/nav-bar/demo/index.vue @@ -0,0 +1,44 @@ + + + diff --git a/src-next/nav-bar/index.js b/src-next/nav-bar/index.js new file mode 100644 index 000000000..76b73d12f --- /dev/null +++ b/src-next/nav-bar/index.js @@ -0,0 +1,105 @@ +// Utils +import { createNamespace } from '../utils'; +import { BORDER_BOTTOM } from '../utils/constant'; + +// Components +import Icon from '../icon'; + +const [createComponent, bem] = createNamespace('nav-bar'); + +export default createComponent({ + props: { + title: String, + fixed: Boolean, + zIndex: [Number, String], + leftText: String, + rightText: String, + leftArrow: Boolean, + placeholder: Boolean, + border: { + type: Boolean, + default: true, + }, + }, + + emits: ['click-left', 'click-right'], + + data() { + return { + height: null, + }; + }, + + mounted() { + if (this.placeholder && this.fixed) { + this.height = this.$refs.navBar.getBoundingClientRect().height; + } + }, + + methods: { + genLeft() { + const leftSlot = this.$slots.left?.(); + + if (leftSlot) { + return leftSlot; + } + + return [ + this.leftArrow && , + this.leftText && {this.leftText}, + ]; + }, + + genRight() { + const rightSlot = this.$slots.right?.(); + + if (rightSlot) { + return rightSlot; + } + + if (this.rightText) { + return {this.rightText}; + } + }, + + genNavBar() { + return ( +
+
+ {this.genLeft()} +
+
+ {this.$slots.title ? this.$slots.title() : this.title} +
+
+ {this.genRight()} +
+
+ ); + }, + + onClickLeft(event) { + this.$emit('click-left', event); + }, + + onClickRight(event) { + this.$emit('click-right', event); + }, + }, + + render() { + if (this.placeholder && this.fixed) { + return ( +
+ {this.genNavBar()} +
+ ); + } + + return this.genNavBar(); + }, +}); diff --git a/src-next/nav-bar/index.less b/src-next/nav-bar/index.less new file mode 100644 index 000000000..582a0a82a --- /dev/null +++ b/src-next/nav-bar/index.less @@ -0,0 +1,66 @@ +@import '../style/var'; + +.van-nav-bar { + position: relative; + z-index: @nav-bar-z-index; + display: flex; + align-items: center; + height: @nav-bar-height; + line-height: 1.5; + text-align: center; + background-color: @nav-bar-background-color; + user-select: none; + + .van-icon { + color: @nav-bar-icon-color; + } + + &__arrow { + min-width: 1em; + margin-right: @padding-base; + font-size: @nav-bar-arrow-size; + } + + &--fixed { + position: fixed; + top: 0; + left: 0; + width: 100%; + } + + &__title { + max-width: 60%; + margin: 0 auto; + color: @nav-bar-title-text-color; + font-weight: @font-weight-bold; + font-size: @nav-bar-title-font-size; + } + + &__left, + &__right { + position: absolute; + top: 0; + bottom: 0; + display: flex; + align-items: center; + padding: 0 @padding-md; + font-size: @font-size-md; + cursor: pointer; + + &:active { + opacity: @active-opacity; + } + } + + &__left { + left: 0; + } + + &__right { + right: 0; + } + + &__text { + color: @nav-bar-text-color; + } +} diff --git a/src-next/nav-bar/test/__snapshots__/demo.spec.js.snap b/src-next/nav-bar/test/__snapshots__/demo.spec.js.snap new file mode 100644 index 000000000..bcd8a6ba2 --- /dev/null +++ b/src-next/nav-bar/test/__snapshots__/demo.spec.js.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders demo correctly 1`] = ` +
+
+
+
+ 返回
+
标题
+
按钮
+
+
+
+
+
+ 返回
+
标题
+
+
+
+
+
+`; diff --git a/src-next/nav-bar/test/__snapshots__/index.spec.js.snap b/src-next/nav-bar/test/__snapshots__/index.spec.js.snap new file mode 100644 index 000000000..263a07ecc --- /dev/null +++ b/src-next/nav-bar/test/__snapshots__/index.spec.js.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`placeholder prop 1`] = ` +
+
+
+
+
+
+
+`; + +exports[`render left & right slot 1`] = ` +
+
Custom Left
+
+
Custom Right
+
+`; + +exports[`render title slot 1`] = ` +
+
+
Custom Title
+
+
+`; diff --git a/src-next/nav-bar/test/demo.spec.js b/src-next/nav-bar/test/demo.spec.js new file mode 100644 index 000000000..5c70922b5 --- /dev/null +++ b/src-next/nav-bar/test/demo.spec.js @@ -0,0 +1,4 @@ +import Demo from '../demo'; +import { snapshotDemo } from '../../../test/demo'; + +snapshotDemo(Demo); diff --git a/src-next/nav-bar/test/index.spec.js b/src-next/nav-bar/test/index.spec.js new file mode 100644 index 000000000..63149c6e0 --- /dev/null +++ b/src-next/nav-bar/test/index.spec.js @@ -0,0 +1,60 @@ +import NavBar from '..'; +import { mount, mockGetBoundingClientRect } from '../../../test'; + +test('render left & right slot', () => { + const wrapper = mount(NavBar, { + scopedSlots: { + left: () => 'Custom Left', + right: () => 'Custom Right', + }, + }); + + expect(wrapper).toMatchSnapshot(); +}); + +test('render title slot', () => { + const wrapper = mount(NavBar, { + scopedSlots: { + title: () => 'Custom Title', + }, + }); + + expect(wrapper).toMatchSnapshot(); +}); + +test('placeholder prop', () => { + const restore = mockGetBoundingClientRect({ height: 50 }); + + const wrapper = mount(NavBar, { + propsData: { + fixed: true, + placeholder: true, + }, + }); + + expect(wrapper).toMatchSnapshot(); + + restore(); +}); + +test('click-left event', () => { + const wrapper = mount(NavBar, { + propsData: { + leftText: 'left', + }, + }); + + wrapper.find('.van-nav-bar__left').trigger('click'); + expect(wrapper.emitted('click-left')).toBeTruthy(); +}); + +test('click-right event', () => { + const wrapper = mount(NavBar, { + propsData: { + rightText: 'right', + }, + }); + + wrapper.find('.van-nav-bar__right').trigger('click'); + expect(wrapper.emitted('click-right')).toBeTruthy(); +}); diff --git a/vant.config.js b/vant.config.js index b7db042f7..e81e090aa 100644 --- a/vant.config.js +++ b/vant.config.js @@ -294,10 +294,10 @@ module.exports = { // path: 'index-bar', // title: 'IndexBar 索引栏', // }, - // { - // path: 'nav-bar', - // title: 'NavBar 导航栏', - // }, + { + path: 'nav-bar', + title: 'NavBar 导航栏', + }, // { // path: 'pagination', // title: 'Pagination 分页', @@ -432,10 +432,10 @@ module.exports = { path: 'col', title: 'Layout', }, - // { - // path: 'popup', - // title: 'Popup', - // }, + { + path: 'popup', + title: 'Popup', + }, { path: 'style', title: 'Built-in style', @@ -628,10 +628,10 @@ module.exports = { // path: 'index-bar', // title: 'IndexBar', // }, - // { - // path: 'nav-bar', - // title: 'NavBar', - // }, + { + path: 'nav-bar', + title: 'NavBar', + }, // { // path: 'pagination', // title: 'Pagination',