forked from opentiny/tiny-vue
refactor(base-select): add base-select
This commit is contained in:
parent
3f8001ac1d
commit
92d9c885d0
|
@ -0,0 +1,951 @@
|
|||
export default {
|
||||
mode: ['pc', 'mobile-first'],
|
||||
apis: [
|
||||
{
|
||||
name: 'select',
|
||||
type: 'component',
|
||||
props: [
|
||||
{
|
||||
name: 'all-text',
|
||||
type: 'string',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '当下拉中显示全部时,自定义全部的显示文本。不指定时,则默认显示"全部"',
|
||||
'en-US':
|
||||
'When all is displayed in the drop-down list, you can customize the display text of all. If this parameter is not specified, All is displayed by default.'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'all-text',
|
||||
mfDemo: 'all-text'
|
||||
},
|
||||
{
|
||||
name: 'allow-copy',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否允许复制输入框的内容,适用单选可搜索场景',
|
||||
'en-US':
|
||||
'Is it allowed to copy the content of the input box, applicable to single choice searchable scenarios'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'copy-single',
|
||||
mfDemo: 'copy-single'
|
||||
},
|
||||
{
|
||||
name: 'allow-create',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否允许创建新条目,需配合 filterable 使用。若搜索字段不在选项列表中,可创建为新的选项',
|
||||
'en-US':
|
||||
'Is it allowed to create new entries? It needs to be used in conjunction with filterable. If the search field is not in the option list, it can be created as a new option'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'allow-create',
|
||||
mfDemo: 'allow-create'
|
||||
},
|
||||
{
|
||||
name: 'autocomplete',
|
||||
type: 'string',
|
||||
defaultValue: "'off'",
|
||||
desc: {
|
||||
'zh-CN': '输入框的原生 autocomplete 属性',
|
||||
'en-US': 'The native autocomplete attribute of the input box'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'native-properties',
|
||||
mfDemo: 'native-properties'
|
||||
},
|
||||
{
|
||||
name: 'cache-op',
|
||||
typeAnchorName: 'ICacheOp',
|
||||
type: 'ICacheOp',
|
||||
defaultValue:
|
||||
"<pre>\n{\n key: '',\n sortBy: 'frequency',\n sort: 'desc',\n dataKey: 'value',\n highlightClass: \n 'memorize-highlight',\n highlightNum: Infinity,\n cacheNum: Infinity,\n serialize: JSON.stringify\n deserialize: JSON.parse\n}\n</pre>",
|
||||
desc: {
|
||||
'zh-CN': '启用本地缓存已选项的功能配置(根据用户点击选择的次数、最后时间继续存储排序)',
|
||||
'en-US': 'Set the component type when Grid or Tree is embedded in the drop-down list box.'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'cache-usage',
|
||||
mfDemo: 'cache-usage'
|
||||
},
|
||||
{
|
||||
name: 'clear-no-match-value',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否自动清空无法在 options 中找到匹配项的值',
|
||||
'en-US': 'Automatically clear values that cannot find matching items in options'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'clear-no-match-value',
|
||||
mfDemo: 'clear-no-match-value'
|
||||
},
|
||||
{
|
||||
name: 'clearable',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否启用一键清除的功能',
|
||||
'en-US': 'Whether to display the one click clear button, only applicable to radio selection'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'clearable',
|
||||
mfDemo: 'clearable'
|
||||
},
|
||||
{
|
||||
name: 'click-expend',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '点击可展开或收起显示不全的选项。仅用于多选',
|
||||
'en-US': 'Click to expand or collapse options. Only applicable to multiple selections'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'collapse-tags',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否将多个标签折叠显示。仅适用多选',
|
||||
'en-US': 'Whether to collapse multiple labels for display. Only applicable to multiple selections'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'collapse-tags',
|
||||
mfDemo: 'collapse-tags'
|
||||
},
|
||||
{
|
||||
name: 'copyable',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否启用一键复制的功能。点击复制按钮一键复制所有标签的文本内容并以逗号分隔,仅适用于多选',
|
||||
'en-US':
|
||||
'Is the one click copy function enabled. Click the copy button to copy the text content of all labels with one click, separated by commas, only applicable to multiple selections'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'copy-multi',
|
||||
mfDemo: 'copy-multi'
|
||||
},
|
||||
{
|
||||
name: 'default-first-option',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否启用按 Enter 键选择第一个匹配项的功能。需配合 filterable 或 remote 使用',
|
||||
'en-US':
|
||||
'Whether to enable the function of pressing the Enter key to select the first match. Must be used in conjunction with filterable or remote'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'allow-create',
|
||||
mfDemo: 'allow-create'
|
||||
},
|
||||
{
|
||||
name: 'disabled',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否禁用',
|
||||
'en-US': 'Is it disabled'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'disabled',
|
||||
mfDemo: 'disabled'
|
||||
},
|
||||
{
|
||||
name: 'dropdown-icon',
|
||||
type: 'Component',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '自定义下拉图标',
|
||||
'en-US': 'Custom drop-down icon'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'multiple'
|
||||
},
|
||||
{
|
||||
name: 'dropdown-style',
|
||||
type: 'String',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '自定义下拉选项样式',
|
||||
'en-US': 'Custom drop-down options style'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'multiple'
|
||||
},
|
||||
{
|
||||
name: 'filter-method',
|
||||
type: '(query: string) => void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '自定义过滤方法',
|
||||
'en-US': 'Custom filtering method'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'filter-method',
|
||||
mfDemo: 'filter-method'
|
||||
},
|
||||
{
|
||||
name: 'filterable',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否可搜索',
|
||||
'en-US': 'Is it searchable'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'filter-method',
|
||||
mfDemo: 'filter-method'
|
||||
},
|
||||
{
|
||||
name: 'grid-op',
|
||||
typeAnchorName: 'IGridOption',
|
||||
type: 'IGridOption',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '下拉表格时,内置表格的配置,用法同 Grid 组件。需结合 render-type 属性使用',
|
||||
'en-US':
|
||||
'When pulling down a table, the configuration of the built-in table is the same as that of the Grid component. To be used in conjunction with the render type attribute'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'nest-grid',
|
||||
mfDemo: 'nest-grid'
|
||||
},
|
||||
{
|
||||
name: 'input-box-type',
|
||||
type: "'input' | 'underline'",
|
||||
defaultValue: "'input'",
|
||||
desc: {
|
||||
'zh-CN': '输入框的显示类型',
|
||||
'en-US': 'Display type of input box'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'input-box-type',
|
||||
mfDemo: 'input-box-type'
|
||||
},
|
||||
{
|
||||
name: 'is-drop-inherit-width',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '下拉弹框的宽度是否跟输入框保持一致。默认超出输入框宽度时由内容撑开',
|
||||
'en-US':
|
||||
'Is the width of the dropdown box consistent with the input box. By default, when the width of the input box is exceeded, it is supported by the content'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'is-drop-inherit-width',
|
||||
mfDemo: 'is-drop-inherit-width'
|
||||
},
|
||||
{
|
||||
name: 'loading',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否加载中,适用于远程搜索场景',
|
||||
'en-US': 'Loading or not, suitable for remote search scenarios'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'remote-method',
|
||||
mfDemo: 'remote-method'
|
||||
},
|
||||
{
|
||||
name: 'loading-text',
|
||||
type: 'string',
|
||||
defaultValue: "'加载中'",
|
||||
desc: {
|
||||
'zh-CN': '远程加载时显示的文本',
|
||||
'en-US': 'Text displayed during remote loading'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'remote-method',
|
||||
mfDemo: 'remote-method'
|
||||
},
|
||||
{
|
||||
name: 'max-visible-rows',
|
||||
type: 'number',
|
||||
defaultValue: '1',
|
||||
desc: {
|
||||
'zh-CN': '多行默认最大显示行数,超出后选项自动隐藏',
|
||||
'en-US':
|
||||
'Default maximum display lines for multiple lines, with automatic hiding option for exceeding lines'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'collapse-tags'
|
||||
},
|
||||
{
|
||||
name: 'modelValue / v-model',
|
||||
type: 'string | number | Array<string|number>',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '绑定值',
|
||||
'en-US': 'Bind value'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'multiple',
|
||||
mfDemo: 'multiple'
|
||||
},
|
||||
{
|
||||
name: 'multiple',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否允许选择多个选项',
|
||||
'en-US': 'Allow multiple options to be selected'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'multiple',
|
||||
mfDemo: 'multiple'
|
||||
},
|
||||
{
|
||||
name: 'multiple-limit',
|
||||
type: 'number',
|
||||
defaultValue: '0',
|
||||
desc: {
|
||||
'zh-CN': '多选时最多可选择的个数,默认为 0 不限制',
|
||||
'en-US':
|
||||
'When selecting multiple options, the maximum number of options available is 0, with no limit by default'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'multiple-limit',
|
||||
mfDemo: 'multiple-limit'
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '输入框的原生 name 属性',
|
||||
'en-US': 'The native name attribute of the input box'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'native-properties',
|
||||
mfDemo: 'native-properties'
|
||||
},
|
||||
{
|
||||
name: 'no-data-text',
|
||||
type: 'string',
|
||||
defaultValue: "'暂无相关数据'",
|
||||
desc: {
|
||||
'zh-CN': '选项列表为空时显示的文本,也可以使用 empty 插槽设置',
|
||||
'en-US': 'The text displayed when the option list is empty can also be set using empty slots'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'no-data-text',
|
||||
mfDemo: 'no-data-text'
|
||||
},
|
||||
{
|
||||
name: 'no-match-text',
|
||||
type: 'string',
|
||||
defaultValue: "'无匹配数据'",
|
||||
desc: {
|
||||
'zh-CN': '搜索条件无匹配时显示的文本,也可以使用 empty 插槽设置',
|
||||
'en-US':
|
||||
'The text displayed when there is no match for the search criteria can also be set using empty slots'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'filter-method'
|
||||
},
|
||||
{
|
||||
name: 'options',
|
||||
typeAnchorName: 'IOption',
|
||||
type: 'IOption[]',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '选项列表配置,使用后不需要再配置 tiny-option',
|
||||
'en-US': 'Option list configuration, no need to configure tiny options after use'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'map-field',
|
||||
mfDemo: 'map-field'
|
||||
},
|
||||
{
|
||||
name: 'placeholder',
|
||||
type: 'string',
|
||||
defaultValue: "'请选择'",
|
||||
desc: {
|
||||
'zh-CN': '占位符',
|
||||
'en-US': 'Placeholder'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'native-properties',
|
||||
mfDemo: 'native-properties'
|
||||
},
|
||||
{
|
||||
name: 'placement',
|
||||
typeAnchorName: 'IPlacement',
|
||||
type: 'IPlacement',
|
||||
defaultValue: "'bottom-start'",
|
||||
desc: {
|
||||
'zh-CN': '下拉弹框相对于触发源的弹出位置',
|
||||
'en-US': 'The pop-up position of the pull-down pop-up box relative to the trigger source'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'popup-style-position',
|
||||
mfDemo: 'popup-style-position'
|
||||
},
|
||||
{
|
||||
name: 'popper-append-to-body',
|
||||
type: 'boolean',
|
||||
defaultValue: 'true',
|
||||
desc: {
|
||||
'zh-CN': '是否将弹出框的 dom 元素插入至 body 元素',
|
||||
'en-US': 'Whether to insert the dom element of the pop-up box into the body element'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'popup-style-position',
|
||||
mfDemo: 'popup-style-position'
|
||||
},
|
||||
{
|
||||
name: 'popper-class',
|
||||
type: 'string',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '自定义下拉框的类名,用于自定义样式',
|
||||
'en-US': 'The class name of the custom dropdown box, used for customizing styles'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'popup-style-position',
|
||||
mfDemo: 'popup-style-position'
|
||||
},
|
||||
{
|
||||
name: 'remote',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否为远程搜索',
|
||||
'en-US': 'Is it a remote search'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'remote-method',
|
||||
mfDemo: 'remote-method'
|
||||
},
|
||||
{
|
||||
name: 'remote-method',
|
||||
type: '(query:string) => void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '远程搜索的方法',
|
||||
'en-US': 'Remote search methods'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'remote-method',
|
||||
mfDemo: 'remote-method'
|
||||
},
|
||||
{
|
||||
name: 'render-type',
|
||||
type: "'tree' | 'grid'",
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '渲染为下拉表格或下拉树,需结合 grid-op / tree-op 使用',
|
||||
'en-US': 'Rendered as a dropdown table or tree, to be used in conjunction with grid op/tree op'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'nest-grid',
|
||||
mfDemo: 'nest-grid'
|
||||
},
|
||||
{
|
||||
name: 'reserve-keyword',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '多选可搜索时,是否在选中一个选项后仍然保留当前的搜索关键词',
|
||||
'en-US':
|
||||
'When selecting multiple searchable options, do you still keep the current search keywords after selecting one option'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'remote-method',
|
||||
mfDemo: 'remote-method'
|
||||
},
|
||||
{
|
||||
name: 'searchable',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否启用下拉面板搜索',
|
||||
'en-US': 'Whether to allow users to create new items. This parameter must be used together with filterable.'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'searchable',
|
||||
mfDemo: 'searchable'
|
||||
},
|
||||
{
|
||||
name: 'show-alloption',
|
||||
type: 'boolean',
|
||||
defaultValue: 'true',
|
||||
desc: {
|
||||
'zh-CN': '是否展示 “全选” 选项',
|
||||
'en-US': 'Whether to display the "Select All" option'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'show-alloption',
|
||||
mfDemo: 'show-alloption'
|
||||
},
|
||||
{
|
||||
name: 'show-empty-image',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否显示空数据图片',
|
||||
'en-US': 'Display empty data image'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'no-data-text',
|
||||
mfDemo: 'no-data-text'
|
||||
},
|
||||
{
|
||||
name: 'size',
|
||||
type: "'medium' | 'small' | 'mini'",
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '输入框尺寸。',
|
||||
'en-US': 'Text box size'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'size',
|
||||
mfDemo: 'size'
|
||||
},
|
||||
{
|
||||
name: 'tag-selectable',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '输入框中的标签是否可通过鼠标选中复制',
|
||||
'en-US': 'Can the label in the input box be copied by selecting it with the mouse'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'copy-multi',
|
||||
mfDemo: 'copy-multi'
|
||||
},
|
||||
{
|
||||
name: 'tag-type',
|
||||
type: "'success' | 'info' | 'warning' | 'danger'",
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '标签类型,仅多选适用。使用 aurora 主题时设置该属性为 info',
|
||||
'en-US':
|
||||
'Label type, only applicable for multiple choices. Set this property to info when using the aurora theme'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'tag-type',
|
||||
mfDemo: 'tag-type'
|
||||
},
|
||||
{
|
||||
name: 'text-field',
|
||||
type: 'string',
|
||||
defaultValue: "'label'",
|
||||
desc: {
|
||||
'zh-CN': '显示值字段',
|
||||
'en-US': 'Show Value Fields'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'map-field',
|
||||
mfDemo: 'map-field'
|
||||
},
|
||||
{
|
||||
name: 'text-split',
|
||||
type: 'string',
|
||||
defaultValue: "','",
|
||||
desc: {
|
||||
'zh-CN': '自定义复制文本的分隔符,需结合 copyable 属性使用',
|
||||
'en-US': 'The separator for custom copied text needs to be used in conjunction with the copyable attribute'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'copy-multi',
|
||||
mfDemo: 'copy-multi'
|
||||
},
|
||||
{
|
||||
name: 'top-create',
|
||||
type: 'boolean',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '是否显示下拉框顶部新增按钮,点击按钮会抛出一个 top-create-click 事件,可以在事件中自定义一些行为',
|
||||
'en-US':
|
||||
'Indicates whether to display a new button on the top of the drop-down list box. When a button is clicked, a top-create-click event is thrown. You can customize some behaviors in the event'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'allow-create'
|
||||
},
|
||||
{
|
||||
name: 'tree-op',
|
||||
typeAnchorName: 'ITreeOption',
|
||||
type: 'ITreeOption',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '下拉树时,内置树组件的配置,用法同 Tree 组件。需结合 render-type 属性使用',
|
||||
'en-US':
|
||||
'When pulling down a tree, the configuration of the built-in tree component is the same as that of the Tree component. To be used in conjunction with the render type attribute'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'nest-tree',
|
||||
mfDemo: 'nest-tree'
|
||||
},
|
||||
{
|
||||
name: 'value-field',
|
||||
type: 'string',
|
||||
defaultValue: "'value'",
|
||||
desc: {
|
||||
'zh-CN': '绑定值字段',
|
||||
'en-US': 'Bind Value Field'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'map-field',
|
||||
mfDemo: 'map-field'
|
||||
},
|
||||
{
|
||||
name: 'value-key',
|
||||
type: 'string',
|
||||
defaultValue: "'value'",
|
||||
desc: {
|
||||
'zh-CN': '作为 value 唯一标识的键名,绑定值为对象类型时必填',
|
||||
'en-US':
|
||||
'The key name that uniquely identifies the value must be filled in when the binding value is of object type'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'binding-obj',
|
||||
mfDemo: 'binding-obj'
|
||||
},
|
||||
{
|
||||
name: 'show-proportion',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '是否展示多选框选中条数和总条数的占比的文字提示',
|
||||
'en-US':
|
||||
'Display the proportion of the number of selected items and the total number of items in the multiple-choice box'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'collapse-tags',
|
||||
mfDemo: 'collapse-tags'
|
||||
},
|
||||
{
|
||||
name: 'show-limit-text',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN':
|
||||
'是否展示多选框开启多选限制选择数量时,选中条数和限制总条数的占比的文字提示。 该属性的优先级大于<code>show-proportion</code> 属性,同时设置只',
|
||||
'en-US':
|
||||
'Display the proportion of the number of selected items and the total number of items in the multiple-choice box'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'multiple'
|
||||
}
|
||||
],
|
||||
events: [
|
||||
{
|
||||
name: 'blur',
|
||||
type: '(event:MouseEvent) => void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '监听输入框失去焦点事件',
|
||||
'en-US': 'Listening for input box lose focus event'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'events',
|
||||
mfDemo: 'events'
|
||||
},
|
||||
{
|
||||
name: 'change',
|
||||
type: '(value:string|number|Array<string|number>, list:Array<IOption|ITreeNode>) => void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '监听绑定值变更事件',
|
||||
'en-US': 'Listening for binding value change events'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'events',
|
||||
mfDemo: 'events'
|
||||
},
|
||||
{
|
||||
name: 'clear',
|
||||
type: '() => void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '监听一键清除事件',
|
||||
'en-US': 'Listening for one click clear events'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'events',
|
||||
mfDemo: 'events'
|
||||
},
|
||||
{
|
||||
name: 'focus',
|
||||
type: '(event:MouseEvent) => void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '监听输入框获取焦点事件',
|
||||
'en-US': 'Listening to input boxes to obtain focus events'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'events',
|
||||
mfDemo: 'events'
|
||||
},
|
||||
{
|
||||
name: 'remove-tag',
|
||||
type: '(tag:string|number) => void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '监听多选时移除标签事件',
|
||||
'en-US': 'Remove label events when listening for multiple selections'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'events',
|
||||
mfDemo: 'events'
|
||||
},
|
||||
{
|
||||
name: 'top-create-click',
|
||||
type: '() => void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '监听顶部新增按钮点击事件,同 top-create 属性一起使用',
|
||||
'en-US':
|
||||
'Listens to the click event of a new button on the top. This parameter is used together with the top-create attribute'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'events'
|
||||
},
|
||||
{
|
||||
name: 'visible-change',
|
||||
type: '(status:boolean) => void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '监听下拉弹框的显示隐藏状态',
|
||||
'en-US': 'Monitor the display and hidden status of dropdown pop ups'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'events',
|
||||
mfDemo: 'events'
|
||||
}
|
||||
],
|
||||
methods: [
|
||||
{
|
||||
name: 'blur',
|
||||
type: '() => void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '使输入框失去焦点',
|
||||
'en-US': 'Causes the input box to lose focus'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'manual-focus-blur',
|
||||
mfDemo: 'manual-focus-blur'
|
||||
},
|
||||
{
|
||||
name: 'focus',
|
||||
type: '() => void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '使输入框获取焦点',
|
||||
'en-US': 'Bring the input box to focus'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'manual-focus-blur',
|
||||
mfDemo: 'manual-focus-blur'
|
||||
}
|
||||
],
|
||||
slots: [
|
||||
{
|
||||
name: 'default',
|
||||
type: '',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '选项默认插槽',
|
||||
'en-US': 'Option default slot'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'slot-default',
|
||||
mfDemo: 'slot-default'
|
||||
},
|
||||
{
|
||||
name: 'empty',
|
||||
type: '',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '空数据插槽',
|
||||
'en-US': 'Empty data slot'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'slot-empty',
|
||||
mfDemo: 'slot-empty'
|
||||
},
|
||||
{
|
||||
name: 'footer',
|
||||
type: '',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '下拉弹框底部插槽',
|
||||
'en-US': 'Pull down the bottom slot of the pop-up box'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'slot-footer',
|
||||
mfDemo: 'slot-footer'
|
||||
},
|
||||
{
|
||||
name: 'prefix',
|
||||
type: '',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '输入框前缀插槽',
|
||||
'en-US': 'Input box prefix slot'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'slot-prefix',
|
||||
mfDemo: 'slot-prefix'
|
||||
},
|
||||
{
|
||||
name: 'reference',
|
||||
type: '',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '触发源插槽',
|
||||
'en-US': 'Trigger Source Slot'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'slot-reference',
|
||||
mfDemo: 'slot-reference'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'option',
|
||||
type: 'component',
|
||||
props: [
|
||||
{
|
||||
name: 'disabled',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '选项是否禁用',
|
||||
'en-US': 'Is the option disabled'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'disabled',
|
||||
mfDemo: 'disabled'
|
||||
},
|
||||
{
|
||||
name: 'icon',
|
||||
type: 'Component',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '自定义选项的图标',
|
||||
'en-US': 'Customize icons for options'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'basic-usage',
|
||||
mfDemo: 'basic-usage'
|
||||
},
|
||||
{
|
||||
name: 'label',
|
||||
type: 'string',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '选项的显示文本',
|
||||
'en-US': 'Display text for option'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'basic-usage',
|
||||
mfDemo: 'basic-usage'
|
||||
},
|
||||
{
|
||||
name: 'required',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '选项是否必选',
|
||||
'en-US': 'Is it mandatory to select an option'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: '',
|
||||
mfDemo: ''
|
||||
},
|
||||
{
|
||||
name: 'value',
|
||||
type: 'string',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '选项的值',
|
||||
'en-US': 'Value for option'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
pcDemo: 'basic-usage',
|
||||
mfDemo: 'basic-usage'
|
||||
}
|
||||
],
|
||||
events: [],
|
||||
methods: [],
|
||||
slots: []
|
||||
}
|
||||
],
|
||||
types: [
|
||||
{
|
||||
name: 'IOption',
|
||||
type: 'interface',
|
||||
code: `
|
||||
interface IOption {
|
||||
value?: string | number
|
||||
label?: string
|
||||
disabled?: boolean
|
||||
icon?: Component
|
||||
required?:boolean
|
||||
}
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'ICacheOp',
|
||||
type: 'interface',
|
||||
code: `
|
||||
interface ICacheItem {
|
||||
frequency: number
|
||||
key: string
|
||||
time: number
|
||||
}
|
||||
|
||||
interface ICacheOp {
|
||||
key: string // 本地缓存的唯一 key 值
|
||||
sortBy?: 'frequency' | 'time' // 排序的字段,默认 frequency (频次)
|
||||
sort?: 'desc' | 'asc' // 排序方式,默认 desc (降序)
|
||||
dataKey?: string // 数据中的唯一标识的 key 名称,默认 value
|
||||
highlightClass?: string // 个性化高亮 class 名称,默认:memorize-highlight
|
||||
highlightNum?: number // 高亮个性化的条数,默认:Infinity
|
||||
cacheNum?: number // 存储个性化的条数,默认:Infinity
|
||||
serialize?: ()=> string // 本地存储序列化方法,默认:JSON.stringify
|
||||
deserialize?: ()=> ICacheItem[] // 本地存储序反列化方法,默认:JSON.parse
|
||||
}
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'IGridOption',
|
||||
type: 'interface',
|
||||
code: `
|
||||
interface IGridOption {
|
||||
data: any[] // 表格数据,用法同 Grid
|
||||
columns: any[] // 列配置,用法同 Grid
|
||||
}
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'ITreeOption',
|
||||
type: 'interface',
|
||||
code: `
|
||||
interface ITreeNode {
|
||||
label: string // 默认树节点的文本字段
|
||||
id: number|string // 树节点唯一标识
|
||||
children: ITreeNode[] // 子节点
|
||||
}
|
||||
|
||||
interface ITreeOption {
|
||||
data: ITreeNode[] // 树数据,用法同 Tree
|
||||
}
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'IPlacement',
|
||||
type: 'type',
|
||||
code: `
|
||||
type IPlacement = 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end'
|
||||
`
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
<div>
|
||||
<tiny-base-select v-model="value" multiple all-text="全部小吃">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '黄金糕' },
|
||||
{ value: '选项2', label: '双皮奶' },
|
||||
{ value: '选项3', label: '蚵仔煎' },
|
||||
{ value: '选项4', label: '龙须面' },
|
||||
{ value: '选项6', label: '螺蛳粉' }
|
||||
])
|
||||
|
||||
const value = ref([])
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,13 @@
|
|||
import { expect, test } from '@playwright/test'
|
||||
|
||||
test('多选时自定义全部的文本', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#all-text')
|
||||
const wrap = page.locator('#all-text')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
|
||||
await select.locator('.tiny-input__suffix').click()
|
||||
await expect(option.filter({ hasText: '全部小吃' })).toHaveCount(1)
|
||||
})
|
|
@ -0,0 +1,36 @@
|
|||
<template>
|
||||
<div>
|
||||
<tiny-base-select v-model="value" multiple all-text="全部小吃">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: [],
|
||||
options: [
|
||||
{ value: '选项1', label: '黄金糕' },
|
||||
{ value: '选项2', label: '双皮奶' },
|
||||
{ value: '选项3', label: '蚵仔煎' },
|
||||
{ value: '选项4', label: '龙须面' },
|
||||
{ value: '选项6', label: '螺蛳粉' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,102 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>场景1:allow-create + filterable,点击创建条目</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value" allow-create filterable>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:allow-create + filterable + default-first-option,Enter 键创建条目</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value" allow-create filterable default-first-option>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景3:下拉框显示新增按钮</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value"
|
||||
placeholder="请选择"
|
||||
@top-create-click="handleAddOption"
|
||||
automatic-dropdown
|
||||
top-create
|
||||
ref="selectDom"
|
||||
>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<tiny-dialog-box :visible="boxVisibility" @update:visible="boxVisibility = $event" title="新建" width="30%">
|
||||
<div>
|
||||
<div>
|
||||
<span>label</span>
|
||||
<br />
|
||||
<br />
|
||||
<tiny-input v-model="optionLabel"></tiny-input>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<span>value</span>
|
||||
<br />
|
||||
<br />
|
||||
<tiny-input v-model="optionValue"></tiny-input>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<tiny-button @click="boxVisibility = false">取消</tiny-button>
|
||||
<tiny-button type="primary" @click="handleConfirm"> 确定 </tiny-button>
|
||||
</template>
|
||||
</tiny-dialog-box>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
BaseSelect as TinyBaseSelect,
|
||||
Option as TinyOption,
|
||||
Input as TinyInput,
|
||||
Button as TinyButton,
|
||||
DialogBox as TinyDialogBox,
|
||||
Modal
|
||||
} from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
|
||||
const selectDom = ref(null)
|
||||
const value = ref('')
|
||||
const boxVisibility = ref(false)
|
||||
const optionLabel = ref('')
|
||||
const optionValue = ref('')
|
||||
|
||||
const handleAddOption = () => {
|
||||
optionValue.value = ''
|
||||
optionLabel.value = ''
|
||||
boxVisibility.value = true
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
if (!optionLabel.value || !optionValue.value) {
|
||||
Modal.message({ message: '选项不能为空!', status: 'warning' })
|
||||
return
|
||||
}
|
||||
boxVisibility.value = false
|
||||
options.value.unshift({
|
||||
value: optionValue,
|
||||
label: optionLabel
|
||||
})
|
||||
selectDom.value.focus()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,50 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('点击选中', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.waitForTimeout(300)
|
||||
await page.goto('select#allow-create')
|
||||
|
||||
const wrap = page.locator('#allow-create')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
|
||||
await input.click()
|
||||
await input.fill('测试allow-create')
|
||||
const KeyboardEvent = await page.evaluateHandle(() => new KeyboardEvent('keyup'))
|
||||
await input.dispatchEvent('keyup', { KeyboardEvent })
|
||||
|
||||
await expect(input).toHaveValue('测试allow-create')
|
||||
await dropdown.getByRole('listitem').filter({ hasText: '测试allow-create' }).click()
|
||||
await expect(input).toHaveValue('测试allow-create')
|
||||
|
||||
await input.click()
|
||||
await expect(input).toHaveValue('')
|
||||
await expect(dropdown.getByRole('listitem').filter({ hasText: '测试allow-create' })).toHaveClass(/selected/)
|
||||
})
|
||||
|
||||
test('enter 选中', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.waitForTimeout(300)
|
||||
await page.goto('select#allow-create')
|
||||
|
||||
const wrap = page.locator('#allow-create')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
|
||||
await input.click()
|
||||
await input.press('a')
|
||||
await input.press('b')
|
||||
await page.waitForTimeout(300)
|
||||
await input.press('Enter')
|
||||
|
||||
await expect(dropdown).toBeHidden()
|
||||
await expect(input).toHaveValue('ab')
|
||||
|
||||
await input.click()
|
||||
|
||||
await expect(input).toHaveValue('')
|
||||
await expect(dropdown.getByRole('listitem').filter({ hasText: 'ab' })).toHaveClass(/selected/)
|
||||
})
|
|
@ -0,0 +1,105 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>场景1:allow-create + filterable,点击创建条目</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value" allow-create filterable>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:allow-create + filterable + default-first-option,Enter 键创建条目</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value" allow-create filterable default-first-option>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景3:下拉框显示新增按钮</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value"
|
||||
placeholder="请选择"
|
||||
@top-create-click="handleAddOption"
|
||||
automatic-dropdown
|
||||
top-create
|
||||
ref="selectDom"
|
||||
>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<tiny-dialog-box :visible="boxVisibility" @update:visible="boxVisibility = $event" title="新建" width="30%">
|
||||
<div>
|
||||
<div>
|
||||
<span>label</span>
|
||||
<br />
|
||||
<br />
|
||||
<tiny-input v-model="optionLabel"></tiny-input>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<span>value</span>
|
||||
<br />
|
||||
<br />
|
||||
<tiny-input v-model="optionValue"></tiny-input>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<tiny-button @click="boxVisibility = false">取消</tiny-button>
|
||||
<tiny-button type="primary" @click="handleConfirm"> 确定 </tiny-button>
|
||||
</template>
|
||||
</tiny-dialog-box>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option, Input, Button, DialogBox, Modal } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option,
|
||||
TinyInput: Input,
|
||||
TinyButton: Button,
|
||||
TinyDialogBox: DialogBox
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value: '',
|
||||
boxVisibility: false,
|
||||
optionLabel: '',
|
||||
optionValue: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleAddOption() {
|
||||
this.optionValue = ''
|
||||
this.optionLabel = ''
|
||||
this.boxVisibility = true
|
||||
},
|
||||
handleConfirm() {
|
||||
if (!this.optionLabel || !this.optionValue) {
|
||||
Modal.message({ message: '选项不能为空!', status: 'warning' })
|
||||
return
|
||||
}
|
||||
this.boxVisibility = false
|
||||
this.options.unshift({
|
||||
value: this.optionValue,
|
||||
label: this.optionLabel
|
||||
})
|
||||
this.$refs.selectDom.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:默认不可搜索时,获取焦点不下拉</p>
|
||||
<tiny-button @click="handleFocus1"> 点击获取焦点 </tiny-button>
|
||||
<tiny-base-select v-model="value" ref="selectOnlyFocusRef">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景2:设置不可搜索时,获取焦点并自动下拉</p>
|
||||
<tiny-button @click="handleFocus2"> 点击获取焦点 </tiny-button>
|
||||
<tiny-base-select v-model="value" ref="selectAutoDropRef" automatic-dropdown>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption, Button as TinyButton } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
const value = ref('')
|
||||
const selectOnlyFocusRef = ref()
|
||||
const selectAutoDropRef = ref()
|
||||
|
||||
const handleFocus1 = () => {
|
||||
selectOnlyFocusRef.value.focus()
|
||||
}
|
||||
|
||||
const handleFocus2 = () => {
|
||||
selectAutoDropRef.value.focus()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.tiny-button {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,31 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('不可搜索时,获取焦点不下拉', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#automatic-dropdown')
|
||||
const wrap = page.locator('#automatic-dropdown')
|
||||
const input = wrap.locator('.tiny-input__inner').first()
|
||||
const dropdown = page.locator('.tiny-select-dropdown').first()
|
||||
|
||||
await wrap.getByRole('button').first().click()
|
||||
// 聚焦高亮
|
||||
await expect(input).toHaveCSS('border-color', 'rgb(94, 124, 224)')
|
||||
// 不下拉
|
||||
await expect(dropdown).toBeHidden()
|
||||
})
|
||||
|
||||
test('可搜索时,获取焦点自动下拉', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#automatic-dropdown')
|
||||
const wrap = page.locator('#automatic-dropdown')
|
||||
const input = wrap.locator('.tiny-input__inner').nth(1)
|
||||
const dropdown = page.locator('.tiny-select-dropdown').nth(1)
|
||||
|
||||
await wrap.getByRole('button').nth(1).click()
|
||||
// 聚焦下拉
|
||||
await dropdown.getByRole('listitem').filter({ hasText: '上海' }).click()
|
||||
await expect(input).toHaveValue('上海')
|
||||
// 验证选中
|
||||
await input.click()
|
||||
await expect(page.getByRole('listitem').filter({ hasText: '上海' })).toHaveClass(/selected/)
|
||||
})
|
|
@ -0,0 +1,59 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:默认不可搜索时,获取焦点不下拉</p>
|
||||
<tiny-button @click="handleFocus1"> 点击获取焦点 </tiny-button>
|
||||
<tiny-base-select v-model="value" ref="selectOnlyFocusRef">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景2:设置不可搜索时,获取焦点并自动下拉</p>
|
||||
<tiny-button @click="handleFocus2"> 点击获取焦点 </tiny-button>
|
||||
<tiny-base-select v-model="value" ref="selectAutoDropRef" automatic-dropdown>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option,
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleFocus1() {
|
||||
this.$refs.selectOnlyFocusRef.focus()
|
||||
},
|
||||
handleFocus2() {
|
||||
this.$refs.selectAutoDropRef.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.tiny-button {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,38 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>选中的值为: {{ value }}</div>
|
||||
<br />
|
||||
<div>场景1:标签式</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" :icon="item.icon">
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:配置式</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value" :options="options"> </tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
import { iconFile } from '@opentiny/vue-icon'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京', icon: iconFile() },
|
||||
{ value: '选项2', label: '上海', icon: iconFile() },
|
||||
{ value: '选项3', label: '天津', icon: iconFile() },
|
||||
{ value: '选项4', label: '重庆', icon: iconFile() },
|
||||
{ value: '选项5', label: '深圳', icon: iconFile() }
|
||||
])
|
||||
const value = ref('')
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,47 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('基础用法标签式', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#basic-usage')
|
||||
const wrap = page.locator('#basic-usage')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
|
||||
await input.click()
|
||||
await option.filter({ hasText: '天津' }).click()
|
||||
await expect(input).toHaveValue('天津')
|
||||
await select.locator('.tiny-input__suffix svg').click()
|
||||
await expect(page.getByRole('listitem').filter({ hasText: '天津' })).toHaveClass(/selected/)
|
||||
await option.filter({ hasText: '深圳' }).click()
|
||||
await expect(input).toHaveValue('深圳')
|
||||
await input.click()
|
||||
await expect(option.filter({ hasText: '深圳' })).toHaveClass(/selected/)
|
||||
await expect(option.locator('.tiny-option__icon')).toHaveCount(5)
|
||||
await option.nth(0).click()
|
||||
await expect(dropdown).toBeHidden()
|
||||
})
|
||||
|
||||
test('基础用法配置式', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#basic-usage')
|
||||
const wrap = page.locator('#basic-usage')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
|
||||
await input.click()
|
||||
await option.filter({ hasText: '天津' }).click()
|
||||
await expect(input).toHaveValue('天津')
|
||||
await select.locator('.tiny-input__suffix svg').click()
|
||||
await expect(page.getByRole('listitem').filter({ hasText: '天津' })).toHaveClass(/selected/)
|
||||
await option.filter({ hasText: '深圳' }).click()
|
||||
await expect(input).toHaveValue('深圳')
|
||||
await input.click()
|
||||
await expect(option.filter({ hasText: '深圳' })).toHaveClass(/selected/)
|
||||
await expect(option.locator('.tiny-option__icon')).toHaveCount(5)
|
||||
await option.nth(0).click()
|
||||
await expect(dropdown).toBeHidden()
|
||||
})
|
|
@ -0,0 +1,47 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>选中的值为: {{ value }}</div>
|
||||
<br />
|
||||
<div>场景1:标签式</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" :icon="item.icon">
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:配置式</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value" :options="options"> </tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
import { iconFile } from '@opentiny/vue-icon'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京', icon: iconFile() },
|
||||
{ value: '选项2', label: '上海', icon: iconFile() },
|
||||
{ value: '选项3', label: '天津', icon: iconFile() },
|
||||
{ value: '选项4', label: '重庆', icon: iconFile() },
|
||||
{ value: '选项5', label: '深圳', icon: iconFile() }
|
||||
],
|
||||
value: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<div>
|
||||
<tiny-base-select v-model="value" value-key="val">
|
||||
<tiny-option v-for="(item, index) in options" :key="index" :label="item.text" :value="item.obj"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p class="value">
|
||||
{{ value }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ obj: { val: '选项1', id: 1 }, text: '北京' },
|
||||
{ obj: { val: '选项2', id: 2 }, text: '上海' },
|
||||
{ obj: { val: '选项3', id: 3 }, text: '天津' },
|
||||
{ obj: { val: '选项4', id: 4 }, text: '重庆' },
|
||||
{ obj: { val: '选项5', id: 5 }, text: '深圳' }
|
||||
])
|
||||
const value = ref({ val: '选项3', id: 3 })
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,21 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('binding-obj', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#binding-obj')
|
||||
|
||||
const wrap = page.locator('#binding-obj')
|
||||
const input = wrap.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('.tiny-select-dropdown')
|
||||
const valueLocator = wrap.locator('.value')
|
||||
|
||||
await input.click()
|
||||
await dropdown.getByRole('listitem').filter({ hasText: '重庆' }).click()
|
||||
await expect(input).toHaveValue('重庆')
|
||||
await expect(valueLocator).toHaveText('{ "val": "选项4", "id": 4 }')
|
||||
|
||||
await input.click()
|
||||
await dropdown.getByRole('listitem').filter({ hasText: '天津' }).click()
|
||||
await expect(input).toHaveValue('天津')
|
||||
await expect(valueLocator).toHaveText('{ "val": "选项3", "id": 3 }')
|
||||
})
|
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<div>
|
||||
<tiny-base-select v-model="value" value-key="val">
|
||||
<tiny-option v-for="(item, index) in options" :key="index" :label="item.text" :value="item.obj"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p class="value">
|
||||
{{ value }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ obj: { val: '选项1', id: 1 }, text: '北京' },
|
||||
{ obj: { val: '选项2', id: 2 }, text: '上海' },
|
||||
{ obj: { val: '选项3', id: 3 }, text: '天津' },
|
||||
{ obj: { val: '选项4', id: 4 }, text: '重庆' },
|
||||
{ obj: { val: '选项5', id: 5 }, text: '深圳' }
|
||||
],
|
||||
value: { val: '选项3', id: 3 }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<div>
|
||||
<tiny-base-select
|
||||
v-model="value"
|
||||
clearable
|
||||
:options="options"
|
||||
:cache-op="cacheOp"
|
||||
@change="cacheChange"
|
||||
></tiny-base-select>
|
||||
<p class="cache-value">
|
||||
{{ cacheValue }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect } from '@opentiny/vue'
|
||||
|
||||
const cacheOp = ref({
|
||||
key: 'test'
|
||||
})
|
||||
const cacheValue = ref('')
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
const value = ref('选项3')
|
||||
const cacheChange = () => {
|
||||
cacheValue.value = window.localStorage.getItem(`tiny_memorize_${cacheOp.value.key}`)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,19 @@
|
|||
import { expect, test } from '@playwright/test'
|
||||
|
||||
test('cache-op', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#cache-usage')
|
||||
|
||||
const wrap = page.locator('#cache-usage')
|
||||
const dropdown = page.locator('.tiny-select-dropdown')
|
||||
const input = wrap.locator('.tiny-input__inner')
|
||||
const cacheValue = wrap.locator('.cache-value')
|
||||
|
||||
await input.click()
|
||||
await dropdown.getByRole('listitem').filter({ hasText: '北京' }).click()
|
||||
await expect(cacheValue).toContainText(['选项1'])
|
||||
|
||||
await input.click()
|
||||
await dropdown.getByRole('listitem').filter({ hasText: '上海' }).click()
|
||||
await expect(cacheValue).toContainText(['选项2'])
|
||||
})
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<div>
|
||||
<tiny-base-select
|
||||
v-model="value"
|
||||
clearable
|
||||
:options="options"
|
||||
:cache-op="cacheOp"
|
||||
@change="cacheChange"
|
||||
></tiny-base-select>
|
||||
<p class="cache-value">
|
||||
{{ cacheValue }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cacheOp: {
|
||||
key: 'test'
|
||||
},
|
||||
cacheValue: '',
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value: '选项3'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cacheChange() {
|
||||
this.cacheValue = window.localStorage.getItem(`tiny_memorize_${this.cacheOp.key}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>
|
||||
场景1:单选,val 找不到匹配值,val为: ,<span class="val">{{ val }}</span>
|
||||
</p>
|
||||
<tiny-base-select v-model="val" :clear-no-match-value="true">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
|
||||
<p>
|
||||
场景2:多选,multiVal 找不到匹配值,multiVal 为:<span class="multi-val">{{ multiVal }}</span>
|
||||
</p>
|
||||
<tiny-base-select v-model="multiVal" :clear-no-match-value="true" multiple>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
|
||||
const val = ref('11')
|
||||
const multiVal = ref(['选项2', '11'])
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,24 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('单选找不到匹配值', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#clear-no-match-value')
|
||||
const wrap = page.locator('#clear-no-match-value')
|
||||
const input = wrap.locator('.tiny-input__inner').nth(0)
|
||||
|
||||
// 验证是否清空不匹配的值
|
||||
await expect(input).toHaveValue('')
|
||||
await expect(wrap.locator('.val')).toHaveText('')
|
||||
})
|
||||
|
||||
test('多选找不到匹配值', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#clear-no-match-value')
|
||||
const wrap = page.locator('#clear-no-match-value')
|
||||
const tag = wrap.locator('.tiny-select').nth(1).locator('.tiny-tag')
|
||||
|
||||
// 验证是否清空不匹配的值
|
||||
await expect(tag).toHaveCount(1)
|
||||
await expect(tag).toHaveText('上海')
|
||||
await expect(wrap.locator('.multi-val')).toHaveText('[ "选项2" ]')
|
||||
})
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>
|
||||
场景1:单选,val 找不到匹配值,val为: ,<span class="val">{{ val }}</span>
|
||||
</p>
|
||||
<tiny-base-select v-model="val" :clear-no-match-value="true">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
|
||||
<p>
|
||||
场景2:多选,multiVal 找不到匹配值,multiVal 为:<span class="multi-val">{{ multiVal }}</span>
|
||||
</p>
|
||||
<tiny-base-select v-model="multiVal" :clear-no-match-value="true" multiple>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
val: '11',
|
||||
multiVal: ['选项2', '11']
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,25 @@
|
|||
<template>
|
||||
<tiny-base-select v-model="value" clearable>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
const value = ref('选项3')
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,21 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('clearable', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#clearable')
|
||||
const wrap = page.locator('#clearable')
|
||||
const dropdown = page.locator('.tiny-select-dropdown')
|
||||
const input = wrap.locator('.tiny-input__inner')
|
||||
const icon = wrap.locator('.tiny-input__suffix')
|
||||
|
||||
// 验证默认值
|
||||
await expect(input).toHaveValue('天津')
|
||||
// 验证清空
|
||||
await input.hover()
|
||||
await icon.click()
|
||||
await expect(input).toHaveValue('')
|
||||
// 验证选中
|
||||
await icon.click()
|
||||
await dropdown.getByRole('listitem').filter({ hasText: '上海' }).click()
|
||||
await expect(input).toHaveValue('上海')
|
||||
})
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<tiny-base-select v-model="value" clearable>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value: '选项3'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<div>
|
||||
<br />
|
||||
<div>场景1: collapse-tags折叠</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value1" :show-proportion="true" multiple collapse-tags>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2: hover-expand 折叠</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value2" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<div>场景3: click-expand 折叠</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value3" :max-visible-rows="2" multiple click-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆超长超长超长超长超长超长超长超长超长' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
|
||||
const value1 = ref(['选项1', '选项2'])
|
||||
const value2 = ref(['选项1', '选项2', '选项3', '选项4'])
|
||||
const value3 = ref(['选项1', '选项2', '选项3', '选项4', '选项5'])
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,32 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('collapse-tags', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#collapse-tags')
|
||||
const wrap = page.locator('#collapse-tags')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const tag = select.locator('.tiny-tag')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
|
||||
// 验证默认值的折叠标签显示
|
||||
await expect(tag).toHaveCount(2)
|
||||
await expect(tag.filter({ hasText: '北京' })).toBeVisible()
|
||||
await expect(tag.filter({ hasText: '+ 1' })).toBeVisible()
|
||||
|
||||
// 点击下拉后选中效果
|
||||
await tag.first().click()
|
||||
await expect(option.filter({ hasText: '北京' })).toHaveClass(/selected/)
|
||||
await expect(option.filter({ hasText: '上海' })).toHaveClass(/selected/)
|
||||
|
||||
// 取消选中一个
|
||||
await option.filter({ hasText: '北京' }).locator('span').nth(2).click()
|
||||
await expect(tag.filter({ hasText: '+ 1' })).toBeHidden()
|
||||
await expect(tag).toHaveCount(1)
|
||||
|
||||
// 再选中2个
|
||||
await option.filter({ hasText: '天津' }).locator('span').nth(2).click()
|
||||
await option.filter({ hasText: '深圳' }).locator('span').nth(2).click()
|
||||
await expect(tag.filter({ hasText: '+ 2' })).toBeVisible()
|
||||
await expect(tag).toHaveCount(2)
|
||||
})
|
|
@ -0,0 +1,56 @@
|
|||
<template>
|
||||
<div>
|
||||
<br />
|
||||
<div>场景1: collapse-tags折叠</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value1" :show-proportion="true" multiple collapse-tags>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2: hover-expand 折叠</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value2" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<div>场景3: click-expand 折叠</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value3" :max-visible-rows="2" multiple click-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆超长超长超长超长超长超长超长超长超长' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value1: ['选项1', '选项2'],
|
||||
value2: ['选项1', '选项2', '选项3', '选项4'],
|
||||
value3: ['选项1', '选项2', '选项3', '选项4', '选项5']
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,44 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:多选复制单个标签</p>
|
||||
<tiny-base-select ref="selectTagSelectable" v-model="value1" multiple tag-selectable>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景2:多选一键复制所有标签</p>
|
||||
<tiny-base-select ref="selectCopyable" v-model="value2" multiple copyable>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景3:多选设置复制文本分隔符</p>
|
||||
<tiny-base-select ref="selectCopyable" v-model="value2" multiple copyable text-split="/">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>复制到此处:</p>
|
||||
<tiny-input v-model="copyValue" class="copy-value" type="text"></tiny-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption, Input as TinyInput } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
const value1 = ref(['选项1'])
|
||||
const value2 = ref(['选项1', '选项2'])
|
||||
const copyValue = ref('')
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,63 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('多选复制单个标签', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#copy-multi')
|
||||
|
||||
const wrap = page.locator('#copy-multi')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const tag = select.locator('.tiny-tag').nth(0)
|
||||
|
||||
await expect(tag).toContainText('北京')
|
||||
await page.waitForTimeout(200)
|
||||
const tagBox = await tag.locator('span').boundingBox()
|
||||
const x = tagBox.x + tagBox.width
|
||||
const y = tagBox.y + tagBox.height - 5
|
||||
|
||||
await page.mouse.move(tagBox.x, tagBox.y)
|
||||
await page.waitForTimeout(200)
|
||||
await page.mouse.down()
|
||||
await page.waitForTimeout(200)
|
||||
await page.mouse.move(x, y)
|
||||
await page.waitForTimeout(200)
|
||||
await page.mouse.up()
|
||||
|
||||
await page.keyboard.press('Control+C')
|
||||
await page.waitForTimeout(200)
|
||||
const valueInput = page.locator('.copy-value .tiny-input__inner')
|
||||
await expect(valueInput).toHaveValue('')
|
||||
await valueInput.focus()
|
||||
await page.keyboard.press('Control+V')
|
||||
await page.waitForTimeout(200)
|
||||
await expect(valueInput).toHaveValue('北京')
|
||||
})
|
||||
|
||||
test('多选一键复制所有标签', async ({ page }) => {
|
||||
await page.goto('select#copy-multi')
|
||||
|
||||
const wrap = page.locator('#copy-multi')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const copyValueInput = wrap.locator('.copy-value .tiny-input__inner')
|
||||
|
||||
await page.waitForTimeout(200)
|
||||
await select.hover()
|
||||
await select.locator('.tiny-select__copy > .tiny-svg').click()
|
||||
|
||||
await copyValueInput.press('Control+V')
|
||||
await expect(copyValueInput).toHaveValue('北京,上海')
|
||||
})
|
||||
|
||||
test('多选设置复制文本分隔符', async ({ page }) => {
|
||||
await page.goto('select#copy-multi')
|
||||
|
||||
const wrap = page.locator('#copy-multi')
|
||||
const select = wrap.locator('.tiny-select').nth(2)
|
||||
const copyValueInput = wrap.locator('.copy-value .tiny-input__inner')
|
||||
|
||||
await page.waitForTimeout(200)
|
||||
await select.hover()
|
||||
await select.locator('.tiny-select__copy > .tiny-svg').click()
|
||||
|
||||
await copyValueInput.press('Control+V')
|
||||
await expect(copyValueInput).toHaveValue('北京/上海')
|
||||
})
|
|
@ -0,0 +1,54 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:多选复制单个标签</p>
|
||||
<tiny-base-select ref="selectTagSelectable" v-model="value1" multiple tag-selectable>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景2:多选一键复制所有标签</p>
|
||||
<tiny-base-select ref="selectCopyable" v-model="value2" multiple copyable>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景3:多选设置复制文本分隔符</p>
|
||||
<tiny-base-select ref="selectCopyable" v-model="value2" multiple copyable text-split="/">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>复制到此处:</p>
|
||||
<tiny-input v-model="copyValue" class="copy-value" type="text"></tiny-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option, Input } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option,
|
||||
TinyInput: Input
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value1: ['选项1'],
|
||||
value2: ['选项1', '选项2'],
|
||||
copyValue: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,150 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:单选无需配置可复制</p>
|
||||
<tiny-base-select v-model="value1" :options="options1"> </tiny-base-select>
|
||||
<p>场景2:单选可搜索配置 allow-copy 可复制</p>
|
||||
<tiny-base-select
|
||||
ref="selectRef"
|
||||
v-model="value1"
|
||||
:options="options1"
|
||||
filterable
|
||||
:filter-method="filter"
|
||||
allow-copy
|
||||
>
|
||||
</tiny-base-select>
|
||||
|
||||
<p>场景3:单选远程搜索配置 allow-copy 可复制</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
filterable
|
||||
remote
|
||||
placeholder="请输入关键词"
|
||||
:remote-method="remoteMethod"
|
||||
:loading="loading"
|
||||
loading-text="Loading..."
|
||||
allow-copy
|
||||
>
|
||||
<tiny-option v-for="item in options2" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p class="font-style">粘贴至此处:</p>
|
||||
<tiny-input v-model="inputVal" type="text" class="custom"></tiny-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption, Input as TinyInput } from '@opentiny/vue'
|
||||
|
||||
const options1 = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
const options2 = ref([])
|
||||
const value1 = ref('选项1')
|
||||
const value2 = ref('Alabama')
|
||||
const inputVal = ref('')
|
||||
const selectRef = ref(null)
|
||||
const loading = ref(false)
|
||||
const list = ref([])
|
||||
|
||||
const filter = (value) => {
|
||||
const select = selectRef.value
|
||||
|
||||
if (value) {
|
||||
select.state.cachedOptions.forEach((item) => {
|
||||
item.state.visible = item.label.includes(value)
|
||||
})
|
||||
} else {
|
||||
select.state.cachedOptions.forEach((item) => {
|
||||
item.state.visible = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const remoteMethod = (query) => {
|
||||
if (query !== undefined) {
|
||||
loading.value = true
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
options2.value = list.value.filter((item) => {
|
||||
return item.label.toLowerCase().includes(query.toLowerCase())
|
||||
})
|
||||
}, 200)
|
||||
} else {
|
||||
options2.value = []
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const states = [
|
||||
'Alabama',
|
||||
'Alaska',
|
||||
'Arizona',
|
||||
'Arkansas',
|
||||
'California',
|
||||
'Colorado',
|
||||
'Connecticut',
|
||||
'Delaware',
|
||||
'Florida',
|
||||
'Georgia',
|
||||
'Hawaii',
|
||||
'Idaho',
|
||||
'Illinois',
|
||||
'Indiana',
|
||||
'Iowa',
|
||||
'Kansas',
|
||||
'Kentucky',
|
||||
'Louisiana',
|
||||
'Maine',
|
||||
'Maryland',
|
||||
'Massachusetts',
|
||||
'Michigan',
|
||||
'Minnesota',
|
||||
'Mississippi',
|
||||
'Missouri',
|
||||
'Montana',
|
||||
'Nebraska',
|
||||
'Nevada',
|
||||
'New Hampshire',
|
||||
'New Jersey',
|
||||
'New Mexico',
|
||||
'New York',
|
||||
'North Carolina',
|
||||
'North Dakota',
|
||||
'Ohio',
|
||||
'Oklahoma',
|
||||
'Oregon',
|
||||
'Pennsylvania',
|
||||
'Rhode Island',
|
||||
'South Carolina',
|
||||
'South Dakota',
|
||||
'Tennessee',
|
||||
'Texas',
|
||||
'Utah',
|
||||
'Vermont',
|
||||
'Virginia',
|
||||
'Washington',
|
||||
'West Virginia',
|
||||
'Wisconsin',
|
||||
'Wyoming'
|
||||
]
|
||||
|
||||
list.value = states.map((item) => {
|
||||
return { value: item, label: item }
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,76 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('单选无需配置可复制', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#copy-single')
|
||||
|
||||
const wrap = page.locator('#copy-single')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const valueInput = wrap.locator('.custom .tiny-input__inner')
|
||||
|
||||
await page.waitForTimeout(200)
|
||||
const inputBox = await input.boundingBox()
|
||||
|
||||
await page.mouse.move(inputBox.x + inputBox?.width / 2, inputBox.y + inputBox?.height / 2)
|
||||
await page.mouse.down()
|
||||
await page.mouse.move(inputBox.x - 2, inputBox.y + inputBox?.height / 2)
|
||||
await page.mouse.up()
|
||||
await page.keyboard.press('Control+C')
|
||||
await expect(valueInput).toHaveValue('')
|
||||
await valueInput.focus()
|
||||
await page.keyboard.press('Control+V')
|
||||
await page.waitForTimeout(200)
|
||||
await expect(valueInput).toHaveValue('北京')
|
||||
})
|
||||
|
||||
test('单选可搜索配置 allow-copy 可复制', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#copy-single')
|
||||
|
||||
const wrap = page.locator('#copy-single')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const valueInput = wrap.locator('.custom .tiny-input__inner')
|
||||
|
||||
await expect(input).toHaveValue('北京')
|
||||
await page.waitForTimeout(200)
|
||||
const inputBox = await input.boundingBox()
|
||||
|
||||
await page.mouse.move(inputBox.x + inputBox?.width / 2, inputBox.y + inputBox?.height / 2)
|
||||
await page.mouse.down()
|
||||
await page.mouse.move(inputBox.x - 2, inputBox.y + inputBox?.height / 2)
|
||||
await page.mouse.up()
|
||||
await page.waitForTimeout(800)
|
||||
|
||||
await page.keyboard.press('Control+C')
|
||||
await expect(valueInput).toHaveValue('')
|
||||
await valueInput.click()
|
||||
await page.keyboard.press('Control+V')
|
||||
await page.waitForTimeout(200)
|
||||
await expect(valueInput).toHaveValue('北京')
|
||||
})
|
||||
|
||||
test('单选远程搜索配置 allow-copy 可复制', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#copy-single')
|
||||
|
||||
const wrap = page.locator('#copy-single')
|
||||
const select = wrap.locator('.tiny-select').nth(2)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const valueInput = wrap.locator('.custom .tiny-input__inner')
|
||||
|
||||
await page.waitForTimeout(100)
|
||||
const inputBox = await input.boundingBox()
|
||||
|
||||
await page.mouse.move(inputBox.x + inputBox?.width / 2, inputBox.y + inputBox?.height / 2)
|
||||
await page.mouse.down()
|
||||
await page.mouse.move(inputBox.x - 2, inputBox.y + inputBox?.height / 2)
|
||||
await page.mouse.up()
|
||||
await page.keyboard.press('Control+C')
|
||||
await expect(valueInput).toHaveValue('')
|
||||
await valueInput.focus()
|
||||
await page.keyboard.press('Control+V')
|
||||
await page.waitForTimeout(200)
|
||||
await expect(valueInput).toHaveValue('Alabama')
|
||||
})
|
|
@ -0,0 +1,156 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:单选无需配置可复制</p>
|
||||
<tiny-base-select v-model="value1" :options="options1"> </tiny-base-select>
|
||||
<p>场景2:单选可搜索配置 allow-copy 可复制</p>
|
||||
<tiny-base-select
|
||||
ref="selectRef"
|
||||
v-model="value1"
|
||||
:options="options1"
|
||||
filterable
|
||||
:filter-method="filter"
|
||||
allow-copy
|
||||
>
|
||||
</tiny-base-select>
|
||||
|
||||
<p>场景3:单选远程搜索配置 allow-copy 可复制</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
filterable
|
||||
remote
|
||||
placeholder="请输入关键词"
|
||||
:remote-method="remoteMethod"
|
||||
:loading="loading"
|
||||
loading-text="Loading..."
|
||||
allow-copy
|
||||
>
|
||||
<tiny-option v-for="item in options2" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p class="font-style">粘贴至此处:</p>
|
||||
<tiny-input v-model="inputVal" type="text" class="custom"></tiny-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option, Input } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option,
|
||||
TinyInput: Input
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options1: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
options2: [],
|
||||
value1: '选项1',
|
||||
value2: 'Alabama',
|
||||
inputVal: '',
|
||||
loading: false,
|
||||
list: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const states = [
|
||||
'Alabama',
|
||||
'Alaska',
|
||||
'Arizona',
|
||||
'Arkansas',
|
||||
'California',
|
||||
'Colorado',
|
||||
'Connecticut',
|
||||
'Delaware',
|
||||
'Florida',
|
||||
'Georgia',
|
||||
'Hawaii',
|
||||
'Idaho',
|
||||
'Illinois',
|
||||
'Indiana',
|
||||
'Iowa',
|
||||
'Kansas',
|
||||
'Kentucky',
|
||||
'Louisiana',
|
||||
'Maine',
|
||||
'Maryland',
|
||||
'Massachusetts',
|
||||
'Michigan',
|
||||
'Minnesota',
|
||||
'Mississippi',
|
||||
'Missouri',
|
||||
'Montana',
|
||||
'Nebraska',
|
||||
'Nevada',
|
||||
'New Hampshire',
|
||||
'New Jersey',
|
||||
'New Mexico',
|
||||
'New York',
|
||||
'North Carolina',
|
||||
'North Dakota',
|
||||
'Ohio',
|
||||
'Oklahoma',
|
||||
'Oregon',
|
||||
'Pennsylvania',
|
||||
'Rhode Island',
|
||||
'South Carolina',
|
||||
'South Dakota',
|
||||
'Tennessee',
|
||||
'Texas',
|
||||
'Utah',
|
||||
'Vermont',
|
||||
'Virginia',
|
||||
'Washington',
|
||||
'West Virginia',
|
||||
'Wisconsin',
|
||||
'Wyoming'
|
||||
]
|
||||
this.list = states.map((item) => {
|
||||
return { value: item, label: item }
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
filter(value) {
|
||||
const select = this.$refs.selectRef
|
||||
|
||||
if (value) {
|
||||
select.state.cachedOptions.forEach((item) => {
|
||||
item.state.visible = item.label.includes(value)
|
||||
})
|
||||
} else {
|
||||
select.state.cachedOptions.forEach((item) => {
|
||||
item.state.visible = true
|
||||
})
|
||||
}
|
||||
},
|
||||
remoteMethod(query) {
|
||||
if (query !== undefined) {
|
||||
this.loading = true
|
||||
setTimeout(() => {
|
||||
this.loading = false
|
||||
this.options2 = this.list.filter((item) => {
|
||||
return item.label.toLowerCase().includes(query.toLowerCase())
|
||||
})
|
||||
}, 200)
|
||||
} else {
|
||||
this.options2 = []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,100 @@
|
|||
<template>
|
||||
<div>
|
||||
<br />
|
||||
<div>场景1: 下拉禁用</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value1" disabled autocomplete>
|
||||
<tiny-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:多选 + 下拉某项禁用</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value2" multiple>
|
||||
<tiny-option
|
||||
v-for="item in options2"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:disabled="item.disabled"
|
||||
>
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景3:单选 + 下拉某项禁用</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value3">
|
||||
<tiny-option
|
||||
v-for="item in options2"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:disabled="item.disabled"
|
||||
>
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景4:多选 + 禁用项默认选中</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value4" multiple>
|
||||
<tiny-option
|
||||
v-for="item in options2"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:disabled="item.disabled"
|
||||
>
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景5:多选 hover-expand 模式下禁用</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value5"
|
||||
placeholder="请选择"
|
||||
multiple
|
||||
disabled
|
||||
hover-expand
|
||||
disabled-tooltip-content="我是自定义内容"
|
||||
>
|
||||
<tiny-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options1 = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆重庆超长超长超长超长超长超长超长超长超长' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
|
||||
const options2 = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海', disabled: true },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆', disabled: true },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
|
||||
const value1 = ref('')
|
||||
const value2 = ref(['选项2'])
|
||||
const value3 = ref('')
|
||||
const value4 = ref(['选项2', '选项3'])
|
||||
const value5 = ref(['选项1', '选项2', '选项3', '选项4', '选项5'])
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,88 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('下拉禁用', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#disabled')
|
||||
const wrap = page.locator('#disabled')
|
||||
const input = wrap.locator('.tiny-input__inner').first()
|
||||
|
||||
const hasDisabled = await input.evaluate((input) => input.hasAttribute('disabled'))
|
||||
await expect(hasDisabled).toBe(true)
|
||||
})
|
||||
|
||||
test('多选某项禁用', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#disabled')
|
||||
const wrap = page.locator('#disabled')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const tag = select.locator('.tiny-tag')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
|
||||
await expect(tag).toHaveCount(1)
|
||||
await select.click()
|
||||
await expect(option.filter({ hasText: '上海' })).toHaveClass(/is-disabled/)
|
||||
|
||||
await option.filter({ hasText: '上海' }).click()
|
||||
await expect(tag).toHaveCount(1)
|
||||
|
||||
await option.filter({ hasText: '北京' }).click()
|
||||
await expect(tag).toHaveCount(2)
|
||||
await expect(tag.filter({ hasText: '北京' })).toHaveCount(1)
|
||||
})
|
||||
|
||||
test('单选某项禁用', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#disabled')
|
||||
const wrap = page.locator('#disabled')
|
||||
const select = wrap.locator('.tiny-select').nth(2)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
|
||||
await select.click()
|
||||
await expect(option.filter({ hasText: '全部' })).toHaveCount(0)
|
||||
await expect(option.filter({ hasText: '上海' })).toHaveClass(/is-disabled/)
|
||||
|
||||
await option.filter({ hasText: '上海' }).click()
|
||||
await expect(dropdown).toBeVisible()
|
||||
await expect(input).toHaveValue('')
|
||||
|
||||
await option.filter({ hasText: '北京' }).click()
|
||||
await expect(dropdown).toBeHidden()
|
||||
await expect(input).toHaveValue('北京')
|
||||
})
|
||||
|
||||
test('多选,禁用项默认选中', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#disabled')
|
||||
const wrap = page.locator('#disabled')
|
||||
const select = wrap.locator('.tiny-select').nth(3)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const tag = select.locator('.tiny-tag')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
|
||||
// 默认值显示tag数
|
||||
await expect(tag).toHaveCount(2)
|
||||
// 禁用项默认选中不显示关闭图标
|
||||
await expect(tag.filter({ hasText: '上海' }).locator('svg')).toHaveCount(0)
|
||||
// 非禁用项显示关闭图标
|
||||
await expect(tag.filter({ hasText: '天津' }).locator('svg')).toHaveCount(1)
|
||||
|
||||
// 下拉禁用和默认选中的效果
|
||||
await select.click()
|
||||
await expect(option.filter({ hasText: '全部' })).toHaveCount(1)
|
||||
await expect(option.filter({ hasText: '上海' })).toHaveClass(/is-disabled/)
|
||||
await expect(option.filter({ hasText: '上海' })).toHaveClass(/selected/)
|
||||
await expect(option.filter({ hasText: '天津' })).toHaveClass(/selected/)
|
||||
|
||||
// 点击禁用项不取消选中
|
||||
await option.filter({ hasText: '上海' }).click()
|
||||
await expect(dropdown).toBeVisible()
|
||||
await expect(tag).toHaveCount(2)
|
||||
|
||||
// 选中其他项
|
||||
await option.filter({ hasText: '北京' }).click()
|
||||
await expect(dropdown).toBeVisible()
|
||||
await expect(tag).toHaveCount(3)
|
||||
})
|
|
@ -0,0 +1,107 @@
|
|||
<template>
|
||||
<div>
|
||||
<br />
|
||||
<div>场景1: 下拉禁用</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value1" disabled autocomplete>
|
||||
<tiny-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:多选 + 下拉某项禁用</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value2" multiple>
|
||||
<tiny-option
|
||||
v-for="item in options2"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:disabled="item.disabled"
|
||||
>
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景3:单选 + 下拉某项禁用</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value3">
|
||||
<tiny-option
|
||||
v-for="item in options2"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:disabled="item.disabled"
|
||||
>
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景4:多选 + 禁用项默认选中</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value4" multiple>
|
||||
<tiny-option
|
||||
v-for="item in options2"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:disabled="item.disabled"
|
||||
>
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景5:多选 hover-expand 模式下禁用</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value5"
|
||||
placeholder="请选择"
|
||||
multiple
|
||||
disabled
|
||||
hover-expand
|
||||
disabled-tooltip-content="我是自定义内容"
|
||||
>
|
||||
<tiny-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options1: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆重庆超长超长超长超长超长超长超长超长超长' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
options2: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海', disabled: true },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆', disabled: true },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value1: '',
|
||||
value2: ['选项2'],
|
||||
value3: '',
|
||||
value4: ['选项2', '选项3'],
|
||||
value5: ['选项1', '选项2', '选项3', '选项4', '选项5']
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,106 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>单选</p>
|
||||
<tiny-base-select
|
||||
v-model="value1"
|
||||
clearable
|
||||
@change="change"
|
||||
@blur="blur"
|
||||
@focus="focus"
|
||||
@visible-change="visibleChange"
|
||||
@clear="clear"
|
||||
@dropdown-click="dropdownClick"
|
||||
>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
|
||||
<p>多选</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
multiple
|
||||
clearable
|
||||
@change="change"
|
||||
@blur="blur"
|
||||
@focus="focus"
|
||||
@visible-change="visibleChange"
|
||||
@remove-tag="removeTag"
|
||||
@dropdown-click="dropdownClick"
|
||||
>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption, Modal } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
const value1 = ref('')
|
||||
const value2 = ref([])
|
||||
|
||||
const change = () => {
|
||||
Modal.message({
|
||||
message: '触发 change 事件',
|
||||
status: 'info'
|
||||
})
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
Modal.message({
|
||||
message: '触发 clear 事件',
|
||||
status: 'info'
|
||||
})
|
||||
}
|
||||
|
||||
const focus = () => {
|
||||
Modal.message({
|
||||
message: '触发 focus 事件',
|
||||
status: 'info'
|
||||
})
|
||||
}
|
||||
|
||||
const blur = () => {
|
||||
Modal.message({
|
||||
message: '触发 blur 事件',
|
||||
status: 'info'
|
||||
})
|
||||
}
|
||||
|
||||
const removeTag = () => {
|
||||
Modal.message({
|
||||
message: '触发 remove-tag 事件',
|
||||
status: 'info'
|
||||
})
|
||||
}
|
||||
|
||||
const visibleChange = () => {
|
||||
Modal.message({
|
||||
message: '触发 visible-change 事件',
|
||||
status: 'info'
|
||||
})
|
||||
}
|
||||
|
||||
const dropdownClick = () => {
|
||||
Modal.message({
|
||||
message: '触发 dropdown-click 事件',
|
||||
status: 'info'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,72 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('单选事件', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#events')
|
||||
const wrap = page.locator('#events')
|
||||
const select = wrap.locator('.tiny-select').first()
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
const model = page.locator('.tiny-modal')
|
||||
|
||||
await input.click()
|
||||
await page.waitForTimeout(500)
|
||||
await expect(model.filter({ hasText: '触发 focus 事件' })).toHaveCount(1)
|
||||
await expect(model.filter({ hasText: '触发 visible-change 事件' })).toHaveCount(1)
|
||||
|
||||
await option.first().click()
|
||||
await expect(input).toHaveValue('北京')
|
||||
await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(1)
|
||||
await expect(model.filter({ hasText: '触发 visible-change 事件' })).toHaveCount(2)
|
||||
|
||||
await page.waitForTimeout(500)
|
||||
await wrap.click()
|
||||
await expect(model.filter({ hasText: '触发 blur 事件' })).toHaveCount(1)
|
||||
|
||||
await page.waitForTimeout(200)
|
||||
await input.hover()
|
||||
await select.locator('.tiny-select__caret.icon-close').click()
|
||||
await page.waitForTimeout(500)
|
||||
await expect(input).toHaveValue('')
|
||||
await expect(model.filter({ hasText: '触发 clear 事件' })).toHaveCount(1)
|
||||
})
|
||||
|
||||
test('多选事件', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#events')
|
||||
const wrap = page.locator('#events')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const tag = wrap.locator('.tiny-tag')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
const model = page.locator('.tiny-modal')
|
||||
|
||||
await page.waitForTimeout(500)
|
||||
await select.click()
|
||||
await expect(model.filter({ hasText: '触发 visible-change 事件' })).toHaveCount(1)
|
||||
|
||||
await option.nth(1).click()
|
||||
await expect(tag).toHaveCount(1)
|
||||
await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(1)
|
||||
|
||||
await option.nth(0).click()
|
||||
await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(2)
|
||||
await expect(tag).toHaveCount(5)
|
||||
|
||||
await page.waitForTimeout(500)
|
||||
await tag.first().locator('.tiny-tag__close').click()
|
||||
await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(1)
|
||||
await expect(model.filter({ hasText: '触发 remove-tag 事件' })).toHaveCount(1)
|
||||
await expect(tag).toHaveCount(4)
|
||||
|
||||
await wrap.click()
|
||||
await expect(model.filter({ hasText: '触发 visible-change 事件' })).toHaveCount(1)
|
||||
|
||||
await page.waitForTimeout(200)
|
||||
await select.hover()
|
||||
await select.locator('.tiny-select__caret.icon-close').click()
|
||||
|
||||
await expect(tag).toHaveCount(0)
|
||||
await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(1)
|
||||
})
|
|
@ -0,0 +1,112 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>单选</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value1"
|
||||
clearable
|
||||
@change="change"
|
||||
@blur="blur"
|
||||
@focus="focus"
|
||||
@visible-change="visibleChange"
|
||||
@clear="clear"
|
||||
@dropdown-click="dropdownClick"
|
||||
>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>多选</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
multiple
|
||||
clearable
|
||||
@change="change"
|
||||
@blur="blur"
|
||||
@focus="focus"
|
||||
@visible-change="visibleChange"
|
||||
@remove-tag="removeTag"
|
||||
@dropdown-click="dropdownClick"
|
||||
>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option, Modal } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value1: '',
|
||||
value2: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
change() {
|
||||
Modal.message({
|
||||
message: '触发 change 事件',
|
||||
status: 'info'
|
||||
})
|
||||
},
|
||||
clear() {
|
||||
Modal.message({
|
||||
message: '触发 clear 事件',
|
||||
status: 'info'
|
||||
})
|
||||
},
|
||||
focus() {
|
||||
Modal.message({
|
||||
message: '触发 focus 事件'
|
||||
})
|
||||
},
|
||||
blur() {
|
||||
Modal.message({
|
||||
message: '触发 blur 事件',
|
||||
status: 'info'
|
||||
})
|
||||
},
|
||||
removeTag() {
|
||||
Modal.message({
|
||||
message: '触发 remove-tag 事件',
|
||||
status: 'info'
|
||||
})
|
||||
},
|
||||
visibleChange() {
|
||||
Modal.message({
|
||||
message: '触发 visible-change 事件',
|
||||
status: 'info'
|
||||
})
|
||||
},
|
||||
dropdownClick() {
|
||||
Modal.message({
|
||||
message: '触发 dropdown-click 事件',
|
||||
status: 'info'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,155 @@
|
|||
<template>
|
||||
<div class="demo-select">
|
||||
<div>父选项:</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
ref="select3"
|
||||
v-model="radioValue1"
|
||||
:init-query="initQuery1"
|
||||
placeholder="请输入关键词"
|
||||
clearable
|
||||
:remote-method="remoteMethod1"
|
||||
:remote-config="{ autoSearch: true, clearData: true, showIcon: true }"
|
||||
remote
|
||||
filterable
|
||||
value-field="id"
|
||||
:multiple="true"
|
||||
text-field="label"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpRadio1"
|
||||
@change="change"
|
||||
></tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>子选项:</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
ref="select4"
|
||||
v-model="radioValue2"
|
||||
:init-query="initQuery2"
|
||||
placeholder="请输入关键词"
|
||||
clearable
|
||||
:remote-method="remoteMethod2"
|
||||
:remote-config="{ autoSearch: true, clearData: true, showIcon: true }"
|
||||
remote
|
||||
filterable
|
||||
:extra-query-params="extraQueryParams"
|
||||
value-field="id"
|
||||
:multiple="true"
|
||||
text-field="label"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpRadio2"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect } from '@opentiny/vue'
|
||||
|
||||
const parents = ref([])
|
||||
const children = ref([])
|
||||
const radioValue1 = ref(['001'])
|
||||
const radioValue2 = ref(['001'])
|
||||
const extraQueryParams = ref(null)
|
||||
|
||||
const gridOpRadio1 = reactive({
|
||||
data: [],
|
||||
height: 300,
|
||||
optimization: {
|
||||
animat: true,
|
||||
delayHover: 250,
|
||||
scrollX: { gt: 20 },
|
||||
scrollY: { gt: 20 }
|
||||
},
|
||||
columns: [
|
||||
{ type: 'selection', title: '' },
|
||||
{ field: 'label', title: '父级' }
|
||||
]
|
||||
})
|
||||
|
||||
const gridOpRadio2 = reactive({
|
||||
data: [],
|
||||
height: 300,
|
||||
optimization: {
|
||||
animat: true,
|
||||
delayHover: 250,
|
||||
scrollX: { gt: 20 },
|
||||
scrollY: { gt: 20 }
|
||||
},
|
||||
columns: [
|
||||
{ type: 'selection', title: '' },
|
||||
{ field: 'label', title: '子级' }
|
||||
]
|
||||
})
|
||||
|
||||
parents.value = [
|
||||
{ id: '001', label: '指南' },
|
||||
{ id: '002', label: '组件' }
|
||||
]
|
||||
|
||||
children.value = [
|
||||
{ id: '001', label: '安装', parent: '001' },
|
||||
{ id: '002', label: '开发', parent: '001' },
|
||||
{ id: '004', label: '框架风格', parent: '002' },
|
||||
{ id: '005', label: '表单组件', parent: '002' },
|
||||
{ id: '006', label: '数据组件', parent: '002' },
|
||||
{ id: '007', label: '提示组件', parent: '002' },
|
||||
{ id: '008', label: '导航组件', parent: '002' },
|
||||
{ id: '009', label: '其他组件', parent: '002' }
|
||||
]
|
||||
|
||||
extraQueryParams.value = radioValue1.value
|
||||
|
||||
const initQuery1 = () => {
|
||||
return new Promise((resolve) => {
|
||||
resolve(parents)
|
||||
})
|
||||
}
|
||||
|
||||
const remoteMethod1 = (value) => {
|
||||
let res = parents.value.filter((parent) => ~parent.label.indexOf(value || ''))
|
||||
|
||||
return new Promise((resolve) => {
|
||||
resolve(res)
|
||||
})
|
||||
}
|
||||
|
||||
// init 表示是否是初始化(mounted里面执行为初始化)
|
||||
const initQuery2 = (value, extraQueryParams, init) => {
|
||||
const res = children.value.filter((child) => extraQueryParams.includes(child.parent))
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(res)
|
||||
}, 1000)
|
||||
})
|
||||
}
|
||||
|
||||
const remoteMethod2 = (value, extraQueryParams) => {
|
||||
let child = children.value.filter((child) => extraQueryParams.includes(child.parent))
|
||||
const res = child.filter((child) => ~child.label.indexOf(value || ''))
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(res)
|
||||
}, 1000)
|
||||
})
|
||||
}
|
||||
|
||||
const change = (radioValue1) => {
|
||||
extraQueryParams.value = radioValue1
|
||||
|
||||
radioValue2.value = radioValue2.value.filter((value2) => {
|
||||
const selected = children.value.find((child) => child.id === value2)
|
||||
|
||||
return radioValue1.includes(selected.parent)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.demo-select .tiny-select {
|
||||
width: 270px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,157 @@
|
|||
<template>
|
||||
<div class="demo-select">
|
||||
<div>父选项:</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
ref="select3"
|
||||
v-model="radioValue1"
|
||||
:init-query="initQuery1"
|
||||
placeholder="请输入关键词"
|
||||
clearable
|
||||
:remote-method="remoteMethod1"
|
||||
:remote-config="{ autoSearch: true, clearData: true, showIcon: true }"
|
||||
remote
|
||||
filterable
|
||||
value-field="id"
|
||||
:multiple="true"
|
||||
text-field="label"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpRadio1"
|
||||
@change="change"
|
||||
></tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>子选项:</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
ref="select4"
|
||||
v-model="radioValue2"
|
||||
:init-query="initQuery2"
|
||||
placeholder="请输入关键词"
|
||||
clearable
|
||||
:remote-method="remoteMethod2"
|
||||
:remote-config="{ autoSearch: true, clearData: true, showIcon: true }"
|
||||
remote
|
||||
filterable
|
||||
:extra-query-params="extraQueryParams"
|
||||
value-field="id"
|
||||
:multiple="true"
|
||||
text-field="label"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpRadio2"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect
|
||||
},
|
||||
created() {
|
||||
this.parents = [
|
||||
{ id: '001', label: '指南' },
|
||||
{ id: '002', label: '组件' }
|
||||
]
|
||||
|
||||
this.children = [
|
||||
{ id: '001', label: '安装', parent: '001' },
|
||||
{ id: '002', label: '开发', parent: '001' },
|
||||
{ id: '004', label: '框架风格', parent: '002' },
|
||||
{ id: '005', label: '表单组件', parent: '002' },
|
||||
{ id: '006', label: '数据组件', parent: '002' },
|
||||
{ id: '007', label: '提示组件', parent: '002' },
|
||||
{ id: '008', label: '导航组件', parent: '002' },
|
||||
{ id: '009', label: '其他组件', parent: '002' }
|
||||
]
|
||||
|
||||
this.extraQueryParams = this.radioValue1
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
parents: [],
|
||||
children: [],
|
||||
radioValue1: ['001'],
|
||||
radioValue2: ['001'],
|
||||
gridOpRadio1: {
|
||||
data: [],
|
||||
height: 300,
|
||||
optimization: {
|
||||
animat: true,
|
||||
delayHover: 250,
|
||||
scrollX: { gt: 20 },
|
||||
scrollY: { gt: 20 }
|
||||
},
|
||||
columns: [
|
||||
{ type: 'selection', title: '' },
|
||||
{ field: 'label', title: '父级' }
|
||||
]
|
||||
},
|
||||
gridOpRadio2: {
|
||||
data: [],
|
||||
height: 300,
|
||||
optimization: {
|
||||
animat: true,
|
||||
delayHover: 250,
|
||||
scrollX: { gt: 20 },
|
||||
scrollY: { gt: 20 }
|
||||
},
|
||||
columns: [
|
||||
{ type: 'selection', title: '' },
|
||||
{ field: 'label', title: '子级' }
|
||||
]
|
||||
},
|
||||
extraQueryParams: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initQuery1() {
|
||||
return new Promise((resolve) => {
|
||||
resolve(this.parents)
|
||||
})
|
||||
},
|
||||
remoteMethod1(value) {
|
||||
const parents = this.parents.filter((parent) => ~parent.label.indexOf(value || ''))
|
||||
|
||||
return new Promise((resolve) => {
|
||||
resolve(parents)
|
||||
})
|
||||
},
|
||||
// init 表示是否是初始化(mounted里面执行为初始化)
|
||||
initQuery2(value, extraQueryParams, init) {
|
||||
const children = this.children.filter((child) => extraQueryParams.includes(child.parent))
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(children)
|
||||
}, 1000)
|
||||
})
|
||||
},
|
||||
remoteMethod2(value, extraQueryParams) {
|
||||
let children = this.children.filter((child) => extraQueryParams.includes(child.parent))
|
||||
children = children.filter((child) => ~child.label.indexOf(value || ''))
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(children)
|
||||
}, 1000)
|
||||
})
|
||||
},
|
||||
change(radioValue1) {
|
||||
this.extraQueryParams = radioValue1
|
||||
this.radioValue2 = this.radioValue2.filter((value2) => {
|
||||
const selected = this.children.find((child) => child.id === value2)
|
||||
return radioValue1.includes(selected.parent)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-select .tiny-select {
|
||||
width: 270px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,72 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:组件默认过滤</p>
|
||||
<tiny-base-select v-model="value1" ref="selectRef" filterable no-match-text="No Match">
|
||||
<tiny-option
|
||||
v-for="item in options"
|
||||
v-show="!item.filter"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景2:自定义过滤</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
ref="customFilterRef"
|
||||
filterable
|
||||
:filter-method="customFilterMethod"
|
||||
clearable
|
||||
no-match-text="No Match"
|
||||
>
|
||||
<tiny-option
|
||||
v-for="item in options"
|
||||
v-show="!item.filter"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
const value1 = ref('')
|
||||
const value2 = ref('')
|
||||
const selectRef = ref()
|
||||
const customFilterRef = ref()
|
||||
|
||||
const customFilterMethod = (searchValue) => {
|
||||
if (searchValue) {
|
||||
customFilterRef.value?.state.cachedOptions.forEach((item) => {
|
||||
item.state.visible = item.label.includes(searchValue)
|
||||
})
|
||||
} else {
|
||||
customFilterRef.value?.state.cachedOptions.forEach((item) => {
|
||||
item.state.visible = true
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,89 @@
|
|||
import { expect, test } from '@playwright/test'
|
||||
|
||||
test('默认搜索', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#filter-method')
|
||||
const wrap = page.locator('#filter-method')
|
||||
const select = wrap.locator('.tiny-select').first()
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
|
||||
// 1.1 没有过滤到内容
|
||||
await input.click()
|
||||
// 1.1.1 验证 no-match-text
|
||||
await expect(page.getByText('No Match')).toBeHidden()
|
||||
await input.press('1')
|
||||
await expect(input).toHaveValue('1')
|
||||
await input.press('Enter')
|
||||
await expect(page.getByText('No Match')).toBeVisible()
|
||||
|
||||
await page.waitForTimeout(500)
|
||||
let allListItems = await option.all()
|
||||
allListItems.forEach(async (item) => {
|
||||
await expect(item).toHaveCSS('display', 'none')
|
||||
})
|
||||
|
||||
// 1.2 过滤到内容
|
||||
await input.fill('上海')
|
||||
await expect(input).toHaveValue('上海')
|
||||
await input.press('Enter')
|
||||
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
allListItems.forEach(async (item) => {
|
||||
const isVisibleItem = (await item.innerText()) === '上海'
|
||||
if (isVisibleItem) {
|
||||
await expect(item).toHaveCSS('display', 'flex')
|
||||
} else {
|
||||
await expect(item).toHaveCSS('display', 'none')
|
||||
}
|
||||
})
|
||||
await expect(option.filter({ hasText: '上海' })).toBeVisible()
|
||||
await option.filter({ hasText: '上海' }).click()
|
||||
await expect(input).toHaveValue('上海')
|
||||
})
|
||||
|
||||
test('自定义过滤', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#filter-method')
|
||||
const wrap = page.locator('#filter-method')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
|
||||
// 1.1 没有过滤到内容
|
||||
await input.click()
|
||||
// 1.1.1 验证 no-match-text
|
||||
await expect(page.getByText('No Match')).toBeHidden()
|
||||
await input.press('1')
|
||||
await expect(input).toHaveValue('1')
|
||||
await input.press('Enter')
|
||||
await expect(page.getByText('No Match')).toBeVisible()
|
||||
|
||||
await page.waitForTimeout(500)
|
||||
let allListItems = await option.all()
|
||||
allListItems.forEach(async (item) => {
|
||||
await expect(item).toHaveCSS('display', 'none')
|
||||
})
|
||||
|
||||
// 1.2 过滤到内容
|
||||
await input.fill('上海')
|
||||
await expect(input).toHaveValue('上海')
|
||||
await input.press('Enter')
|
||||
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
allListItems.forEach(async (item) => {
|
||||
const isVisibleItem = (await item.innerText()) === '上海'
|
||||
if (isVisibleItem) {
|
||||
await expect(item).toHaveCSS('display', 'flex')
|
||||
} else {
|
||||
await expect(item).toHaveCSS('display', 'none')
|
||||
}
|
||||
})
|
||||
await expect(option.filter({ hasText: '上海' })).toBeVisible()
|
||||
await option.filter({ hasText: '上海' }).click()
|
||||
await expect(input).toHaveValue('上海')
|
||||
})
|
|
@ -0,0 +1,82 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:组件默认过滤</p>
|
||||
<tiny-base-select v-model="value1" ref="selectRef" filterable no-match-text="No Match">
|
||||
<tiny-option
|
||||
v-for="item in options"
|
||||
v-show="!item.filter"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景2:自定义过滤</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
ref="customFilterRef"
|
||||
filterable
|
||||
:filter-method="customFilterMethod"
|
||||
clearable
|
||||
no-match-text="No Match"
|
||||
>
|
||||
<tiny-option
|
||||
v-for="item in options"
|
||||
v-show="!item.filter"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value1: '',
|
||||
value2: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
customFilterMethod(searchValue) {
|
||||
const customFilterRef = this.$refs.customFilterRef
|
||||
|
||||
if (searchValue) {
|
||||
customFilterRef.state.cachedOptions.forEach((item) => {
|
||||
item.state.visible = item.label.includes(searchValue)
|
||||
})
|
||||
} else {
|
||||
customFilterRef.state.cachedOptions.forEach((item) => {
|
||||
item.state.visible = true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,42 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>场景1:过滤器模式(默认)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value"
|
||||
label="地区名称"
|
||||
shape="filter"
|
||||
:drop-style="{ width: '200px', 'min-width': '200px' }"
|
||||
>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:过滤器模式(透明)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value"
|
||||
label="地区名称"
|
||||
shape="filter"
|
||||
:drop-style="{ width: '200px', 'min-width': '200px' }"
|
||||
blank
|
||||
>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
const value = ref('')
|
||||
</script>
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>场景1:过滤器模式(默认)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value"
|
||||
label="地区名称"
|
||||
shape="filter"
|
||||
:drop-style="{ width: '200px', 'min-width': '200px' }"
|
||||
>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:过滤器模式(透明)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value"
|
||||
label="地区名称"
|
||||
shape="filter"
|
||||
:drop-style="{ width: '200px', 'min-width': '200px' }"
|
||||
blank
|
||||
>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,25 @@
|
|||
<template>
|
||||
<tiny-base-select v-model="value" :hide-drop="true">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
const value = ref('')
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,12 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('hidedrop', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#hide-drop')
|
||||
const wrap = page.locator('#hide-drop')
|
||||
const select = wrap.locator('.tiny-select')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
|
||||
await select.click()
|
||||
await expect(dropdown).toBeHidden()
|
||||
})
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<tiny-base-select v-model="value" :hide-drop="true">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>设置为下划线类型:</p>
|
||||
<p class="font-style">场景1:下划线默认</p>
|
||||
<tiny-base-select v-model="value1" input-box-type="underline" clearable>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p class="font-style">场景2:下划线禁用</p>
|
||||
<tiny-base-select v-model="value2" input-box-type="underline" disabled>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p class="font-style">场景3:下划线多选</p>
|
||||
<tiny-base-select v-model="value3" input-box-type="underline" multiple>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
const value1 = ref('')
|
||||
const value2 = ref('')
|
||||
const value3 = ref([])
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,72 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('下划线默认', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#input-box-type')
|
||||
const wrap = page.locator('#input-box-type')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
|
||||
await expect(select).toHaveClass(/tiny-select__underline/)
|
||||
await expect(input).toHaveCSS('border-top-width', '0px')
|
||||
await expect(input).toHaveCSS('border-left-width', '0px')
|
||||
await expect(input).toHaveCSS('border-right-width', '0px')
|
||||
await expect(input).toHaveCSS('border-color', 'rgb(173, 176, 184)')
|
||||
await expect(select.locator('svg')).toHaveCSS('fill', 'rgb(87, 93, 108)')
|
||||
|
||||
await select.click()
|
||||
await option.first().click()
|
||||
await expect(dropdown).toBeHidden()
|
||||
await expect(input).toHaveValue('北京')
|
||||
})
|
||||
|
||||
test('下划线禁用', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#input-box-type')
|
||||
const wrap = page.locator('#input-box-type')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
|
||||
await expect(select).toHaveClass(/tiny-select__underline/)
|
||||
await expect(input).toHaveCSS('border-top-width', '0px')
|
||||
await expect(input).toHaveCSS('border-left-width', '0px')
|
||||
await expect(input).toHaveCSS('border-right-width', '0px')
|
||||
await expect(input).toHaveCSS('border-color', 'rgb(223, 225, 230)')
|
||||
await expect(input).toHaveCSS('cursor', 'not-allowed')
|
||||
await expect(select.locator('svg')).toHaveCSS('fill', 'rgb(173, 176, 184)')
|
||||
const hasDisabled = await input.evaluate((input) => input.hasAttribute('disabled'))
|
||||
await expect(hasDisabled).toBe(true)
|
||||
|
||||
await select.click()
|
||||
await expect(dropdown).toBeHidden()
|
||||
await expect(input).toHaveValue('')
|
||||
})
|
||||
|
||||
test('下划线多选', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#input-box-type')
|
||||
const wrap = page.locator('#input-box-type')
|
||||
const select = wrap.locator('.tiny-select').nth(2)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const tag = wrap.locator('.tiny-tag')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
|
||||
await expect(select).toHaveClass(/tiny-select__underline/)
|
||||
await expect(input).toHaveCSS('border-top-width', '0px')
|
||||
await expect(input).toHaveCSS('border-left-width', '0px')
|
||||
await expect(input).toHaveCSS('border-right-width', '0px')
|
||||
await expect(input).toHaveCSS('border-color', 'rgb(173, 176, 184)')
|
||||
await expect(select.locator('.tiny-select__caret')).toHaveCSS('fill', 'rgb(87, 93, 108)')
|
||||
|
||||
await select.click()
|
||||
await expect(dropdown).toBeVisible()
|
||||
await option.first().click()
|
||||
await expect(tag).toHaveCount(5)
|
||||
|
||||
await expect(select).toHaveClass(/tiny-select__underline/)
|
||||
await expect(select).toHaveClass(/tiny-select__multiple/)
|
||||
})
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>设置为下划线类型</p>
|
||||
<p>场景1:下划线默认</p>
|
||||
<tiny-base-select v-model="value1" input-box-type="underline" clearable>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景2:下划线禁用</p>
|
||||
<tiny-base-select v-model="value2" input-box-type="underline" disabled>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景3:下划线多选</p>
|
||||
<tiny-base-select v-model="value3" input-box-type="underline" multiple>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value1: '',
|
||||
value2: '',
|
||||
value3: []
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,39 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:默认下拉弹框宽度由内容撑开:</p>
|
||||
<tiny-base-select v-model="value">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景2:下拉弹框宽度与输入框一致:</p>
|
||||
<tiny-base-select v-model="value" is-drop-inherit-width>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{
|
||||
value: '选项1',
|
||||
label: '北京北京北京北京北京北京北京北京北京北京北京北京北京北京北京北京北京'
|
||||
},
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
const value = ref('')
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,34 @@
|
|||
import { expect, test } from '@playwright/test'
|
||||
|
||||
test('默认下拉弹框宽度由内容撑开', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#is-drop-inherit-width')
|
||||
|
||||
const wrap = page.locator('#is-drop-inherit-width')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
|
||||
await select.click()
|
||||
const inputBox = await input.boundingBox()
|
||||
const listitemBox = await option.first().boundingBox()
|
||||
|
||||
const result = listitemBox.width > inputBox.width
|
||||
await expect(result).toBe(true)
|
||||
})
|
||||
|
||||
test('下拉弹框宽度与输入框一致', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#is-drop-inherit-width')
|
||||
const wrap = page.locator('#is-drop-inherit-width')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
|
||||
await select.click()
|
||||
const inputBox = await input.boundingBox()
|
||||
const dropdownBox = await dropdown.boundingBox()
|
||||
const result = dropdownBox.width - inputBox.width
|
||||
await expect(result < 1).toBe(true)
|
||||
})
|
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:默认下拉弹框宽度由内容撑开:</p>
|
||||
<tiny-base-select v-model="value">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景2:下拉弹框宽度与输入框一致:</p>
|
||||
<tiny-base-select v-model="value" is-drop-inherit-width>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{
|
||||
value: '选项1',
|
||||
label: '北京北京北京北京北京北京北京北京北京北京北京北京北京北京北京北京北京'
|
||||
},
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,88 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="demo1">
|
||||
<div>场景1:默认 focus() 后仅聚焦,不下拉</div>
|
||||
<br />
|
||||
<tiny-button @click="handleFocus1"> 点击获取焦点 </tiny-button>
|
||||
<tiny-button @click="handleBlur1"> 点击失去焦点 </tiny-button>
|
||||
<br />
|
||||
<tiny-base-select v-model="value" ref="drop1">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
<br />
|
||||
<div class="demo2">
|
||||
<div>场景2:配置 filterable,focus() 后聚焦并自动下拉</div>
|
||||
<br />
|
||||
<tiny-button @click="handleFocus2"> 点击获取焦点 </tiny-button>
|
||||
<tiny-button @click="handleBlur2"> 点击失去焦点 </tiny-button>
|
||||
<br />
|
||||
<tiny-base-select v-model="value" ref="drop2" filterable>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
<br />
|
||||
<div class="demo3">
|
||||
<div>场景2:配置 automaticDropdown,focus() 后聚焦并自动下拉</div>
|
||||
<br />
|
||||
<tiny-button @click="handleFocus3"> 点击获取焦点 </tiny-button>
|
||||
<tiny-button @click="handleBlur3"> 点击失去焦点 </tiny-button>
|
||||
<br />
|
||||
<tiny-base-select v-model="value" ref="drop3" automatic-dropdown>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption, Button as TinyButton } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
|
||||
const value = ref('')
|
||||
const drop1 = ref(null)
|
||||
const drop2 = ref(null)
|
||||
const drop3 = ref(null)
|
||||
|
||||
const handleFocus1 = () => {
|
||||
drop1.value.focus()
|
||||
}
|
||||
|
||||
const handleBlur1 = () => {
|
||||
drop1.value.blur()
|
||||
}
|
||||
|
||||
const handleFocus2 = () => {
|
||||
drop2.value.focus()
|
||||
}
|
||||
|
||||
const handleBlur2 = () => {
|
||||
drop2.value.blur()
|
||||
}
|
||||
|
||||
const handleFocus3 = () => {
|
||||
drop3.value.focus()
|
||||
}
|
||||
|
||||
const handleBlur3 = () => {
|
||||
drop3.value.blur()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
.tiny-button {
|
||||
max-width: unset;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,18 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('可搜索+手动聚焦失焦', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#manual-focus-blur')
|
||||
const wrap = page.locator('#manual-focus-blur')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const button = wrap.locator('.demo2 .tiny-button')
|
||||
|
||||
await page.waitForTimeout(2000)
|
||||
// 手动聚焦下拉
|
||||
await button.nth(0).click()
|
||||
await expect(dropdown).toBeVisible()
|
||||
|
||||
// 手动失焦收起
|
||||
await button.nth(1).click()
|
||||
await expect(dropdown).toBeHidden()
|
||||
})
|
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="demo1">
|
||||
<div>场景1:默认 focus() 后仅聚焦,不下拉</div>
|
||||
<br />
|
||||
<tiny-button @click="handleFocus1"> 点击获取焦点 </tiny-button>
|
||||
<tiny-button @click="handleBlur1"> 点击失去焦点 </tiny-button>
|
||||
<br />
|
||||
<tiny-base-select v-model="value" ref="drop1">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
<br />
|
||||
<div class="demo2">
|
||||
<div>场景2:配置 filterable,focus() 后聚焦并自动下拉</div>
|
||||
<br />
|
||||
<tiny-button @click="handleFocus2"> 点击获取焦点 </tiny-button>
|
||||
<tiny-button @click="handleBlur2"> 点击失去焦点 </tiny-button>
|
||||
<br />
|
||||
<tiny-base-select v-model="value" ref="drop2" filterable>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
<br />
|
||||
<div class="demo3">
|
||||
<div>场景2:配置 automaticDropdown,focus() 后聚焦并自动下拉</div>
|
||||
<br />
|
||||
<tiny-button @click="handleFocus3"> 点击获取焦点 </tiny-button>
|
||||
<tiny-button @click="handleBlur3"> 点击失去焦点 </tiny-button>
|
||||
<br />
|
||||
<tiny-base-select v-model="value" ref="drop3" automatic-dropdown>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option,
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleFocus1() {
|
||||
this.$refs.drop1.focus()
|
||||
},
|
||||
handleBlur1() {
|
||||
this.$refs.drop1.blur()
|
||||
},
|
||||
handleFocus2() {
|
||||
this.$refs.drop2.focus()
|
||||
},
|
||||
handleBlur2() {
|
||||
this.$refs.drop2.blur()
|
||||
},
|
||||
handleFocus3() {
|
||||
this.$refs.drop3.focus()
|
||||
},
|
||||
handleBlur3() {
|
||||
this.$refs.drop3.blur()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
.tiny-button {
|
||||
max-width: unset;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,59 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:配置式配置映射字段</p>
|
||||
<tiny-base-select v-model="value1" multiple :options="options" value-field="val" text-field="text">
|
||||
</tiny-base-select>
|
||||
<p>场景2:嵌套表格配置映射字段</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
multiple
|
||||
value-field="id"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOp"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect } from '@opentiny/vue'
|
||||
|
||||
const value1 = ref(['选项1', '选项2'])
|
||||
const value2 = ref(['001', '002'])
|
||||
const gridOp = ref({
|
||||
data: [
|
||||
{ id: '001', area: '华南区', province: '广东省', city: '广州市' },
|
||||
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
|
||||
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
|
||||
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
|
||||
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
|
||||
],
|
||||
columns: [
|
||||
{ type: 'selection', title: '' },
|
||||
{ field: 'area', title: '区域', width: 90 },
|
||||
{ field: 'province', title: '省份', width: 60 },
|
||||
{ field: 'city', title: '城市', width: 60 }
|
||||
]
|
||||
})
|
||||
|
||||
const options = ref([
|
||||
{ val: '选项1', text: '北京' },
|
||||
{ val: '选项2', text: '上海' },
|
||||
{ val: '选项3', text: '天津' },
|
||||
{ val: '选项4', text: '重庆' },
|
||||
{ val: '选项5', text: '深圳' },
|
||||
{ val: '选项6', text: '南京' },
|
||||
{ val: '选项7', text: '成都' }
|
||||
])
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,60 @@
|
|||
import { expect, test } from '@playwright/test'
|
||||
|
||||
test('配置式配置映射字段', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#map-field')
|
||||
const wrap = page.locator('#map-field')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
const suffix = select.locator('.tiny-input__suffix')
|
||||
const tag = select.locator('.tiny-tag')
|
||||
|
||||
await expect(tag).toHaveCount(2)
|
||||
await expect(tag.first()).toHaveText('北京')
|
||||
await expect(tag.nth(1)).toHaveText('上海')
|
||||
await suffix.click()
|
||||
await page.waitForTimeout(500)
|
||||
await expect(dropdown).toBeVisible()
|
||||
await expect(option.filter({ hasText: '北京' })).toHaveClass(/selected/)
|
||||
await expect(option.filter({ hasText: '上海' })).toHaveClass(/selected/)
|
||||
})
|
||||
|
||||
test('嵌套表格配置映射字段', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#map-field')
|
||||
const wrap = page.locator('#map-field')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const suffix = select.locator('.tiny-input__suffix')
|
||||
const tag = select.locator('.tiny-tag')
|
||||
|
||||
await expect(tag).toHaveCount(2)
|
||||
await suffix.click()
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
const tr = dropdown.locator('.tiny-grid__body-wrapper .tiny-grid-body__row')
|
||||
const currentTr = dropdown.locator('.tiny-grid__body-wrapper .row__selected')
|
||||
|
||||
await expect(tr).toHaveCount(5)
|
||||
await expect(currentTr).toHaveCount(2)
|
||||
await dropdown.getByRole('row', { name: '华南区 广东省 珠海市' }).getByRole('cell').first().click()
|
||||
await expect(tag).toHaveCount(3)
|
||||
await expect(currentTr).toHaveCount(3)
|
||||
await dropdown.getByRole('row', { name: '华南区 广东省 珠海市' }).getByRole('cell').first().click()
|
||||
await expect(tag).toHaveCount(2)
|
||||
await expect(currentTr).toHaveCount(2)
|
||||
await dropdown.getByRole('row', { name: '区域 省份 城市' }).getByRole('cell').first().click()
|
||||
await expect(tag).toHaveCount(5)
|
||||
await expect(currentTr).toHaveCount(5)
|
||||
let all = await dropdown
|
||||
.getByRole('row', { name: '区域 省份 城市' })
|
||||
.locator('.tiny-grid-checkbox__icon .tiny-svg')
|
||||
.nth(1)
|
||||
await expect(all).toHaveClass(/icon-checked-sur/)
|
||||
await dropdown.getByRole('row', { name: '区域 省份 城市' }).getByRole('cell').first().click()
|
||||
await page.waitForTimeout(500)
|
||||
await expect(all).toBeHidden()
|
||||
await expect(tag).toHaveCount(0)
|
||||
await expect(currentTr).toHaveCount(0)
|
||||
})
|
|
@ -0,0 +1,66 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:配置式配置映射字段</p>
|
||||
<tiny-base-select v-model="value1" multiple :options="options" value-field="val" text-field="text">
|
||||
</tiny-base-select>
|
||||
<p>场景2:嵌套表格配置映射字段</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
multiple
|
||||
value-field="id"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOp"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value1: ['选项1', '选项2'],
|
||||
value2: ['001', '002'],
|
||||
gridOp: {
|
||||
data: [
|
||||
{ id: '001', area: '华南区', province: '广东省', city: '广州市' },
|
||||
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
|
||||
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
|
||||
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
|
||||
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
|
||||
],
|
||||
columns: [
|
||||
{ type: 'selection', title: '' },
|
||||
{ field: 'area', title: '区域', width: 90 },
|
||||
{ field: 'province', title: '省份', width: 60 },
|
||||
{ field: 'city', title: '城市', width: 60 }
|
||||
]
|
||||
},
|
||||
options: [
|
||||
{ val: '选项1', text: '北京' },
|
||||
{ val: '选项2', text: '上海' },
|
||||
{ val: '选项3', text: '天津' },
|
||||
{ val: '选项4', text: '重庆' },
|
||||
{ val: '选项5', text: '深圳' },
|
||||
{ val: '选项6', text: '南京' },
|
||||
{ val: '选项7', text: '成都' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<div>
|
||||
<tiny-base-select v-model="value">
|
||||
<tiny-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
@click.native="clickItem(item.value)"
|
||||
:highlight-class="item._highlightClass"
|
||||
></tiny-option>
|
||||
</tiny-base-select>
|
||||
<p class="cache-value">
|
||||
{{ cacheValue }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
import Memorize from '@opentiny/vue-renderless/common/deps/memorize'
|
||||
|
||||
const MemorizeInstance = new Memorize({ key: 'test456' })
|
||||
|
||||
const options = MemorizeInstance.assemble([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
|
||||
const value = ref('选项3')
|
||||
const cacheValue = ref([])
|
||||
|
||||
const clickItem = (value) => {
|
||||
MemorizeInstance.updateByKey(value)
|
||||
cacheValue.value = window.localStorage.getItem('tiny_memorize_test456')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,19 @@
|
|||
import { expect, test } from '@playwright/test'
|
||||
|
||||
test('手动缓存', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#memoize-usage')
|
||||
const wrap = page.locator('#memoize-usage')
|
||||
const select = wrap.locator('.tiny-select')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
const cacheValue = wrap.locator('.cache-value')
|
||||
|
||||
await select.click()
|
||||
await option.filter({ hasText: '北京' }).click()
|
||||
await expect(cacheValue).toContainText(['选项1'])
|
||||
|
||||
await select.click()
|
||||
await option.filter({ hasText: '上海' }).click()
|
||||
await expect(cacheValue).toContainText(['选项2'])
|
||||
})
|
|
@ -0,0 +1,65 @@
|
|||
<template>
|
||||
<div>
|
||||
<tiny-base-select v-model="value">
|
||||
<tiny-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
@click.native="clickItem(item.value)"
|
||||
:highlight-class="item._highlightClass"
|
||||
></tiny-option>
|
||||
</tiny-base-select>
|
||||
<p class="cache-value">
|
||||
{{ cacheValue }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
import Memorize from '@opentiny/vue-renderless/common/deps/memorize'
|
||||
|
||||
const MemorizeInstance = new Memorize({ key: 'test456' })
|
||||
|
||||
const options = MemorizeInstance.assemble([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options,
|
||||
value: '选项3',
|
||||
cacheValue: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickItem(value) {
|
||||
MemorizeInstance.updateByKey(value)
|
||||
this.cacheValue = window.localStorage.getItem('tiny_memorize_test456')
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
window.localStorage.setItem('tiny_memorize_test456', '')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,91 @@
|
|||
<template>
|
||||
<div>
|
||||
<br />
|
||||
<div>场景1:多选</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value1" multiple>
|
||||
<tiny-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:必选</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value2" multiple>
|
||||
<tiny-option
|
||||
v-for="item in options2"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:required="item.required"
|
||||
>
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<div>场景3:配置式必选</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value3" multiple :options="options2"> </tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<div>场景4:多选个数限制</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value4" multiple :multiple-limit="2" show-limit-text>
|
||||
<tiny-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<div>场景5:自定义图标 + 自定义样式</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value4"
|
||||
multiple
|
||||
:dropdown-icon="tinyIconPopup"
|
||||
:drop-style="{ width: '200px', 'min-width': '200px' }"
|
||||
>
|
||||
<tiny-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
import { iconPopup } from '@opentiny/vue-icon'
|
||||
|
||||
const options1 = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' },
|
||||
{ value: '选项6', label: '南京' },
|
||||
{ value: '选项7', label: '成都' }
|
||||
])
|
||||
|
||||
const options2 = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳', required: true },
|
||||
{ value: '选项6', label: '南京' },
|
||||
{ value: '选项7', label: '成都' }
|
||||
])
|
||||
|
||||
const value1 = ref(['选项1', '选项2'])
|
||||
const value2 = ref(['选项1', '选项2'])
|
||||
const value3 = ref([])
|
||||
const value4 = ref([])
|
||||
const tinyIconPopup = iconPopup()
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,147 @@
|
|||
<template>
|
||||
<div class="demo-box">
|
||||
<tiny-button @click="displayOnly = !displayOnly">display-only/{{ displayOnly }}</tiny-button>
|
||||
<p>边框为表单范围</p>
|
||||
<tiny-form class="custom-form" :inline="inline" label-position="top" :display-only="displayOnly">
|
||||
<tiny-form-item label="label 垂直布局">
|
||||
<div>
|
||||
<tiny-base-select v-model="formData.select1" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<tiny-base-select v-model="formData.select1" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</tiny-form-item>
|
||||
<p> </p>
|
||||
</tiny-form>
|
||||
<br />
|
||||
<br />
|
||||
<tiny-form class="custom-form" :inline="inline" :display-only="displayOnly">
|
||||
<tiny-form-item label="form 超出隐藏">
|
||||
<tiny-base-select v-model="formData.select1" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</tiny-form-item>
|
||||
</tiny-form>
|
||||
<br />
|
||||
<tiny-form class="custom-form visible-form" :inline="inline" :display-only="displayOnly">
|
||||
<tiny-form-item label="自定义-超出显示">
|
||||
<tiny-base-select v-model="formData.select1" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</tiny-form-item>
|
||||
</tiny-form>
|
||||
<br />
|
||||
<tiny-form class="custom-form" :inline="inline" :display-only="displayOnly">
|
||||
<tiny-form-item label="默认尺寸">
|
||||
<tiny-base-select v-model="formData.select1" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</tiny-form-item>
|
||||
<p> </p>
|
||||
</tiny-form>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<tiny-form class="custom-form" size="mini" :inline="inline" :display-only="displayOnly">
|
||||
<tiny-form-item label="mini" size="mini">
|
||||
<tiny-base-select v-model="formData.select1" size="mini" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</tiny-form-item>
|
||||
<p> </p>
|
||||
</tiny-form>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<tiny-form class="custom-form" size="small" :inline="inline" :display-only="displayOnly">
|
||||
<tiny-form-item label="small" size="small">
|
||||
<tiny-base-select v-model="formData.select1" size="small" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</tiny-form-item>
|
||||
<p> </p>
|
||||
</tiny-form>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<tiny-form class="custom-form" size="medium" :inline="inline" :display-only="displayOnly">
|
||||
<tiny-form-item label="medium" size="medium">
|
||||
<tiny-base-select v-model="formData.select1" size="medium" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</tiny-form-item>
|
||||
<p> </p>
|
||||
</tiny-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import {
|
||||
BaseSelect as TinyBaseSelect,
|
||||
Option as TinyOption,
|
||||
Form as TinyForm,
|
||||
FormItem as TinyFormItem,
|
||||
Button as TinyButton
|
||||
} from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{
|
||||
value: '选项1',
|
||||
label: '北京'
|
||||
},
|
||||
{
|
||||
value: '选项2',
|
||||
label: '上海'
|
||||
},
|
||||
{
|
||||
value: '选项3',
|
||||
label: '天津'
|
||||
},
|
||||
{
|
||||
value: '选项4',
|
||||
label: '重庆'
|
||||
},
|
||||
{
|
||||
value: '选项5',
|
||||
label: '深圳'
|
||||
},
|
||||
{
|
||||
value: '选项6',
|
||||
label: '杭州'
|
||||
},
|
||||
{
|
||||
value: '选项7',
|
||||
label: '宇宙无敌老面小馒头'
|
||||
}
|
||||
])
|
||||
|
||||
const displayOnly = ref(true)
|
||||
const top = ref(false)
|
||||
const inline = ref(false)
|
||||
const size = ref('')
|
||||
const formData = reactive({
|
||||
select1: ['选项1', '选项2', '选项3', '选项4', '选项5', '选项6', '选项7']
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.demo-box {
|
||||
width: 350px;
|
||||
|
||||
.custom-form {
|
||||
border: 1px solid #fdf4f4;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.visible-form {
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,152 @@
|
|||
<template>
|
||||
<div class="demo-box">
|
||||
<tiny-button @click="displayOnly = !displayOnly">display-only/{{ displayOnly }}</tiny-button>
|
||||
<p>边框为表单范围</p>
|
||||
<tiny-form class="custom-form" :inline="inline" label-position="top" :display-only="displayOnly">
|
||||
<tiny-form-item label="label 垂直布局">
|
||||
<div>
|
||||
<tiny-base-select v-model="formData.select1" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<tiny-base-select v-model="formData.select1" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</tiny-form-item>
|
||||
<p> </p>
|
||||
</tiny-form>
|
||||
<br />
|
||||
<br />
|
||||
<tiny-form class="custom-form" :inline="inline" :display-only="displayOnly">
|
||||
<tiny-form-item label="form 超出隐藏">
|
||||
<tiny-base-select v-model="formData.select1" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</tiny-form-item>
|
||||
</tiny-form>
|
||||
<br />
|
||||
<tiny-form class="custom-form visible-form" :inline="inline" :display-only="displayOnly">
|
||||
<tiny-form-item label="自定义-超出显示">
|
||||
<tiny-base-select v-model="formData.select1" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</tiny-form-item>
|
||||
</tiny-form>
|
||||
<br />
|
||||
<tiny-form class="custom-form" :inline="inline" :display-only="displayOnly">
|
||||
<tiny-form-item label="默认尺寸">
|
||||
<tiny-base-select v-model="formData.select1" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</tiny-form-item>
|
||||
<p> </p>
|
||||
</tiny-form>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<tiny-form class="custom-form" size="mini" :inline="inline" :display-only="displayOnly">
|
||||
<tiny-form-item label="mini" size="mini">
|
||||
<tiny-base-select v-model="formData.select1" size="mini" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</tiny-form-item>
|
||||
<p> </p>
|
||||
</tiny-form>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<tiny-form class="custom-form" size="small" :inline="inline" :display-only="displayOnly">
|
||||
<tiny-form-item label="small" size="small">
|
||||
<tiny-base-select v-model="formData.select1" size="small" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</tiny-form-item>
|
||||
<p> </p>
|
||||
</tiny-form>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<tiny-form class="custom-form" size="medium" :inline="inline" :display-only="displayOnly">
|
||||
<tiny-form-item label="medium" size="medium">
|
||||
<tiny-base-select v-model="formData.select1" size="medium" multiple hover-expand>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</tiny-form-item>
|
||||
<p> </p>
|
||||
</tiny-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Form, FormItem, Option, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyForm: Form,
|
||||
TinyButton: Button,
|
||||
TinyFormItem: FormItem,
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
displayOnly: true,
|
||||
top: false,
|
||||
inline: false,
|
||||
size: '',
|
||||
options: [
|
||||
{
|
||||
value: '选项1',
|
||||
label: '北京'
|
||||
},
|
||||
{
|
||||
value: '选项2',
|
||||
label: '上海'
|
||||
},
|
||||
{
|
||||
value: '选项3',
|
||||
label: '天津'
|
||||
},
|
||||
{
|
||||
value: '选项4',
|
||||
label: '重庆'
|
||||
},
|
||||
{
|
||||
value: '选项5',
|
||||
label: '深圳'
|
||||
},
|
||||
{
|
||||
value: '选项6',
|
||||
label: '杭州'
|
||||
},
|
||||
{
|
||||
value: '选项7',
|
||||
label: '宇宙无敌老面小馒头'
|
||||
}
|
||||
],
|
||||
formData: {
|
||||
select1: ['选项1', '选项2', '选项3', '选项4', '选项5', '选项6', '选项7']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.demo-box {
|
||||
width: 350px;
|
||||
|
||||
.custom-form {
|
||||
border: 1px solid #fdf4f4;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.visible-form {
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,49 @@
|
|||
import { expect, test } from '@playwright/test'
|
||||
|
||||
test('多选时取远端数据与当前已选数据的并集', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#multiple')
|
||||
const wrap = page.locator('#multiple')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
const tag = select.locator('.tiny-tag')
|
||||
|
||||
await expect(tag).toHaveCount(2)
|
||||
await select.locator('.tiny-input__suffix').click()
|
||||
await option.filter({ hasText: '全部' }).click()
|
||||
await expect(tag).toHaveCount(7)
|
||||
await option.filter({ hasText: '全部' }).click()
|
||||
await expect(tag).toHaveCount(0)
|
||||
await option.filter({ hasText: '北京' }).click()
|
||||
await expect(tag).toHaveCount(1)
|
||||
await option.filter({ hasText: '上海' }).click()
|
||||
await expect(tag).toHaveCount(2)
|
||||
await tag.filter({ hasText: '上海' }).locator('.tiny-tag__close').click()
|
||||
await expect(tag).toHaveCount(1)
|
||||
})
|
||||
|
||||
test('multiple-limit', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#multiple')
|
||||
const wrap = page.locator('#multiple')
|
||||
const select = wrap.locator('.tiny-select').nth(3)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
const tag = select.locator('.tiny-tag')
|
||||
|
||||
await select.click()
|
||||
await option.nth(0).click()
|
||||
await option.nth(1).click()
|
||||
await expect(tag).toHaveCount(2)
|
||||
await expect(option.filter({ hasText: '全部' })).toHaveCount(0)
|
||||
|
||||
const list = await option.all()
|
||||
list.forEach(async (item, index) => {
|
||||
if (index <= 1) {
|
||||
await expect(item).toHaveClass(/selected/)
|
||||
} else {
|
||||
await expect(item).toHaveClass(/is-disabled/)
|
||||
}
|
||||
})
|
||||
})
|
|
@ -0,0 +1,98 @@
|
|||
<template>
|
||||
<div>
|
||||
<br />
|
||||
<div>场景1:多选</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value1" multiple searchable>
|
||||
<tiny-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:必选</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value2" multiple>
|
||||
<tiny-option
|
||||
v-for="item in options2"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:required="item.required"
|
||||
>
|
||||
</tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<div>场景3:配置式必选</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value3" multiple :options="options2"> </tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<div>场景4:多选个数限制</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value4" multiple :multiple-limit="2" show-limit-text>
|
||||
<tiny-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<div>场景5:自定义图标 + 自定义样式</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value4"
|
||||
multiple
|
||||
:dropdown-icon="iconPopup"
|
||||
:drop-style="{ width: '200px', 'min-width': '200px' }"
|
||||
>
|
||||
<tiny-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
import { iconPopup } from '@opentiny/vue-icon'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options1: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' },
|
||||
{ value: '选项6', label: '南京' },
|
||||
{ value: '选项7', label: '成都' }
|
||||
],
|
||||
options2: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳', required: true },
|
||||
{ value: '选项6', label: '南京' },
|
||||
{ value: '选项7', label: '成都' }
|
||||
],
|
||||
value1: ['选项1', '选项2'],
|
||||
value2: ['选项1', '选项2'],
|
||||
value3: ['选项1', '选项2'],
|
||||
value4: [],
|
||||
iconPopup: iconPopup()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,25 @@
|
|||
<template>
|
||||
<tiny-base-select v-model="value" placeholder="自定义 placeholder" name="inputName" autocomplete>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options = ref([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
const value = ref('')
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,16 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('原生属性', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#native-properties')
|
||||
|
||||
const wrap = page.locator('#native-properties')
|
||||
const select = wrap.locator('.tiny-select')
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
|
||||
await expect(input).toHaveAttribute('name', 'inputName')
|
||||
await expect(input).toHaveAttribute('placeholder', '自定义 placeholder')
|
||||
|
||||
const isHasAutocomplete = await input.evaluate((input) => input.hasAttribute('autocomplete'))
|
||||
await expect(isHasAutocomplete).toBe(true)
|
||||
})
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<tiny-base-select v-model="value" placeholder="自定义 placeholder" name="inputName" autocomplete>
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
],
|
||||
value: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,94 @@
|
|||
<template>
|
||||
<div class="demo-select">
|
||||
<p>场景1:嵌套表格(单选)</p>
|
||||
<tiny-base-select
|
||||
v-model="value1"
|
||||
value-field="id"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpSingle"
|
||||
></tiny-base-select>
|
||||
<p>场景2:嵌套表格(多选)</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
multiple
|
||||
value-field="id"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpMulti"
|
||||
></tiny-base-select>
|
||||
<p>场景3:嵌套表格 + 可搜索 + 可清除</p>
|
||||
<tiny-base-select
|
||||
ref="select"
|
||||
v-model="value3"
|
||||
filterable
|
||||
:filter-method="filter"
|
||||
clearable
|
||||
value-field="id"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpSingle"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect } from '@opentiny/vue'
|
||||
|
||||
const value1 = ref('')
|
||||
const value2 = ref([])
|
||||
const value3 = ref('')
|
||||
|
||||
const gridOpSingle = reactive({
|
||||
data: [
|
||||
{ id: '001', area: '华南区', province: '广东省', city: '深圳1' },
|
||||
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
|
||||
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
|
||||
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
|
||||
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
|
||||
],
|
||||
columns: [
|
||||
{ type: 'radio', title: '' },
|
||||
{ field: 'area', title: '区域', width: 90 },
|
||||
{ field: 'province', title: '省份', width: 60 },
|
||||
{ field: 'city', title: '城市', width: 60 }
|
||||
]
|
||||
})
|
||||
|
||||
const gridOpMulti = reactive({
|
||||
data: [
|
||||
{ id: '001', area: '华南区', province: '广东省', city: '深圳1' },
|
||||
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
|
||||
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
|
||||
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
|
||||
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
|
||||
],
|
||||
columns: [
|
||||
{ type: 'selection', title: '' },
|
||||
{ field: 'area', title: '区域', width: 90 },
|
||||
{ field: 'province', title: '省份', width: 60 },
|
||||
{ field: 'city', title: '城市', width: 60 }
|
||||
]
|
||||
})
|
||||
|
||||
const filter = (value) => {
|
||||
if (!value) {
|
||||
return gridOpSingle.data
|
||||
}
|
||||
|
||||
return gridOpSingle.data.filter((item) => {
|
||||
return item.city.includes(value)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,85 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:嵌套表格禁用某项(单选)</p>
|
||||
<tiny-base-select
|
||||
v-model="value1"
|
||||
value-field="id"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpRadio"
|
||||
:radio-config="radioConfig"
|
||||
></tiny-base-select>
|
||||
<p>场景2:嵌套表格禁用某项(多选)</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
value-field="id"
|
||||
multiple
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOp"
|
||||
:select-config="selectConfig"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect } from '@opentiny/vue'
|
||||
|
||||
const selectConfig = ref({
|
||||
checkMethod({ rowIndex }) {
|
||||
return rowIndex % 2 === 0
|
||||
}
|
||||
})
|
||||
|
||||
const radioConfig = ref({
|
||||
checkMethod({ rowIndex }) {
|
||||
return rowIndex % 2 === 1
|
||||
}
|
||||
})
|
||||
|
||||
const value1 = ref('')
|
||||
const value2 = ref([])
|
||||
|
||||
const gridOpRadio = ref({
|
||||
data: [
|
||||
{ id: '001', area: '华南区', province: '广东省', city: '广州市' },
|
||||
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
|
||||
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
|
||||
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
|
||||
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
|
||||
],
|
||||
columns: [
|
||||
{ type: 'radio', title: '' },
|
||||
{ field: 'area', title: '区域', width: 100 },
|
||||
{ field: 'province', title: '省份', width: 50 },
|
||||
{ field: 'city', title: '城市' }
|
||||
]
|
||||
})
|
||||
|
||||
const gridOp = ref({
|
||||
data: [
|
||||
{ id: '001', area: '华南区', province: '广东省', city: '广州市' },
|
||||
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
|
||||
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
|
||||
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
|
||||
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
|
||||
],
|
||||
columns: [
|
||||
{ type: 'selection', title: '' },
|
||||
{ field: 'area', title: '区域', width: 100 },
|
||||
{ field: 'province', title: '省份', width: 50 },
|
||||
{ field: 'city', title: '城市' }
|
||||
]
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,41 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('嵌套表格禁用某项(单选)', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#nest-grid-disable')
|
||||
const wrap = page.locator('#nest-grid-disable')
|
||||
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
|
||||
await select.click()
|
||||
await expect(dropdown.locator('.tiny-grid-radio.is__disabled')).toHaveCount(3)
|
||||
await expect(input).toHaveValue('')
|
||||
|
||||
await dropdown.getByRole('row').nth(1).getByRole('cell').first().click()
|
||||
await expect(input).toHaveValue('')
|
||||
|
||||
await dropdown.getByRole('row').nth(2).getByRole('cell').first().click()
|
||||
await expect(input).toHaveValue('深圳市')
|
||||
})
|
||||
|
||||
test('嵌套表格禁用某项(多选)', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#nest-grid-disable')
|
||||
|
||||
const wrap = page.locator('#nest-grid-disable')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const tag = select.locator('.tiny-tag')
|
||||
|
||||
await select.click()
|
||||
await dropdown.getByRole('row').nth(2).getByRole('cell').first().click()
|
||||
await expect(tag).toHaveCount(0)
|
||||
|
||||
await dropdown.getByRole('row').nth(1).getByRole('cell').first().click()
|
||||
await expect(tag).toHaveCount(1)
|
||||
|
||||
await dropdown.getByRole('row').nth(4).getByRole('cell').first().click()
|
||||
await expect(tag).toHaveCount(1)
|
||||
})
|
|
@ -0,0 +1,122 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>场景1:嵌套表格禁用某项(单选)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value1"
|
||||
value-field="id"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpRadio"
|
||||
:radio-config="radioConfig"
|
||||
></tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:嵌套表格禁用某项(多选)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
value-field="id"
|
||||
multiple
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOp"
|
||||
:select-config="selectConfig"
|
||||
></tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景3:嵌套表格行选中(单选)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value3"
|
||||
value-field="id"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpRadio"
|
||||
:radio-config="{ trigger: 'row' }"
|
||||
placeholder="请选择"
|
||||
></tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景4:嵌套表格行选中(多选)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="value4"
|
||||
value-field="id"
|
||||
multiple
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOp"
|
||||
:select-config="{ trigger: 'row' }"
|
||||
placeholder="请选择"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectConfig: {
|
||||
checkMethod({ rowIndex }) {
|
||||
return rowIndex % 2 === 0
|
||||
}
|
||||
},
|
||||
radioConfig: {
|
||||
checkMethod({ rowIndex }) {
|
||||
return rowIndex % 2 === 1
|
||||
}
|
||||
},
|
||||
value1: '',
|
||||
value2: [],
|
||||
value3: '',
|
||||
value4: [],
|
||||
gridOpRadio: {
|
||||
data: [
|
||||
{ id: '001', area: '华南区', province: '广东省', city: '广州市' },
|
||||
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
|
||||
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
|
||||
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
|
||||
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
|
||||
],
|
||||
columns: [
|
||||
{ type: 'radio', title: '' },
|
||||
{ field: 'area', title: '区域', width: 100 },
|
||||
{ field: 'province', title: '省份', width: 50 },
|
||||
{ field: 'city', title: '城市' }
|
||||
]
|
||||
},
|
||||
gridOp: {
|
||||
data: [
|
||||
{ id: '001', area: '华南区', province: '广东省', city: '广州市' },
|
||||
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
|
||||
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
|
||||
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
|
||||
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
|
||||
],
|
||||
columns: [
|
||||
{ type: 'selection', title: '' },
|
||||
{ field: 'area', title: '区域', width: 100 },
|
||||
{ field: 'province', title: '省份', width: 50 },
|
||||
{ field: 'city', title: '城市' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,122 @@
|
|||
<template>
|
||||
<div class="demo-select">
|
||||
<div>场景1:下拉表格远程搜索初始化查询(单选)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
ref="select"
|
||||
v-model="radioValue1"
|
||||
placeholder="请输入关键词"
|
||||
clearable
|
||||
:init-query="initQuery"
|
||||
:remote-method="remoteMethod"
|
||||
:remote-config="{ autoSearch: true, clearData: true, showIcon: true }"
|
||||
remote
|
||||
filterable
|
||||
value-field="id"
|
||||
:multiple="false"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpRadio"
|
||||
></tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:下拉表格远程搜索初始化查询(多选)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
ref="select"
|
||||
v-model="radioValue2"
|
||||
placeholder="请输入关键词"
|
||||
clearable
|
||||
:init-query="initQuery"
|
||||
:remote-method="remoteMethod"
|
||||
:remote-config="{ autoSearch: true, clearData: true, showIcon: true }"
|
||||
remote
|
||||
filterable
|
||||
value-field="id"
|
||||
:multiple="true"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpRadio2"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect } from '@opentiny/vue'
|
||||
|
||||
const allData = ref([])
|
||||
const radioValue1 = ref('001')
|
||||
const radioValue2 = ref(['001', '002'])
|
||||
|
||||
const gridOpRadio = reactive({
|
||||
data: [],
|
||||
height: 300,
|
||||
optimization: {
|
||||
animat: true,
|
||||
delayHover: 250,
|
||||
scrollX: { gt: 20 },
|
||||
scrollY: { gt: 20 }
|
||||
},
|
||||
columns: [
|
||||
{ type: 'radio', title: '' },
|
||||
{ field: 'area', title: '区域' },
|
||||
{ field: 'province', title: '省份' },
|
||||
{ field: 'city', title: '城市' }
|
||||
]
|
||||
})
|
||||
|
||||
const gridOpRadio2 = reactive({
|
||||
data: [],
|
||||
height: 300,
|
||||
optimization: {
|
||||
animat: true,
|
||||
delayHover: 250,
|
||||
scrollX: { gt: 20 },
|
||||
scrollY: { gt: 20 }
|
||||
},
|
||||
columns: [
|
||||
{ type: 'selection', title: '' },
|
||||
{ field: 'area', title: '区域' },
|
||||
{ field: 'province', title: '省份' },
|
||||
{ field: 'city', title: '城市' }
|
||||
]
|
||||
})
|
||||
|
||||
allData.value = Array.from({ length: 10000 }, (item, index) => {
|
||||
return {
|
||||
id: '00' + index,
|
||||
area: '华南区' + index,
|
||||
province: '广东省' + index,
|
||||
city: '广州市' + index
|
||||
}
|
||||
})
|
||||
|
||||
const initQuery = (value) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(allData.value)
|
||||
}, 500)
|
||||
})
|
||||
}
|
||||
|
||||
const remoteMethod = (value) => {
|
||||
const filterData = allData.value.filter((item) => {
|
||||
return item.city.includes(value)
|
||||
})
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(filterData)
|
||||
}, 500)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.demo-select {
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,129 @@
|
|||
<template>
|
||||
<div class="demo-select">
|
||||
<div>场景1:下拉表格远程搜索初始化查询(单选)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
ref="select"
|
||||
v-model="radioValue1"
|
||||
placeholder="请输入关键词"
|
||||
clearable
|
||||
:init-query="initQuery"
|
||||
:remote-method="remoteMethod"
|
||||
:remote-config="{ autoSearch: true, clearData: true, showIcon: true }"
|
||||
remote
|
||||
filterable
|
||||
value-field="id"
|
||||
:multiple="false"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpRadio"
|
||||
></tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:下拉表格远程搜索初始化查询(多选)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
ref="select"
|
||||
v-model="radioValue2"
|
||||
placeholder="请输入关键词"
|
||||
clearable
|
||||
:init-query="initQuery"
|
||||
:remote-method="remoteMethod"
|
||||
:remote-config="{ autoSearch: true, clearData: true, showIcon: true }"
|
||||
remote
|
||||
filterable
|
||||
value-field="id"
|
||||
:multiple="true"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpRadio2"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect
|
||||
},
|
||||
created() {
|
||||
this.allData = Array.from({ length: 10000 }, (item, index) => {
|
||||
return {
|
||||
id: '00' + index,
|
||||
area: '华南区' + index,
|
||||
province: '广东省' + index,
|
||||
city: '广州市' + index
|
||||
}
|
||||
})
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
allData: [],
|
||||
radioValue1: '001',
|
||||
radioValue2: ['001', '002'],
|
||||
gridOpRadio: {
|
||||
data: [],
|
||||
height: 300,
|
||||
optimization: {
|
||||
animat: true,
|
||||
delayHover: 250,
|
||||
scrollX: { gt: 20 },
|
||||
scrollY: { gt: 20 }
|
||||
},
|
||||
columns: [
|
||||
{ type: 'radio', title: '' },
|
||||
{ field: 'area', title: '区域' },
|
||||
{ field: 'province', title: '省份' },
|
||||
{ field: 'city', title: '城市' }
|
||||
]
|
||||
},
|
||||
gridOpRadio2: {
|
||||
data: [],
|
||||
height: 300,
|
||||
optimization: {
|
||||
animat: true,
|
||||
delayHover: 250,
|
||||
scrollX: { gt: 20 },
|
||||
scrollY: { gt: 20 }
|
||||
},
|
||||
columns: [
|
||||
{ type: 'selection', title: '' },
|
||||
{ field: 'area', title: '区域' },
|
||||
{ field: 'province', title: '省份' },
|
||||
{ field: 'city', title: '城市' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initQuery(value) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(this.allData)
|
||||
}, 500)
|
||||
})
|
||||
},
|
||||
remoteMethod(value) {
|
||||
let filterData = this.allData.filter((item) => {
|
||||
return item.city.includes(value)
|
||||
})
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(filterData)
|
||||
}, 500)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.demo-select {
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,120 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:单选,下拉表格远程搜索基础用法</p>
|
||||
<tiny-base-select
|
||||
v-model="value1"
|
||||
placeholder="请输入关键词"
|
||||
render-type="grid"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="remoteMethod"
|
||||
:grid-op="gridOpRadio"
|
||||
></tiny-base-select>
|
||||
|
||||
<p>场景2:单选,下拉表格远程搜索 + 自动搜索 + 显示按钮</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
placeholder="请输入关键词"
|
||||
render-type="grid"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="remoteMethod"
|
||||
:grid-op="gridOpRadio"
|
||||
:remote-config="{ autoSearch: true, clearData: true, showIcon: true }"
|
||||
></tiny-base-select>
|
||||
|
||||
<p>场景3:多选,下拉表格远程搜索基础用法</p>
|
||||
<tiny-base-select
|
||||
v-model="value3"
|
||||
placeholder="请输入关键词"
|
||||
multiple
|
||||
render-type="grid"
|
||||
reserve-keyword
|
||||
filterable
|
||||
remote
|
||||
:remote-method="remoteMethod"
|
||||
:grid-op="gridOpMultiple"
|
||||
></tiny-base-select>
|
||||
|
||||
<p>场景4:多选,下拉表格远程搜索 + 自动搜索 + 显示按钮</p>
|
||||
<tiny-base-select
|
||||
v-model="value4"
|
||||
placeholder="请输入关键词"
|
||||
multiple
|
||||
reserve-keyword
|
||||
filterable
|
||||
remote
|
||||
render-type="grid"
|
||||
:remote-method="remoteMethod"
|
||||
:grid-op="gridOpMultiple"
|
||||
:remote-config="{ autoSearch: true, clearData: true, showIcon: true }"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect } from '@opentiny/vue'
|
||||
|
||||
const allData = Array.from({ length: 1000 }, (a, i) => {
|
||||
return {
|
||||
value: '00' + i,
|
||||
province: '省份' + i,
|
||||
city: '城市' + i,
|
||||
area: '区域' + i,
|
||||
label: `省${i}-市${i}`
|
||||
}
|
||||
})
|
||||
const baseGridOp = {
|
||||
data: [],
|
||||
height: 300,
|
||||
optimization: {
|
||||
animat: true,
|
||||
delayHover: 250,
|
||||
scrollX: { gt: 20 },
|
||||
scrollY: { gt: 20 }
|
||||
}
|
||||
}
|
||||
const baseCols = [
|
||||
{ field: 'province', title: '省份' },
|
||||
{ field: 'city', title: '城市' },
|
||||
{ field: 'area', title: '区域' }
|
||||
]
|
||||
|
||||
const value1 = ref('')
|
||||
const value2 = ref('')
|
||||
const value3 = ref([])
|
||||
const value4 = ref([])
|
||||
const gridOpRadio = {
|
||||
...baseGridOp,
|
||||
columns: [{ type: 'radio', title: '' }, ...baseCols]
|
||||
}
|
||||
const gridOpMultiple = {
|
||||
...baseGridOp,
|
||||
columns: [{ type: 'selection', title: '' }, ...baseCols]
|
||||
}
|
||||
|
||||
const filter = (value) => {
|
||||
return allData.filter((item) => item.city.includes(value))
|
||||
}
|
||||
|
||||
const remoteMethod = (value) => {
|
||||
const filterData = filter(value)
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(filterData)
|
||||
}, 500)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,135 @@
|
|||
import { expect, test } from '@playwright/test'
|
||||
|
||||
test.describe('下拉表格远程搜索', () => {
|
||||
test('单选,下拉表格远程搜索基础用法', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#nest-grid-remote')
|
||||
|
||||
const wrap = page.locator('#nest-grid-remote')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const suffixSvg = dropdown.locator('.tiny-input__suffix .tiny-select__caret')
|
||||
|
||||
await expect(suffixSvg).toBeHidden()
|
||||
await expect(dropdown).toBeHidden()
|
||||
await input.focus()
|
||||
await input.fill(' ')
|
||||
await input.press('Enter')
|
||||
await page.waitForTimeout(200)
|
||||
await expect(dropdown).toBeVisible()
|
||||
await expect(dropdown.locator('.tiny-grid__body tbody')).toBeEmpty()
|
||||
await input.fill('1')
|
||||
await input.press('Enter')
|
||||
await page.waitForTimeout(200)
|
||||
await expect(dropdown.locator('.tiny-grid__body tbody')).not.toBeEmpty()
|
||||
|
||||
const row1 = page.getByRole('row', { name: '省份1 城市1 区域1' })
|
||||
const row2 = page.getByRole('row', { name: '省份2 城市2 区域2' })
|
||||
await expect(row2).not.toBeVisible()
|
||||
await row1.getByRole('cell').first().click()
|
||||
await expect(row1).toHaveClass(/row__current/)
|
||||
await expect(input).toHaveValue('省1-市1')
|
||||
|
||||
const row3 = page.getByRole('row', { name: '省份10 城市10 区域10' })
|
||||
await input.click()
|
||||
await row3.getByRole('cell').first().click()
|
||||
await expect(input).toHaveValue('省10-市10')
|
||||
})
|
||||
|
||||
test('单选,下拉表格远程搜索 + 自动搜索 + 显示按钮', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#nest-grid-remote')
|
||||
|
||||
const wrap = page.locator('#nest-grid-remote')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const suffixSvg = select.locator('.tiny-input__suffix .tiny-select__caret')
|
||||
|
||||
await expect(suffixSvg).toBeVisible()
|
||||
await expect(dropdown).toBeHidden()
|
||||
await input.click()
|
||||
await expect(dropdown).toBeVisible()
|
||||
await expect(dropdown.locator('.tiny-grid__body tbody')).not.toBeEmpty()
|
||||
await page.getByRole('row', { name: '省份2 城市2 区域2' }).getByRole('cell').first().click()
|
||||
await expect(input).toHaveValue('省2-市2')
|
||||
await input.click()
|
||||
await expect(page.getByRole('row', { name: '省份2 城市2 区域2' })).toHaveClass(/row__current/)
|
||||
await page.getByRole('row', { name: '省份6 城市6 区域6' }).getByRole('cell').first().click()
|
||||
await expect(input).toHaveValue('省6-市6')
|
||||
await input.click()
|
||||
await expect(page.getByRole('row', { name: '省份6 城市6 区域6' })).toHaveClass(/row__current/)
|
||||
await input.fill(' ')
|
||||
await input.press('Enter')
|
||||
await expect(dropdown).toBeVisible()
|
||||
await expect(dropdown.locator('.tiny-grid__body tbody')).toBeEmpty()
|
||||
})
|
||||
|
||||
test('多选,下拉表格远程搜索基础用法', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#nest-grid-remote')
|
||||
const wrap = page.locator('#nest-grid-remote')
|
||||
const select = wrap.locator('.tiny-select').nth(2)
|
||||
const input = select.locator('.tiny-select__input')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const suffixSvg = select.locator('.tiny-input__suffix .tiny-select__caret').first()
|
||||
|
||||
// 下拉按钮不显示
|
||||
await expect(suffixSvg).toBeHidden()
|
||||
await expect(dropdown).toBeHidden()
|
||||
|
||||
await input.fill(' ')
|
||||
await input.press('Enter')
|
||||
await page.waitForTimeout(1000)
|
||||
await expect(dropdown).toBeVisible()
|
||||
await expect(dropdown.locator('.tiny-grid__body tbody')).toBeEmpty()
|
||||
await input.fill('')
|
||||
await input.press('Enter')
|
||||
await page.waitForTimeout(1000)
|
||||
await expect(dropdown.locator('.tiny-grid__body tbody')).not.toBeEmpty()
|
||||
await page.getByRole('row', { name: '省份0 城市0 区域0' }).getByRole('cell').first().click()
|
||||
const tags = page.locator('.tiny-select .tiny-tag')
|
||||
expect((await tags.all()).length).toEqual(1)
|
||||
await expect(tags.first()).toContainText(/市0/)
|
||||
await page.getByRole('row', { name: '省份1 城市1 区域1' }).getByRole('cell').first().click()
|
||||
expect((await tags.all()).length).toEqual(2)
|
||||
await expect(tags.first()).toContainText(/市0/)
|
||||
await expect(tags.nth(1)).toContainText(/市1/)
|
||||
})
|
||||
|
||||
test('多选,下拉表格远程搜索 + 自动搜索 + 显示按钮', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#nest-grid-remote')
|
||||
|
||||
const wrap = page.locator('#nest-grid-remote')
|
||||
const select = wrap.locator('.tiny-select').nth(3)
|
||||
const input = select.locator('.tiny-select__input')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const suffixSvg = select.locator('.tiny-input__suffix .tiny-select__caret').first()
|
||||
const tag = select.locator('.tiny-tag')
|
||||
|
||||
await expect(suffixSvg).toBeVisible()
|
||||
await expect(dropdown).toBeHidden()
|
||||
await select.click()
|
||||
await expect(dropdown).toBeVisible()
|
||||
await expect(dropdown.locator('.tiny-grid__body tbody')).not.toBeEmpty()
|
||||
|
||||
await dropdown.getByRole('row', { name: '省份0 城市0 区域0' }).getByRole('cell').first().click()
|
||||
|
||||
expect((await tag.all()).length).toEqual(1)
|
||||
await expect(tag.first()).toContainText(/市0/)
|
||||
|
||||
await dropdown.getByRole('row', { name: '省份1 城市1 区域1' }).getByRole('cell').first().click()
|
||||
expect((await tag.all()).length).toEqual(2)
|
||||
await expect(tag.first()).toContainText(/市0/)
|
||||
await expect(tag.nth(1)).toContainText(/市1/)
|
||||
await tag.nth(0).locator('.tiny-svg').click()
|
||||
await tag.nth(0).locator('.tiny-svg').click()
|
||||
await expect((await tag.all()).length).toEqual(0)
|
||||
await input.fill(' ')
|
||||
await input.press('Enter')
|
||||
await expect(dropdown).toBeVisible()
|
||||
await expect(dropdown.locator('.tiny-grid__body tbody')).toBeEmpty()
|
||||
})
|
||||
})
|
|
@ -0,0 +1,136 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:单选,下拉表格远程搜索基础用法</p>
|
||||
<tiny-base-select
|
||||
v-model="value1"
|
||||
placeholder="请输入关键词"
|
||||
render-type="grid"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="remoteMethod"
|
||||
:grid-op="gridOpRadio"
|
||||
></tiny-base-select>
|
||||
|
||||
<p>场景2:单选,下拉表格远程搜索 + 自动搜索 + 显示按钮</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
placeholder="请输入关键词"
|
||||
render-type="grid"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="remoteMethod"
|
||||
:grid-op="gridOpRadio"
|
||||
:remote-config="{ autoSearch: true, clearData: true, showIcon: true }"
|
||||
></tiny-base-select>
|
||||
|
||||
<p>场景3:多选,下拉表格远程搜索基础用法</p>
|
||||
<tiny-base-select
|
||||
v-model="value3"
|
||||
placeholder="请输入关键词"
|
||||
multiple
|
||||
render-type="grid"
|
||||
reserve-keyword
|
||||
filterable
|
||||
remote
|
||||
:remote-method="remoteMethod"
|
||||
:grid-op="gridOpMultiple"
|
||||
></tiny-base-select>
|
||||
|
||||
<p>场景4:多选,下拉表格远程搜索 + 自动搜索 + 显示按钮</p>
|
||||
<tiny-base-select
|
||||
v-model="value4"
|
||||
placeholder="请输入关键词"
|
||||
multiple
|
||||
reserve-keyword
|
||||
filterable
|
||||
remote
|
||||
render-type="grid"
|
||||
:remote-method="remoteMethod"
|
||||
:grid-op="gridOpMultiple"
|
||||
:remote-config="{ autoSearch: true, clearData: true, showIcon: true }"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect
|
||||
},
|
||||
created() {
|
||||
this.allData = Array.from({ length: 1000 }, (a, i) => {
|
||||
return {
|
||||
value: '00' + i,
|
||||
province: '省份' + i,
|
||||
city: '城市' + i,
|
||||
area: '区域' + i,
|
||||
label: `省${i}-市${i}`
|
||||
}
|
||||
})
|
||||
},
|
||||
data() {
|
||||
const baseGridOp = {
|
||||
data: [],
|
||||
height: 300,
|
||||
optimization: {
|
||||
animat: true,
|
||||
delayHover: 250,
|
||||
scrollX: { gt: 20 },
|
||||
scrollY: { gt: 20 }
|
||||
}
|
||||
}
|
||||
const baseCols = [
|
||||
{
|
||||
field: 'province',
|
||||
title: '省份'
|
||||
},
|
||||
{ field: 'city', title: '城市' },
|
||||
{
|
||||
field: 'area',
|
||||
title: '区域'
|
||||
}
|
||||
]
|
||||
return {
|
||||
allData: [],
|
||||
value1: '',
|
||||
value2: '',
|
||||
value3: [],
|
||||
value4: [],
|
||||
gridOpRadio: {
|
||||
...baseGridOp,
|
||||
columns: [{ type: 'radio', title: '' }, ...baseCols]
|
||||
},
|
||||
gridOpMultiple: {
|
||||
...baseGridOp,
|
||||
columns: [{ type: 'selection', title: '' }, ...baseCols]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
remoteMethod(value) {
|
||||
const filterData = this.filter(value)
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(filterData)
|
||||
}, 500)
|
||||
})
|
||||
},
|
||||
filter(value) {
|
||||
return this.allData.filter((item) => item.city.includes(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,95 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('嵌套表格(单选)', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#nest-grid')
|
||||
|
||||
const wrap = page.locator('#nest-grid')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const suffixSvg = select.locator('.tiny-select__caret')
|
||||
const row = dropdown.getByRole('row')
|
||||
|
||||
await expect(suffixSvg).toHaveCount(1)
|
||||
await expect(suffixSvg).toBeVisible()
|
||||
|
||||
await input.click()
|
||||
await expect(dropdown).toBeVisible()
|
||||
await expect(row).toHaveCount(6)
|
||||
|
||||
await row.nth(1).getByRole('cell').first().click()
|
||||
await expect(input).toHaveValue('深圳1')
|
||||
await input.click()
|
||||
await expect(row.filter({ hasText: '深圳1' })).toHaveClass(/row__current/)
|
||||
})
|
||||
|
||||
test('嵌套表格(多选)', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#nest-grid')
|
||||
|
||||
const wrap = page.locator('#nest-grid')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const suffixSvg = select.locator('.tiny-select__caret')
|
||||
const row = dropdown.getByRole('row')
|
||||
const tag = select.locator('.tiny-tag')
|
||||
const currentRow = dropdown.locator('.row__selected')
|
||||
|
||||
await expect(tag).toHaveCount(0)
|
||||
await suffixSvg.click()
|
||||
|
||||
await expect(row).toHaveCount(6)
|
||||
await expect(currentRow).toHaveCount(0)
|
||||
await expect(row.nth(0).getByRole('cell').first().locator('.icon-half-select')).toBeHidden()
|
||||
await expect(row.nth(0).getByRole('cell').first().locator('.icon-checked-sur')).toBeHidden()
|
||||
|
||||
await row.nth(1).getByRole('cell').first().click()
|
||||
await row.nth(2).getByRole('cell').first().click()
|
||||
await row.nth(3).getByRole('cell').first().click()
|
||||
await expect(tag).toHaveCount(3)
|
||||
await expect(currentRow).toHaveCount(3)
|
||||
await expect(row.nth(0).getByRole('cell').first().locator('.icon-half-select')).toBeVisible()
|
||||
|
||||
await row.nth(0).getByRole('cell').first().click()
|
||||
await expect(tag).toHaveCount(5)
|
||||
await expect(currentRow).toHaveCount(5)
|
||||
await expect(row.nth(0).getByRole('cell').first().locator('.icon-checked-sur')).toBeVisible()
|
||||
|
||||
await row.nth(0).getByRole('cell').first().click()
|
||||
await expect(tag).toHaveCount(0)
|
||||
await expect(currentRow).toHaveCount(0)
|
||||
await expect(row.nth(0).getByRole('cell').first().locator('.icon-half-select')).toBeHidden()
|
||||
await expect(row.nth(0).getByRole('cell').first().locator('.icon-checked-sur')).toBeHidden()
|
||||
})
|
||||
|
||||
test('嵌套表格 + 可搜索 + 可清除', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#nest-grid')
|
||||
|
||||
const wrap = page.locator('#nest-grid')
|
||||
const select = wrap.locator('.tiny-select').nth(2)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const suffixSvg = select.locator('.tiny-select__caret')
|
||||
const row = dropdown.getByRole('row')
|
||||
|
||||
await input.click()
|
||||
|
||||
// 可搜索
|
||||
await expect(row).toHaveCount(6)
|
||||
await input.fill('深圳')
|
||||
await input.press('Enter')
|
||||
await page.waitForTimeout(200)
|
||||
await expect(row).toHaveCount(3)
|
||||
await row.nth(1).getByRole('cell').first().click()
|
||||
await expect(input).toHaveValue('深圳1')
|
||||
await input.click()
|
||||
await page.waitForTimeout(200)
|
||||
await expect(row.filter({ hasText: '深圳1' })).toHaveClass(/row__current/)
|
||||
await page.waitForTimeout(200)
|
||||
// 可清除
|
||||
await input.hover()
|
||||
await suffixSvg.nth(0).click()
|
||||
await expect(input).toHaveValue('')
|
||||
})
|
|
@ -0,0 +1,101 @@
|
|||
<template>
|
||||
<div class="demo-select">
|
||||
<p>场景1:嵌套表格(单选)</p>
|
||||
<tiny-base-select
|
||||
v-model="value1"
|
||||
value-field="id"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpSingle"
|
||||
></tiny-base-select>
|
||||
<p>场景2:嵌套表格(多选)</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
multiple
|
||||
value-field="id"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpMulti"
|
||||
></tiny-base-select>
|
||||
<p>场景3:嵌套表格 + 可搜索 + 可清除</p>
|
||||
<tiny-base-select
|
||||
ref="select"
|
||||
v-model="value3"
|
||||
filterable
|
||||
:filter-method="filter"
|
||||
clearable
|
||||
value-field="id"
|
||||
text-field="city"
|
||||
render-type="grid"
|
||||
:grid-op="gridOpSingle"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect
|
||||
},
|
||||
methods: {
|
||||
filter(value) {
|
||||
if (!value) {
|
||||
return this.gridOpSingle.data
|
||||
}
|
||||
|
||||
return this.gridOpSingle.data.filter((item) => {
|
||||
return item.city.includes(value)
|
||||
})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value1: '',
|
||||
value2: [],
|
||||
value3: '',
|
||||
gridOpSingle: {
|
||||
data: [
|
||||
{ id: '001', area: '华南区', province: '广东省', city: '深圳1' },
|
||||
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
|
||||
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
|
||||
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
|
||||
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
|
||||
],
|
||||
columns: [
|
||||
{ type: 'radio', title: '' },
|
||||
{ field: 'area', title: '区域', width: 90 },
|
||||
{ field: 'province', title: '省份', width: 60 },
|
||||
{ field: 'city', title: '城市', width: 60 }
|
||||
]
|
||||
},
|
||||
gridOpMulti: {
|
||||
data: [
|
||||
{ id: '001', area: '华南区', province: '广东省', city: '深圳1' },
|
||||
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
|
||||
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
|
||||
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
|
||||
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
|
||||
],
|
||||
columns: [
|
||||
{ type: 'selection', title: '' },
|
||||
{ field: 'area', title: '区域', width: 90 },
|
||||
{ field: 'province', title: '省份', width: 60 },
|
||||
{ field: 'city', title: '城市', width: 60 }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<tiny-base-select v-model="radioValue" value-field="id" text-field="city" render-type="grid" :grid-op="gridOpRadio">
|
||||
</tiny-base-select>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect } from '@opentiny/vue'
|
||||
|
||||
const radioValue = ref('')
|
||||
const gridOpRadio = ref({
|
||||
height: 200,
|
||||
data: [],
|
||||
columns: [
|
||||
{ type: 'radio', title: '' },
|
||||
{ field: 'area', title: '区域', width: 90 },
|
||||
{ field: 'province', title: '省份', width: 60 },
|
||||
{ field: 'city', title: '城市', width: 60 }
|
||||
]
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
const arr = []
|
||||
|
||||
for (let i = 0; i <= 800; i++) {
|
||||
const obj = {
|
||||
id: i,
|
||||
area: '华南区' + i,
|
||||
province: '广东省',
|
||||
city: '广州市'
|
||||
}
|
||||
arr.push(obj)
|
||||
}
|
||||
|
||||
gridOpRadio.value.data = arr
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,34 @@
|
|||
import { expect, test } from '@playwright/test'
|
||||
|
||||
test('下拉表格大数据', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#nest-radio-grid-much-data')
|
||||
|
||||
const wrap = page.locator('#nest-radio-grid-much-data')
|
||||
const select = wrap.locator('.tiny-select')
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const suffixSvg = select.locator('.tiny-input__suffix .tiny-select__caret')
|
||||
const row = dropdown.getByRole('row')
|
||||
|
||||
await expect(suffixSvg).toHaveCount(1)
|
||||
await expect(suffixSvg).toBeVisible()
|
||||
await expect(dropdown).toBeHidden()
|
||||
|
||||
await input.click()
|
||||
await expect(dropdown).toBeVisible()
|
||||
await expect(dropdown.locator('.tiny-grid__body tbody')).not.toBeEmpty()
|
||||
await row.nth(1).getByRole('cell').first().click()
|
||||
await expect(input).toHaveValue('广州市')
|
||||
|
||||
await input.click()
|
||||
await page.waitForTimeout(200)
|
||||
await expect(row.nth(1)).toHaveClass(/row__current/)
|
||||
await expect(row).toHaveCount(8)
|
||||
await expect(page.getByRole('row', { name: '华南区12 广东省 广州市' })).toBeHidden()
|
||||
await row.nth(7).scrollIntoViewIfNeeded()
|
||||
await expect(row).toHaveCount(8)
|
||||
await row.nth(7).scrollIntoViewIfNeeded()
|
||||
await expect(row).toHaveCount(8)
|
||||
await page.getByRole('row', { name: '华南区12 广东省 广州市' }).getByRole('cell').first().click()
|
||||
})
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<tiny-base-select v-model="radioValue" value-field="id" text-field="city" render-type="grid" :grid-op="gridOpRadio">
|
||||
</tiny-base-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
radioValue: '',
|
||||
gridOpRadio: {
|
||||
height: 200,
|
||||
data: [],
|
||||
columns: [
|
||||
{ type: 'radio', title: '' },
|
||||
{ field: 'area', title: '区域', width: 90 },
|
||||
{ field: 'province', title: '省份', width: 60 },
|
||||
{ field: 'city', title: '城市', width: 60 }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const arr = []
|
||||
|
||||
for (let i = 0; i <= 800; i++) {
|
||||
const obj = {
|
||||
id: i,
|
||||
area: '华南区' + i,
|
||||
province: '广东省',
|
||||
city: '广州市'
|
||||
}
|
||||
arr.push(obj)
|
||||
}
|
||||
|
||||
this.gridOpRadio.data = arr
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<div class="demo-select">
|
||||
<p>场景1:下拉树单选</p>
|
||||
<tiny-base-select
|
||||
v-model="treeValue1"
|
||||
value-field="id"
|
||||
text-field="label"
|
||||
render-type="tree"
|
||||
:tree-op="treeOp"
|
||||
></tiny-base-select>
|
||||
<p>场景2:下拉树多选</p>
|
||||
<tiny-base-select
|
||||
v-model="treeValue2"
|
||||
multiple
|
||||
value-field="id"
|
||||
text-field="label"
|
||||
render-type="tree"
|
||||
:tree-op="treeOp"
|
||||
></tiny-base-select>
|
||||
<p>场景3:下拉树可搜索</p>
|
||||
<tiny-base-select
|
||||
v-model="treeValue3"
|
||||
filterable
|
||||
:filter-method="filter"
|
||||
clearable
|
||||
value-field="id"
|
||||
text-field="label"
|
||||
render-type="tree"
|
||||
:tree-op="treeOp"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect } from '@opentiny/vue'
|
||||
|
||||
const treeValue1 = ref(10)
|
||||
const treeValue2 = ref([9, 6])
|
||||
const treeValue3 = ref('')
|
||||
|
||||
const treeOp = ref({
|
||||
data: [
|
||||
{
|
||||
id: 1,
|
||||
label: '一级 1',
|
||||
children: [
|
||||
{
|
||||
id: 4,
|
||||
label: '二级 1-1',
|
||||
children: [
|
||||
{
|
||||
id: 9,
|
||||
label: '三级 1-1-1'
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
label: '三级 1-1-2'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: '一级 2',
|
||||
children: [
|
||||
{
|
||||
id: 5,
|
||||
label: '二级 2-1'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
label: '二级 2-2'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const filter = (value, data) => {
|
||||
if (!value) return true
|
||||
|
||||
return data.label.includes(value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-select .tiny-select {
|
||||
width: 270px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,84 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('下拉树单选', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#nest-tree')
|
||||
|
||||
const wrap = page.locator('#nest-tree')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const suffixSvg = select.locator('.tiny-input__suffix .tiny-select__caret')
|
||||
const treeNode = dropdown.locator('.tiny-tree-node')
|
||||
|
||||
await expect(suffixSvg).toHaveCount(1)
|
||||
await expect(suffixSvg).toBeVisible()
|
||||
await expect(input).toHaveValue('三级 1-1-2')
|
||||
|
||||
await input.click()
|
||||
await expect(treeNode.filter({ hasText: /^三级 1-1-2$/ })).toHaveClass(/is-current/)
|
||||
|
||||
await treeNode.filter({ hasText: /^二级 2-1$/ }).click()
|
||||
await expect(input).toHaveValue('二级 2-1')
|
||||
await input.click()
|
||||
await expect(treeNode.filter({ hasText: /^二级 2-1$/ })).toHaveClass(/is-current/)
|
||||
})
|
||||
|
||||
test('下拉树多选', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#nest-tree')
|
||||
|
||||
const wrap = page.locator('#nest-tree')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const suffixSvg = select.locator('.tiny-input__suffix .tiny-select__caret')
|
||||
const treeNode = dropdown.locator('.tiny-tree-node')
|
||||
const checkedTreeNodes = dropdown.locator('.tiny-tree-node.is-checked')
|
||||
const tag = select.locator('.tiny-tag')
|
||||
|
||||
await expect(tag).toHaveCount(2)
|
||||
|
||||
await suffixSvg.click()
|
||||
await expect(checkedTreeNodes).toHaveCount(2)
|
||||
await expect(treeNode).toHaveCount(7)
|
||||
await page
|
||||
.locator('div')
|
||||
.filter({ hasText: /^一级 2$/ })
|
||||
.locator('.tiny-checkbox')
|
||||
.click()
|
||||
|
||||
await expect(checkedTreeNodes).toHaveCount(4)
|
||||
await expect(tag).toHaveCount(4)
|
||||
})
|
||||
|
||||
test('下拉树可搜索', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#nest-tree')
|
||||
|
||||
const wrap = page.locator('#nest-tree')
|
||||
const select = wrap.locator('.tiny-select').nth(2)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const treeNode = dropdown.locator('.tiny-tree-node')
|
||||
const hiddenTreeNodes = dropdown.locator('.tiny-tree-node.is-hidden')
|
||||
const checkedTreeNodes = dropdown.locator('.tiny-tree-node.is-current')
|
||||
|
||||
await expect(input).toHaveValue('')
|
||||
await expect(dropdown).toBeHidden()
|
||||
|
||||
await input.click()
|
||||
await expect(treeNode).toHaveCount(7)
|
||||
|
||||
await input.fill('2-')
|
||||
await input.press('Enter')
|
||||
await expect(hiddenTreeNodes).toHaveCount(4)
|
||||
await expect(checkedTreeNodes).toHaveCount(0)
|
||||
|
||||
await treeNode.getByText(/^一级 2$/).click()
|
||||
await expect(dropdown).toBeHidden()
|
||||
await expect(input).toHaveValue('一级 2')
|
||||
|
||||
await input.click()
|
||||
await expect(checkedTreeNodes.locator('.tiny-tree-node__content').nth(0)).toHaveText(/^一级 2$/)
|
||||
})
|
|
@ -0,0 +1,164 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>场景1:下拉树(单选)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="treeValue1"
|
||||
value-field="id"
|
||||
text-field="label"
|
||||
render-type="tree"
|
||||
:tree-op="treeOp"
|
||||
></tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:下拉树(多选)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="treeValue2"
|
||||
multiple
|
||||
value-field="id"
|
||||
text-field="label"
|
||||
render-type="tree"
|
||||
:tree-op="treeOp"
|
||||
></tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景3:下拉树可搜索</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="treeValue3"
|
||||
filterable
|
||||
:filter-method="filter"
|
||||
clearable
|
||||
value-field="id"
|
||||
text-field="label"
|
||||
render-type="tree"
|
||||
:tree-op="treeOp"
|
||||
></tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景4:下拉树懒加载(单选)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="treeValue4"
|
||||
value-field="id"
|
||||
text-field="label"
|
||||
render-type="tree"
|
||||
:tree-op="treeOpLazy"
|
||||
placeholder="请选择"
|
||||
></tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景5:下拉树懒加载(多选)</div>
|
||||
<br />
|
||||
<tiny-base-select
|
||||
v-model="treeValue5"
|
||||
value-field="id"
|
||||
text-field="label"
|
||||
render-type="tree"
|
||||
:tree-op="treeOpLazy"
|
||||
multiple
|
||||
placeholder="请选择"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
treeValue1: 10,
|
||||
treeValue2: [1, 9],
|
||||
treeValue3: '',
|
||||
treeValue4: 3,
|
||||
treeValue5: [1],
|
||||
treeOp: {
|
||||
data: [
|
||||
{
|
||||
id: 1,
|
||||
label: '一级 1',
|
||||
children: [
|
||||
{
|
||||
id: 4,
|
||||
label: '二级 1-1',
|
||||
children: [
|
||||
{
|
||||
id: 9,
|
||||
label: '三级 1-1-1'
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
label: '三级 1-1-2'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: '一级 2',
|
||||
children: [
|
||||
{
|
||||
id: 5,
|
||||
label: '二级 2-1'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
label: '二级 2-2'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
treeOpLazy: {
|
||||
lazy: true,
|
||||
load(node, resolve) {
|
||||
if (node.level === 0) {
|
||||
return resolve([
|
||||
{
|
||||
id: 3,
|
||||
label: '一级 3'
|
||||
}
|
||||
])
|
||||
}
|
||||
if (node.level > 1) return resolve([])
|
||||
|
||||
setTimeout(() => {
|
||||
const data = [
|
||||
{
|
||||
id: 1,
|
||||
label: '一级 1'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: '一级 2',
|
||||
isLeaf: true
|
||||
}
|
||||
]
|
||||
|
||||
resolve(data)
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
filter(value, data) {
|
||||
if (!value) return true
|
||||
|
||||
return data.label.includes(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tiny-select {
|
||||
width: 270px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:默认</p>
|
||||
<tiny-base-select v-model="value">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景2:自定义空数据文本</p>
|
||||
<tiny-base-select v-model="value" no-data-text="暂无数据">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景3:显示空数据图片</p>
|
||||
<tiny-base-select v-model="value" no-data-text="None" :show-empty-image="true">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options = ref([])
|
||||
const value = ref('')
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,39 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('默认空数据文本', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#no-data-text')
|
||||
|
||||
const wrap = page.locator('#no-data-text')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
|
||||
await input.click()
|
||||
await expect(dropdown.locator('.tiny-select-dropdown__empty')).toHaveText('暂无相关数据')
|
||||
})
|
||||
|
||||
test('自定义空数据文本', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#no-data-text')
|
||||
|
||||
const wrap = page.locator('#no-data-text')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
|
||||
await input.click()
|
||||
await expect(dropdown.locator('.tiny-select-dropdown__empty')).toHaveText('暂无数据')
|
||||
})
|
||||
|
||||
test('显示空数据图片', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#no-data-text')
|
||||
const wrap = page.locator('#no-data-text')
|
||||
const select = wrap.locator('.tiny-select').nth(2)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
|
||||
await input.click()
|
||||
await expect(dropdown.locator('.tiny-select-dropdown__empty-images')).toBeVisible()
|
||||
})
|
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>场景1:默认</p>
|
||||
<tiny-base-select v-model="value">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景2:自定义空数据文本</p>
|
||||
<tiny-base-select v-model="value" no-data-text="暂无数据">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
<p>场景3:显示空数据图片</p>
|
||||
<tiny-base-select v-model="value" no-data-text="None" :show-empty-image="true">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [],
|
||||
value: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>单选:</p>
|
||||
<tiny-base-select v-model="value1" :options="options" optimization @change="onChange"></tiny-base-select>
|
||||
<p>多选:</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
optimization
|
||||
multiple
|
||||
collapse-tags
|
||||
:multiple-limit="5"
|
||||
:options="options"
|
||||
@change="onChange"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Modal } from '@opentiny/vue'
|
||||
|
||||
const buildOptions = () =>
|
||||
Array.from({ length: 100000 }).map((item, i) => JSON.parse(`{"value":"选项${i}","label":"北京${i}"}`))
|
||||
|
||||
const value1 = ref('')
|
||||
const value2 = ref([])
|
||||
const options = ref(buildOptions())
|
||||
|
||||
const onChange = (value) => {
|
||||
Modal.message({
|
||||
message: JSON.stringify(value),
|
||||
status: 'info'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,46 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('单选虚拟滚动', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#optimization')
|
||||
|
||||
const wrap = page.locator('#optimization')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const input = select.locator('.tiny-input__inner')
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
|
||||
await select.click()
|
||||
await expect((await option.all()).length).toBeLessThan(20) // 新虚拟滚动,预加载行数不一样了
|
||||
await expect(option.filter({ hasText: '北京17' })).toBeHidden()
|
||||
await option.nth(9).scrollIntoViewIfNeeded()
|
||||
await page.waitForTimeout(1000)
|
||||
await expect(option.filter({ hasText: '北京17' })).toBeVisible() // 现在预加载的行比较多,所以17行已经可以看到了
|
||||
})
|
||||
|
||||
test('多选虚拟滚动', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#optimization')
|
||||
const wrap = page.locator('#optimization')
|
||||
const select = wrap.locator('.tiny-select').nth(1)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
const tag = select.locator('.tiny-tag')
|
||||
|
||||
await select.click()
|
||||
await expect((await option.all()).length).toBeLessThan(20) // 新虚拟滚动,预加载行数不一样了
|
||||
await expect(option.filter({ hasText: '北京17' })).toBeHidden()
|
||||
await expect(option.filter({ hasText: '北京16' })).toBeHidden()
|
||||
await page.waitForTimeout(500)
|
||||
await option.nth(9).scrollIntoViewIfNeeded()
|
||||
await page.waitForTimeout(1000)
|
||||
await option.nth(9).scrollIntoViewIfNeeded()
|
||||
await expect(option.filter({ hasText: '北京16' })).toBeVisible()
|
||||
await expect(option.filter({ hasText: '北京17' })).toBeVisible()
|
||||
await option.filter({ hasText: '北京17' }).click()
|
||||
await expect(tag.first()).toHaveText('北京17')
|
||||
await expect((await tag.all()).length).toEqual(1)
|
||||
await option.filter({ hasText: '北京16' }).click()
|
||||
await expect((await tag.all()).length).toEqual(2)
|
||||
await expect(tag.nth(1)).toHaveText('+ 1')
|
||||
})
|
|
@ -0,0 +1,54 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>单选:</p>
|
||||
<tiny-base-select v-model="value1" :options="options" optimization @change="onChange"></tiny-base-select>
|
||||
<p>多选:</p>
|
||||
<tiny-base-select
|
||||
v-model="value2"
|
||||
optimization
|
||||
multiple
|
||||
collapse-tags
|
||||
:multiple-limit="5"
|
||||
:options="options"
|
||||
@change="onChange"
|
||||
></tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Modal } from '@opentiny/vue'
|
||||
|
||||
const buildOptions = () =>
|
||||
Array.from({ length: 100000 }).map((item, i) => JSON.parse(`{"value":"选项${i}","label":"北京${i}"}`))
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value1: '',
|
||||
value2: [],
|
||||
options: buildOptions()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onChange(value) {
|
||||
Modal.message({
|
||||
message: JSON.stringify(value),
|
||||
status: 'info'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,96 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>场景1:分组 + 多选 + 面板可搜索</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value2" multiple filterable :searchable="true">
|
||||
<tiny-option-group v-for="group in options3" :key="group.label" :label="group.label" :disabled="!!group.disabled">
|
||||
<tiny-option
|
||||
v-for="item in group.options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></tiny-option>
|
||||
</tiny-option-group>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:单选分组</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value1" filterable>
|
||||
<tiny-option-group v-for="group in options3" :key="group.label" :label="group.label" :disabled="!!group.disabled">
|
||||
<tiny-option
|
||||
v-for="item in group.options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></tiny-option>
|
||||
</tiny-option-group>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景3:分组 + 多选</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value2" multiple>
|
||||
<tiny-option-group v-for="group in options3" :key="group.label" :label="group.label" :disabled="!!group.disabled">
|
||||
<tiny-option
|
||||
v-for="item in group.options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></tiny-option>
|
||||
</tiny-option-group>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景4:分组 + 多选 + 可搜索</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value2" filterable multiple>
|
||||
<tiny-option-group v-for="group in options3" :key="group.label" :label="group.label" :disabled="!!group.disabled">
|
||||
<tiny-option
|
||||
v-for="item in group.options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></tiny-option>
|
||||
</tiny-option-group>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption, OptionGroup as TinyOptionGroup } from '@opentiny/vue'
|
||||
|
||||
const options3 = ref([
|
||||
{
|
||||
label: '热门城市',
|
||||
disabled: true,
|
||||
options: [
|
||||
{ value: 'Shanghai', label: '上海' },
|
||||
{ value: 'Beijing', label: '北京' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '城市名',
|
||||
options: [
|
||||
{ value: 'Chengdu', label: '成都' },
|
||||
{ value: 'Shenzhen', label: '深圳' },
|
||||
{ value: 'Guangzhou', label: '广州' },
|
||||
{ value: 'Dalian', label: '大连' },
|
||||
{ value: 'Chongqing', label: '重庆' },
|
||||
{ value: 'Xianggang', label: '香港' },
|
||||
{ value: 'Aomen', label: '澳门' },
|
||||
{ value: 'Wulumuqi', label: '乌鲁木齐' }
|
||||
]
|
||||
}
|
||||
])
|
||||
|
||||
const value1 = ref([])
|
||||
const value2 = ref('')
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,22 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('option-group', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('select#option-group')
|
||||
|
||||
const wrap = page.locator('#option-group')
|
||||
const select = wrap.locator('.tiny-select').nth(0)
|
||||
const dropdown = page.locator('body > .tiny-select-dropdown')
|
||||
const option = dropdown.locator('.tiny-option')
|
||||
const title = dropdown.locator('.tiny-option-group__title')
|
||||
const group = dropdown.locator('.tiny-option-group ')
|
||||
|
||||
await select.click()
|
||||
await expect(title.nth(0)).toHaveText('热门城市')
|
||||
await expect(title.nth(1)).toHaveText('城市名')
|
||||
await expect(option.filter({ hasText: '上海' })).toHaveClass(/is-disabled/)
|
||||
await expect(option.filter({ hasText: '北京' })).toHaveClass(/is-disabled/)
|
||||
await expect(group.nth(0).locator('.tiny-option')).toHaveCount(2)
|
||||
await expect(group.nth(1).locator('.tiny-option')).toHaveCount(8)
|
||||
await expect((await group.all()).length).toEqual(2)
|
||||
})
|
|
@ -0,0 +1,105 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>场景1:分组 + 多选 + 面板可搜索</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value2" multiple filterable :searchable="true">
|
||||
<tiny-option-group v-for="group in options3" :key="group.label" :label="group.label" :disabled="!!group.disabled">
|
||||
<tiny-option
|
||||
v-for="item in group.options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></tiny-option>
|
||||
</tiny-option-group>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:单选分组</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value1" filterable>
|
||||
<tiny-option-group v-for="group in options3" :key="group.label" :label="group.label" :disabled="!!group.disabled">
|
||||
<tiny-option
|
||||
v-for="item in group.options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></tiny-option>
|
||||
</tiny-option-group>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景3:分组 + 多选</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value2" multiple>
|
||||
<tiny-option-group v-for="group in options3" :key="group.label" :label="group.label" :disabled="!!group.disabled">
|
||||
<tiny-option
|
||||
v-for="item in group.options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></tiny-option>
|
||||
</tiny-option-group>
|
||||
</tiny-base-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景4:分组 + 多选 + 可搜索</div>
|
||||
<br />
|
||||
<tiny-base-select v-model="value2" filterable multiple>
|
||||
<tiny-option-group v-for="group in options3" :key="group.label" :label="group.label" :disabled="!!group.disabled">
|
||||
<tiny-option
|
||||
v-for="item in group.options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></tiny-option>
|
||||
</tiny-option-group>
|
||||
</tiny-base-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BaseSelect, Option, OptionGroup } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyBaseSelect: BaseSelect,
|
||||
TinyOption: Option,
|
||||
TinyOptionGroup: OptionGroup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value1: [],
|
||||
value2: '',
|
||||
options3: [
|
||||
{
|
||||
label: '热门城市',
|
||||
disabled: true,
|
||||
options: [
|
||||
{ value: 'Shanghai', label: '上海' },
|
||||
{ value: 'Beijing', label: '北京' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '城市名',
|
||||
options: [
|
||||
{ value: 'Chengdu', label: '成都' },
|
||||
{ value: 'Shenzhen', label: '深圳' },
|
||||
{ value: 'Guangzhou', label: '广州' },
|
||||
{ value: 'Dalian', label: '大连' },
|
||||
{ value: 'Chongqing', label: '重庆' },
|
||||
{ value: 'Xianggang', label: '香港' },
|
||||
{ value: 'Aomen', label: '澳门' },
|
||||
{ value: 'Wulumuqi', label: '乌鲁木齐' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,32 @@
|
|||
<template>
|
||||
<tiny-base-select v-model="value" popper-class="drop" :popper-append-to-body="false" placement="top">
|
||||
<tiny-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||
</tiny-base-select>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { BaseSelect as TinyBaseSelect, Option as TinyOption } from '@opentiny/vue'
|
||||
|
||||
const options = reactive([
|
||||
{ value: '选项1', label: '北京' },
|
||||
{ value: '选项2', label: '上海' },
|
||||
{ value: '选项3', label: '天津' },
|
||||
{ value: '选项4', label: '重庆' },
|
||||
{ value: '选项5', label: '深圳' }
|
||||
])
|
||||
const value = ref('')
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tiny-select {
|
||||
width: 280px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.drop {
|
||||
background-color: #d5e8ff;
|
||||
}
|
||||
</style>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue