This commit is contained in:
maplemei 2019-09-25 17:47:38 +08:00
parent 9786701c41
commit 2d26f68640
72 changed files with 3707 additions and 2064 deletions

16
.editorconfig Normal file
View File

@ -0,0 +1,16 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

44
CHANGELOG.md Normal file
View File

@ -0,0 +1,44 @@
## 更新日志
### 1.0.3
*2019-09-25*
#### Bug fixes
- 借鉴[ElementUI](https://element.eleme.cn/#/zh-CN)的文档编写方式, 重新编辑使用文档
- 修改on监听时已选中数据不对的问题
- 修改显示模式也支持html方式
- 存在layui时, 同样也能直接使用xmSelect, 不用必须layui.xmSelect
### 1.0.2
*2019-09-23*
#### Bug fixes
- 搜索时输入中文延迟后才进行回显
- 远程搜索时, loading状态也能进行输入的问题
- 单选模式下, 前面的图标变成圆形
- 修正Windows下的一些样式错乱, 兼容IE10以上
- 启动分页, 当搜索时, 如果搜索总页码为0, 再次搜索有页码时, 当前页面为0的问题
- 当底部空间不足时, 再次判断顶部空间是否充足, 优化展开方向
### 1.0.1
*2019-09-22*
#### 新增
- 物理分页配置
- 自定义搜索模式(远程搜索)
- 下拉选高度配置
#### Bug fixes
- 调整布局为flex布局
- 展开下拉选时, 自动聚焦搜索框

128
README.md
View File

@ -16,7 +16,7 @@
QQ群: 660408068
[更新日志](docs/changelog.md)
[更新日志](CHANGELOG.md)
#### 软件架构
@ -61,132 +61,6 @@ QQ群: 660408068
</a>
</p>
#### 使用说明
> 默认配置项
```
{
//多选数据
data: [],
//默认选中数据, 优先级大于selected
initValue: null,
//默认提示
tips: '请选择', //please selected
//空数据提示
empty: '暂无数据', //no data
//搜索延迟 ms
delay: 500,
//搜索默认提示
searchTips: setting.searchTips,
//是否开始本地搜索
filterable: false,
//本地搜索过滤方法
filterMethod: function(val, item, index, prop){
if(!val) return true;
return item[prop.name].indexOf(val) != -1;
},
//是否开启远程搜索
remoteSearch: false,
//远程搜索回调
remoteMethod: function(val, cb){
//val: 搜索的值, cb: 回调函数
cb([]);
},
//下拉方向
direction: 'auto',
//自定义样式
style: {},
//默认多选的高度
height: '200px',
//是否开启分页
paging: false,
//分页每页的条数
pageSize: 10,
//是否开启单选模式
radio: false,
//是否开启重复选模式
repeat: false,
//是否点击选项后自动关闭下拉框
clickClose: false,
//自定义属性名称
prop: {
name: 'name',
value: 'value',
selected: 'selected',
disabled: 'disabled',
},
//主题配置
theme: {
color: '#009688',
},
//模型, 用来控制插件的显示方式, 标签/文字/汇总个数/自定义
model: {
label: {
type: 'block',
text: {
left: '',
right: '',
separator: ', ',
},
block: {
showCount: 0,
showIcon: true,
},
count: {
template(data, sels){
return '已选中 '+sels.length+' 项, 共 '+data.length+' 项'
}
},
},
},
// 展开下拉框
show(){
},
// 隐藏下拉框
hide(){
},
// 模板组成, 当前option数据
template({ item, sels, name, value }){
return name;
},
//监听选中事件
on({ arr, item, selected }){
}
}
```
> 默认方法
```
//更新组件
xmSelect: update(options)
//重置组件
xmSelect: reset()
//重新渲染
xmSelect: render(options)
//主动关闭
xmSelect: opened()
//主动关闭
xmSelect: closed()
//获取已选中数据
xmSelect: getValue()
//设置选中数据, array: 选中数据, show: 是否展开下拉框
xmSelect: setValue(array, show)
```
#### 示例
[示例页面](https://maplemei.gitee.io/xm-select/)

24
build/md-loader/config.js Executable file
View File

@ -0,0 +1,24 @@
const Config = require('markdown-it-chain');
const anchorPlugin = require('markdown-it-anchor');
const slugify = require('transliteration').slugify;
const containers = require('./containers');
const overWriteFenceRule = require('./fence');
const config = new Config();
config
.options.html(true).end()
.plugin('anchor').use(anchorPlugin, [{
level: 2,
slugify: slugify,
permalink: true,
permalinkBefore: true
}]).end()
.plugin('containers').use(containers).end();
const md = config.toMd();
overWriteFenceRule(md);
module.exports = md;

24
build/md-loader/containers.js Executable file
View File

@ -0,0 +1,24 @@
const mdContainer = require('markdown-it-container');
module.exports = md => {
md.use(mdContainer, 'demo', {
validate(params) {
return params.trim().match(/^demo\s*(.*)$/);
},
render(tokens, idx) {
const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/);
if (tokens[idx].nesting === 1) {
const description = m && m.length > 1 ? m[1] : '';
const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : '';
return `<demo-block>
${description ? `<div>${md.render(description)}</div>` : ''}
<!--element-demo: ${content}:element-demo-->
`;
}
return '</demo-block>';
}
});
md.use(mdContainer, 'tip');
md.use(mdContainer, 'warning');
};

14
build/md-loader/fence.js Executable file
View File

@ -0,0 +1,14 @@
// 覆盖默认的 fence 渲染策略
module.exports = md => {
const defaultRender = md.renderer.rules.fence;
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
const token = tokens[idx];
// 判断该 fence 是否在 :::demo 内
const prevToken = tokens[idx - 1];
const isInDemoContainer = prevToken && prevToken.nesting === 1 && prevToken.info.trim().match(/^demo\s*(.*)$/);
if (token.info === 'html' && isInDemoContainer) {
return `<template slot="highlight"><pre v-pre><code class="html">${md.utils.escapeHtml(token.content)}</code></pre></template>`;
}
return defaultRender(tokens, idx, options, env, self);
};
};

67
build/md-loader/index.js Executable file
View File

@ -0,0 +1,67 @@
const {
stripScript,
stripTemplate,
genInlineComponentText
} = require('./util');
const md = require('./config');
module.exports = function(source) {
const content = md.render(source);
const startTag = '<!--element-demo:';
const startTagLen = startTag.length;
const endTag = ':element-demo-->';
const endTagLen = endTag.length;
let componenetsString = '';
let id = 0; // demo 的 id
let output = []; // 输出的内容
let start = 0; // 字符串开始位置
let commentStart = content.indexOf(startTag);
let commentEnd = content.indexOf(endTag, commentStart + startTagLen);
while (commentStart !== -1 && commentEnd !== -1) {
output.push(content.slice(start, commentStart));
const commentContent = content.slice(commentStart + startTagLen, commentEnd);
const html = stripTemplate(commentContent);
const script = stripScript(commentContent);
let demoComponentContent = genInlineComponentText(html, script);
const demoComponentName = `element-demo${id}`;
output.push(`<template slot="source"><${demoComponentName} /></template>`);
componenetsString += `${JSON.stringify(demoComponentName)}: ${demoComponentContent},`;
// 重新计算下一次的位置
id++;
start = commentEnd + endTagLen;
commentStart = content.indexOf(startTag, start);
commentEnd = content.indexOf(endTag, commentStart + startTagLen);
}
// 仅允许在 demo 不存在时,才可以在 Markdown 中写 script 标签
// todo: 优化这段逻辑
let pageScript = '';
if (componenetsString) {
pageScript = `<script>
export default {
name: 'component-doc',
components: {
${componenetsString}
},
}
</script>`;
} else if (content.indexOf('<script>') === 0) { // 硬编码,有待改善
start = content.indexOf('</script>') + '</script>'.length;
pageScript = content.slice(0, start);
}
output.push(content.slice(start));
return `
<template>
<section class="content element-doc">
${output.join('')}
</section>
</template>
${pageScript}
`;
};

90
build/md-loader/util.js Executable file
View File

@ -0,0 +1,90 @@
const {
compileTemplate
} = require('@vue/component-compiler-utils');
const compiler = require('vue-template-compiler');
function stripScript(content) {
const result = content.match(/<(script)>([\s\S]+)<\/\1>/);
return result && result[2] ? result[2].trim() : '';
}
function stripStyle(content) {
const result = content.match(/<(style)\s*>([\s\S]+)<\/\1>/);
return result && result[2] ? result[2].trim() : '';
}
// 编写例子时不一定有 template。所以采取的方案是剔除其他的内容
function stripTemplate(content) {
content = content.trim();
if (!content) {
return content;
}
return content.replace(/<(script|style)[\s\S]+<\/\1>/g, '').trim();
}
function pad(source) {
return source
.split(/\r?\n/)
.map(line => ` ${line}`)
.join('\n');
}
function genInlineComponentText(template, script) {
// https://github.com/vuejs/vue-loader/blob/423b8341ab368c2117931e909e2da9af74503635/lib/loaders/templateLoader.js#L46
const finalOptions = {
source: `<div>${template}</div>`,
filename: 'inline-component', // TODO这里有待调整
compiler
};
const compiled = compileTemplate(finalOptions);
// tips
if (compiled.tips && compiled.tips.length) {
compiled.tips.forEach(tip => {
console.warn(tip);
});
}
// errors
if (compiled.errors && compiled.errors.length) {
console.error(
`\n Error compiling template:\n${pad(compiled.source)}\n` +
compiled.errors.map(e => ` - ${e}`).join('\n') +
'\n'
);
}
let demoComponentContent = `
${compiled.code}
`;
// todo: 这里采用了硬编码有待改进
script = script.trim();
if (script) {
script = script.replace(/export\s+default/, 'const democomponentExport =');
} else {
script = 'const democomponentExport = {}';
}
demoComponentContent =
`(function() {
${demoComponentContent}
return {
render,
staticRenderFns,
mounted(){
this.$nextTick(() => {
${script}
});
}
}
})()`;
// console.log('\n\n\n=================\n\n\n')
// console.log(demoComponentContent);
// console.log('\n\n\n=================\n\n\n')
return demoComponentContent;
}
module.exports = {
stripScript,
stripStyle,
stripTemplate,
genInlineComponentText
};

102
build/webpack.config.js Normal file
View File

@ -0,0 +1,102 @@
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const {
CleanWebpackPlugin
} = require('clean-webpack-plugin');
const isProd = process.env.NODE_ENV === 'prod';
const webpackConfig = {
entry: {
'xm-select': "./src/index.js",
'static/docs': "./docs/entry.js",
},
output: {
path: path.resolve(__dirname, isProd ? '../dist/' : '../docs/dist/'),
filename: '[name].js',
publicPath: './',
chunkFilename: path.posix.join('./', 'static/[name].js'),
},
module: {
rules: [{
test: /\.css$/,
loader: 'style-loader!css-loader'
}, {
test: /\.less$/,
exclude: /node_modules/,
loader: 'style-loader!css-loader!less-loader'
}, {
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}, {
test: /\.vue$/,
loader: 'vue-loader',
options: {
compilerOptions: {
preserveWhitespace: false
}
}
}, {
test: /\.md$/,
use: [{
loader: 'vue-loader',
options: {
compilerOptions: {
preserveWhitespace: false
}
}
}, {
loader: path.resolve(__dirname, './md-loader/index.js')
}]
}, {
test: /\.(svg|otf|ttf|woff2?|eot|gif|png|jpe?g)(\?\S*)?$/,
loader: 'url-loader',
// todo: 这种写法有待调整
query: {
limit: 10000,
name: path.posix.join('static', '[name].[hash:7].[ext]')
}
}]
},
resolve: {
alias: {
'@': path.resolve(__dirname, "../src"),
'components': path.resolve(__dirname, "../src/components"),
'style': path.resolve(__dirname, "../src/style"),
}
},
plugins: [
new HtmlWebpackPlugin({
template: './docs/index.ejs',
filename: 'index.html',
// favicon: './examples/favicon.ico',
minify: {
collapseWhitespace: true
}
}),
new VueLoaderPlugin(),
],
devServer: {
host: '0.0.0.0',
port: 9000,
publicPath: '/',
hot: true
},
};
if (isProd) {
webpackConfig.plugins.push(
new CleanWebpackPlugin(),
)
}
module.exports = webpackConfig;

2
dist/index.html vendored
View File

@ -1 +1 @@
<!DOCTYPE html><html><head><link rel="preload" href="xm-select.js" as="script"><meta charset="utf-8"><title>xm-select</title></head><body><div id="demo1"></div><script type="text/javascript" src="xm-select.js"></script></body></html>
<!DOCTYPE html><html><head><link rel="preload" href="./xm-select.js" as="script"><link rel="preload" href="./static/docs.js" as="script"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"><!-- <link rel="stylesheet" href="//shadow.elemecdn.com/npm/highlight.js@9.3.0/styles/color-brewer.css"> --><!-- <link rel="stylesheet" href="//shadow.elemecdn.com/npm/element-ui@2.12.0/lib/theme-chalk/index.css"> --><title>xm-select</title></head><body><div id="app"></div><script type="text/javascript" src="./xm-select.js"></script><script type="text/javascript" src="./static/docs.js"></script></body></html>

1
dist/static/2.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/static/3.js vendored Normal file

File diff suppressed because one or more lines are too long

26
dist/static/docs.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
dist/static/element-icons.535877f.woff vendored Normal file

Binary file not shown.

BIN
dist/static/element-icons.732389d.ttf vendored Normal file

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB

2
dist/xm-select.js vendored

File diff suppressed because one or more lines are too long

260
docs/App.vue Normal file
View File

@ -0,0 +1,260 @@
<template>
<div id="app" class="xm-select-doc is-component">
<main-header></main-header>
<div class="main-cnt">
<el-scrollbar class="page-component__scroll" ref="componentScrollBar">
<div class="page-container page-component">
<el-scrollbar class="page-component__nav">
<side-nav :data="navsData" :base="``"></side-nav>
</el-scrollbar>
<div class="page-component__content">
<router-view class="content"></router-view>
</div>
<el-backtop target=".page-component__scroll .el-scrollbar__wrap" :right="100" :bottom="150"></el-backtop>
</div>
</el-scrollbar>
</div>
</div>
</template>
<script>
import navsData from './router.js';
import throttle from 'throttle-debounce/throttle';
import SideNav from './components/side-nav.vue';
import MainHeader from './components/header.vue'
export default {
components: {
SideNav, MainHeader
},
data() {
return {
lang: this.$route.meta.lang,
navsData,
scrollTop: 0,
showHeader: true,
componentScrollBar: null,
componentScrollBoxElement: null
};
},
watch: {
'$route.path'() {
//
this.componentScrollBox.scrollTop = 0;
this.$nextTick(() => {
this.componentScrollBar.update();
});
}
},
methods: {
renderAnchorHref() {
if (/changelog/g.test(location.href)) return;
const anchors = document.querySelectorAll('h2 a,h3 a,h4 a,h5 a');
const basePath = location.href.split('#').splice(0, 2).join('#');
[].slice.call(anchors).forEach(a => {
const href = a.getAttribute('href');
a.href = basePath + href;
});
},
goAnchor() {
if (location.href.match(/#/g).length > 1) {
const anchor = location.href.match(/#[^#]+$/g);
if (!anchor) return;
const elm = document.querySelector(anchor[0]);
if (!elm) return;
setTimeout(_ => {
this.componentScrollBox.scrollTop = elm.offsetTop;
}, 50);
}
},
handleScroll() {
const scrollTop = this.componentScrollBox.scrollTop;
if (this.showHeader !== this.scrollTop > scrollTop) {
this.showHeader = this.scrollTop > scrollTop;
}
if (scrollTop === 0) {
this.showHeader = true;
}
if (!this.navFaded) {
this.$emit('fadeNav');
}
this.scrollTop = scrollTop;
}
},
created() {
this.$on('navFade', val => {
this.navFaded = val;
});
},
mounted() {
this.componentScrollBar = this.$refs.componentScrollBar;
this.componentScrollBox = this.componentScrollBar.$el.querySelector('.el-scrollbar__wrap');
this.throttledScrollHandler = throttle(300, this.handleScroll);
this.componentScrollBox.addEventListener('scroll', this.throttledScrollHandler);
this.renderAnchorHref();
this.goAnchor();
document.body.classList.add('is-component');
},
destroyed() {
document.body.classList.remove('is-component');
},
beforeDestroy() {
this.componentScrollBox.removeEventListener('scroll', this.throttledScrollHandler);
},
beforeRouteUpdate(to, from, next) {
next();
setTimeout(() => {
const toPath = to.path;
const fromPath = from.path;
if (toPath === fromPath && to.hash) {
this.goAnchor();
}
if (toPath !== fromPath) {
document.documentElement.scrollTop = document.body.scrollTop = 0;
this.renderAnchorHref();
}
}, 100);
}
};
</script>
<style lang="less">
.page-component__scroll {
height: calc(100% - 80px);
margin-top: 80px;
&>.el-scrollbar__wrap {
overflow-x: auto;
}
}
.page-component {
box-sizing: border-box;
height: 100%;
&.page-container {
padding: 0;
}
.page-component__nav {
width: 240px;
position: fixed;
top: 0;
bottom: 0;
margin-top: 80px;
transition: padding-top .3s;
&>.el-scrollbar__wrap {
height: 100%;
overflow-x: auto;
}
&.is-extended {
padding-top: 0;
}
}
.side-nav {
height: 100%;
padding-top: 50px;
padding-bottom: 50px;
padding-right: 0;
&>ul {
padding-bottom: 50px;
}
}
.page-component__content {
padding-left: 270px;
padding-bottom: 100px;
box-sizing: border-box;
}
.content {
padding-top: 50px;
&> {
h3 {
margin: 55px 0 20px;
}
table {
border-collapse: collapse;
width: 100%;
background-color: #fff;
font-size: 14px;
margin-bottom: 45px;
line-height: 1.5em;
strong {
font-weight: normal;
}
td,
th {
border-bottom: 1px solid #dcdfe6;
padding: 15px;
max-width: 250px;
}
th {
text-align: left;
white-space: nowrap;
color: #909399;
font-weight: normal;
}
td {
color: #606266;
}
th:first-child,
td:first-child {
padding-left: 10px;
}
}
ul:not(.timeline) {
margin: 10px 0;
padding: 0 0 0 20px;
font-size: 14px;
color: #5e6d82;
line-height: 2em;
}
}
}
}
@media (max-width: 768px) {
.page-component {
.page-component__nav {
width: 100%;
position: static;
margin-top: 0;
}
.side-nav {
padding-top: 0;
padding-left: 50px;
}
.page-component__content {
padding-left: 10px;
padding-right: 10px;
}
.content {
padding-top: 0;
}
.content>table {
overflow: auto;
display: block;
}
}
}
</style>

206
docs/assets/common.less Executable file
View File

@ -0,0 +1,206 @@
*{
margin: 0;
padding: 0;
}
html, body {
margin: 0;
padding: 0;
height: 100%;
font-family: 'Helvetica Neue',Helvetica,'PingFang SC','Hiragino Sans GB','Microsoft YaHei',SimSun,sans-serif;
font-weight: 400;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
&.is-component {
overflow: hidden;
}
}
#app {
height: 100%;
&.is-component {
overflow-y: hidden;
.main-cnt {
padding: 0;
margin-top: 0;
height: 100%;
min-height: auto;
}
.headerWrapper {
position: fixed;
width: 100%;
left: 0;
top: 0;
z-index: 1500;
.container {
padding: 0;
}
}
}
}
a {
color: #409EFF;
text-decoration: none;
}
code {
background-color: #f9fafc;
padding: 0 4px;
border: 1px solid #eaeefb;
border-radius: 4px;
}
button, input, select, textarea {
font-family: inherit;
font-size: inherit;
line-height: inherit;
color: inherit;
}
.hljs {
line-height: 1.8;
font-family: Menlo, Monaco, Consolas, Courier, monospace;
font-size: 12px;
padding: 18px 24px;
background-color: #fafafa;
border: solid 1px #eaeefb;
margin-bottom: 25px;
border-radius: 4px;
-webkit-font-smoothing: auto;
}
.main-cnt {
margin-top: -80px;
padding: 80px 0 340px;
box-sizing: border-box;
min-height: 100%;
}
.container,
.page-container {
width: 1140px;
padding: 0;
margin: 0 auto;
}
.page-container {
padding-top: 55px;
h2 {
font-size: 28px;
color: #1f2d3d;
margin: 0;
}
h3 {
font-size: 22px;
}
h2, h3, h4, h5 {
font-weight: normal;
color: #1f2f3d;
&:hover a {
opacity: .4;
}
a {
float: left;
margin-left: -20px;
opacity: 0;
cursor: pointer;
&:hover {
opacity: .4;
}
}
}
p {
font-size: 14px;
color: #5e6d82;
line-height: 1.5em;
}
.tip {
padding: 8px 16px;
background-color: #ECF8FF;
border-radius: 4px;
border-left: #50bfff 5px solid;
margin: 20px 0;
code {
background-color: rgba(255, 255, 255, .7);
color: #445368;
}
}
.warning {
padding: 8px 16px;
background-color: #fff6f7;
border-radius: 4px;
border-left: #FE6C6F 5px solid;
margin: 20px 0;
code {
background-color: rgba(255, 255, 255, .7);
color: #445368;
}
}
}
.demo {
margin: 20px 0;
}
@media (max-width: 1140px) {
.container,
.page-container {
width: 100%;
}
}
@media (max-width: 768px) {
.container,
.page-container {
padding: 0 20px;
}
#app.is-component .headerWrapper .container {
padding: 0 12px;
}
}
.xm-select-demo{
vertical-align: top;
display: inline-block;
width: 300px;
}
.btn{
outline: 0;
display: inline-block;
height: 38px;
line-height: 38px;
padding: 0 18px;
background-color: #009688;
color: #fff;
white-space: nowrap;
text-align: center;
font-size: 14px;
border: none;
border-radius: 2px;
cursor: pointer;
vertical-align: top;
margin-left: 10px;
&:hover{
opacity: .8;
}
&:active{
opacity: 1;
}
}

BIN
docs/assets/wx.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View File

@ -1,28 +0,0 @@
# 2019-09-23
`v1.0.2`
1. [修改]搜索时输入中文延迟后才进行回显
2. [修改]远程搜索时, loading状态也能进行输入的问题
3. [修改]单选模式下, 前面的图标变成圆形
4. [修改]修正Windows下的一些样式错乱, 兼容IE10以上
5. [修改]启动分页, 当搜索时, 如果搜索总页码为0, 再次搜索有页码时, 当前页面为0的问题
6. [修改]当底部空间不足时, 再次判断顶部空间是否充足, 优化展开方向
# 2019-09-22
`v1.0.1`
1. [新增]物理分页配置
2. [新增]自定义搜索模式(远程搜索)
3. [新增]下拉选高度配置
4. [修改]调整布局为flex布局
5. [修改]展开下拉选时, 自动聚焦搜索框
# 2019-09-16
`v1.0.0`
这仅仅是一个开始~~~

View File

@ -0,0 +1,3 @@
<template>
<router-view></router-view>
</template>

240
docs/components/demo-block.vue Executable file
View File

@ -0,0 +1,240 @@
<template>
<div class="demo-block" :class="[blockClass, { 'hover': hovering }]" @mouseenter="hovering = true" @mouseleave="hovering = false">
<div class="source">
<slot name="source"></slot>
</div>
<div class="meta" ref="meta">
<div class="description" v-if="$slots.default">
<slot></slot>
</div>
<div class="highlight">
<slot name="highlight"></slot>
</div>
</div>
<div class="demo-block-control" ref="control" :class="{ 'is-fixed': fixedControl }" @click="isExpanded = !isExpanded">
<transition name="arrow-slide">
<i :class="[iconClass, { 'hovering': hovering }]"></i>
</transition>
<transition name="text-slide">
<span v-show="hovering">{{ controlText }}</span>
</transition>
</div>
</div>
</template>
<script>
export default {
data() {
return {
hovering: false,
isExpanded: false,
fixedControl: false,
scrollParent: null
};
},
methods: {
scrollHandler() {
const { top, bottom, left } = this.$refs.meta.getBoundingClientRect();
this.fixedControl = bottom > document.documentElement.clientHeight &&
top + 44 <= document.documentElement.clientHeight;
this.$refs.control.style.left = this.fixedControl ? `${ left }px` : '0';
},
removeScrollHandler() {
this.scrollParent && this.scrollParent.removeEventListener('scroll', this.scrollHandler);
}
},
computed: {
langConfig() {
return {
"hide-text": "隐藏代码",
"show-text": "显示代码",
}
},
blockClass() {
return `demo-xm-select demo-${ this.$router.currentRoute.path.split('/').pop() }`;
},
iconClass() {
return this.isExpanded ? 'el-icon-caret-top' : 'el-icon-caret-bottom';
},
controlText() {
return this.isExpanded ? this.langConfig['hide-text'] : this.langConfig['show-text'];
},
codeArea() {
return this.$el.getElementsByClassName('meta')[0];
},
codeAreaHeight() {
if (this.$el.getElementsByClassName('description').length > 0) {
return this.$el.getElementsByClassName('description')[0].clientHeight +
this.$el.getElementsByClassName('highlight')[0].clientHeight + 20;
}
return this.$el.getElementsByClassName('highlight')[0].clientHeight;
}
},
watch: {
isExpanded(val) {
this.codeArea.style.height = val ? `${ this.codeAreaHeight + 1 }px` : '0';
if (!val) {
this.fixedControl = false;
this.$refs.control.style.left = '0';
this.removeScrollHandler();
return;
}
setTimeout(() => {
this.scrollParent = document.querySelector('.page-component__scroll > .el-scrollbar__wrap');
this.scrollParent && this.scrollParent.addEventListener('scroll', this.scrollHandler);
this.scrollHandler();
}, 200);
}
},
mounted() {
this.$nextTick(() => {
let highlight = this.$el.getElementsByClassName('highlight')[0];
if (this.$el.getElementsByClassName('description').length === 0) {
highlight.style.width = '100%';
highlight.borderRight = 'none';
}
});
},
beforeDestroy() {
this.removeScrollHandler();
}
};
</script>
<style lang="less">
.demo-block {
border: solid 1px #ebebeb;
border-radius: 3px;
transition: .2s;
&.hover {
box-shadow: 0 0 8px 0 rgba(232, 237, 250, .6), 0 2px 4px 0 rgba(232, 237, 250, .5);
}
code {
font-family: Menlo, Monaco, Consolas, Courier, monospace;
}
.demo-button {
float: right;
}
.source {
padding: 24px;
}
.meta {
background-color: #fafafa;
border-top: solid 1px #eaeefb;
overflow: hidden;
height: 0;
transition: height .2s;
}
.description {
padding: 20px;
box-sizing: border-box;
border: solid 1px #ebebeb;
border-radius: 3px;
font-size: 14px;
line-height: 22px;
color: #666;
word-break: break-word;
margin: 10px;
background-color: #fff;
p {
margin: 0;
line-height: 26px;
}
code {
color: #5e6d82;
background-color: #e6effb;
margin: 0 4px;
display: inline-block;
padding: 1px 5px;
font-size: 12px;
border-radius: 3px;
height: 18px;
line-height: 18px;
}
}
.highlight {
pre {
margin: 0;
}
code.hljs {
margin: 0;
border: none;
max-height: none;
border-radius: 0;
&::before {
content: none;
}
}
}
.demo-block-control {
border-top: solid 1px #eaeefb;
height: 44px;
box-sizing: border-box;
background-color: #fff;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
text-align: center;
margin-top: -1px;
color: #d3dce6;
cursor: pointer;
position: relative;
&.is-fixed {
position: fixed;
bottom: 0;
width: 868px;
}
i {
font-size: 16px;
line-height: 44px;
transition: .3s;
&.hovering {
transform: translateX(-40px);
}
}
>span {
position: absolute;
transform: translateX(-30px);
font-size: 14px;
line-height: 44px;
transition: .3s;
display: inline-block;
}
&:hover {
color: #409EFF;
background-color: #f9fafc;
}
& .text-slide-enter,
& .text-slide-leave-active {
opacity: 0;
transform: translateX(10px);
}
.control-button {
line-height: 26px;
position: absolute;
top: 0;
right: 0;
font-size: 14px;
padding-left: 5px;
padding-right: 25px;
}
}
}
</style>

325
docs/components/header.vue Executable file
View File

@ -0,0 +1,325 @@
<template>
<div class="headerWrapper">
<header class="header" ref="header">
<div class="container">
<h1>
<router-link :to="`/`">
<!-- logo -->
<slot>
<!-- <img src="../assets/images/element-logo.svg" alt="element-logo" class="nav-logo"> -->
<!-- <img src="../assets/images/element-logo-small.svg" alt="element-logo" class="nav-logo-small"> -->
xm-select
</slot>
</router-link>
</h1>
<!-- nav -->
<ul class="nav">
<li class="nav-item">
<router-link active-class="active" :to="`/`">使用手册</router-link>
</li>
<li class="nav-item">
<a href='https://gitee.com/maplemei/xm-select' target="_blank" style="opacity: 1; display: flex; margin-top: 20px;">
<img src='https://gitee.com/maplemei/xm-select/widgets/widget_6.svg' alt='Fork me on Gitee'></img>
</a>
</li>
</ul>
</div>
</header>
</div>
</template>
<script>
export default {
data() {
return {
active: '',
};
},
};
</script>
<style lang="less" scoped>
.headerWrapper {
height: 80px;
}
.header {
height: 80px;
background-color: #fff;
color: #fff;
top: 0;
left: 0;
width: 100%;
line-height: 80px;
z-index: 100;
position: relative;
.container {
height: 100%;
box-sizing: border-box;
border-bottom: 1px solid #DCDFE6;
}
.nav-lang-spe {
color: #888;
}
h1 {
margin: 0;
float: left;
font-size: 32px;
font-weight: normal;
a {
color: #333;
text-decoration: none;
display: block;
}
span {
font-size: 12px;
display: inline-block;
width: 34px;
height: 18px;
border: 1px solid rgba(255, 255, 255, .5);
text-align: center;
line-height: 18px;
vertical-align: middle;
margin-left: 10px;
border-radius: 3px;
}
}
.nav {
float: right;
height: 100%;
line-height: 80px;
background: transparent;
padding: 0;
margin: 0;
&::before,
&::after {
display: table;
content: "";
}
&::after {
clear: both;
}
}
.nav-gap {
position: relative;
width: 1px;
height: 80px;
padding: 0 20px;
&::before {
content: '';
position: absolute;
top: calc(50% - 8px);
width: 1px;
height: 16px;
background: #ebebeb;
}
}
.nav-logo,
.nav-logo-small {
vertical-align: sub;
}
.nav-logo-small {
display: none;
}
.nav-item {
margin: 0;
float: left;
list-style: none;
position: relative;
cursor: pointer;
&.nav-algolia-search {
cursor: default;
}
&.lang-item,
&:last-child {
cursor: default;
margin-left: 34px;
span {
opacity: .8;
}
.nav-lang {
cursor: pointer;
display: inline-block;
height: 100%;
color: #888;
&:hover {
color: #409EFF;
}
&.active {
font-weight: bold;
color: #409EFF;
}
}
}
a {
text-decoration: none;
color: #1989FA;
opacity: 0.5;
display: block;
padding: 0 22px;
&.active,
&:hover {
opacity: 1;
}
&.active::after {
content: '';
display: inline-block;
position: absolute;
bottom: 0;
left: calc(50% - 15px);
width: 30px;
height: 2px;
background: #409EFF;
}
}
}
}
.nav-dropdown {
margin-bottom: 6px;
padding-left: 18px;
width: 100%;
span {
display: block;
width: 100%;
font-size: 16px;
color: #888;
line-height: 40px;
transition: .2s;
padding-bottom: 6px;
user-select: none;
&:hover {
cursor: pointer;
}
}
i {
transition: .2s;
font-size: 12px;
color: #979797;
transform: translateY(-2px);
}
.is-active {
span,
i {
color: #409EFF;
}
i {
transform: rotateZ(180deg) translateY(3px);
}
}
&:hover {
span,
i {
color: #409EFF;
}
}
}
.nav-dropdown-list {
width: auto;
}
@media (max-width: 850px) {
.header {
.nav-logo {
display: none;
}
.nav-logo-small {
display: inline-block;
}
.nav-item {
margin-left: 6px;
&.lang-item,
&:last-child {
margin-left: 10px;
}
a {
padding: 0 5px;
}
}
.nav-theme-switch,
.nav-algolia-search {
display: none;
}
}
}
@media (max-width: 700px) {
.header {
.container {
padding: 0 12px;
}
.nav-item {
a {
font-size: 12px;
vertical-align: top;
}
&.lang-item {
height: 100%;
.nav-lang {
display: flex;
align-items: center;
span {
padding-bottom: 0;
}
}
}
}
.nav-dropdown {
padding: 0;
span {
font-size: 12px;
}
}
.nav-gap {
padding: 0 8px;
}
.nav-versions {
display: none;
}
}
}
</style>

234
docs/components/side-nav.vue Executable file
View File

@ -0,0 +1,234 @@
<template>
<div class="side-nav" @mouseenter="isFade = false" :class="{ 'is-fade': isFade }" :style="navStyle">
<ul>
<li class="nav-item" v-for="(item, key) in data.filter(a => !a.hidden)" :key="key">
<a v-if="!item.path && !item.href" @click="expandMenu">{{item.name}}</a>
<a v-if="item.href" :href="item.href" target="_blank">{{item.name}}</a>
<router-link v-if="item.path" active-class="active" :to="base + item.path" exact v-text="item.title || item.name"></router-link>
<ul class="pure-menu-list sub-nav" v-if="item.children">
<li class="nav-item" v-for="(navItem, key) in item.children" :key="key">
<router-link class="" active-class="active" :to="base + navItem.path" exact v-text="navItem.title || navItem.name"></router-link>
</li>
</ul>
<template v-if="item.groups">
<div class="nav-group" v-for="(group, key) in item.groups" :key="key">
<div class="nav-group__title" @click="expandMenu">{{group.groupName}}</div>
<ul class="pure-menu-list">
<li class="nav-item" v-for="(navItem, key) in group.list" v-show="!navItem.disabled" :key="key">
<router-link active-class="active" :to="base + navItem.path" exact v-text="navItem.title"></router-link>
</li>
</ul>
</div>
</template>
</li>
</ul>
<!--<div id="code-sponsor-widget"></div>-->
</div>
</template>
<script>
export default {
props: {
data: Array,
base: {
type: String,
default: ''
}
},
data() {
return {
highlights: [],
navState: [],
isSmallScreen: false,
isFade: false
};
},
watch: {
'$route.path'() {
this.handlePathChange();
},
isFade(val) {
this.$emit('navFade', val);
}
},
computed: {
navStyle() {
const style = {};
if (this.isSmallScreen) {
style.paddingBottom = '60px';
}
style.opacity = this.isFade ? '0.5' : '1';
return style;
},
},
methods: {
handleResize() {
this.isSmallScreen = document.documentElement.clientWidth < 768;
this.handlePathChange();
},
handlePathChange() {
if (!this.isSmallScreen) {
this.expandAllMenu();
return;
}
this.$nextTick(() => {
this.hideAllMenu();
let activeAnchor = this.$el.querySelector('a.active');
let ul = activeAnchor.parentNode;
while (ul.tagName !== 'UL') {
ul = ul.parentNode;
}
ul.style.height = 'auto';
});
},
hideAllMenu() {
[].forEach.call(this.$el.querySelectorAll('.pure-menu-list'), ul => {
ul.style.height = '0';
});
},
expandAllMenu() {
[].forEach.call(this.$el.querySelectorAll('.pure-menu-list'), ul => {
ul.style.height = 'auto';
});
},
expandMenu(event) {
if (!this.isSmallScreen) return;
let target = event.currentTarget;
if (!target.nextElementSibling || target.nextElementSibling.tagName !== 'UL') return;
this.hideAllMenu();
event.currentTarget.nextElementSibling.style.height = 'auto';
}
},
created() {
this.$on('fadeNav', () => {
this.isFade = true;
});
},
mounted() {
this.handleResize();
window.addEventListener('resize', this.handleResize);
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize);
}
};
</script>
<style lang="less">
.side-nav {
width: 100%;
box-sizing: border-box;
padding-right: 30px;
transition: opacity .3s;
&.is-fade {
transition: opacity 3s;
}
li {
list-style: none;
}
ul {
padding: 0;
margin: 0;
overflow: hidden;
}
>ul>.nav-item>a {
margin-top: 15px;
}
>ul>.nav-item:nth-child(-n + 4)>a {
margin-top: 0;
}
.nav-item {
a {
font-size: 16px;
color: #333;
line-height: 40px;
height: 40px;
margin: 0;
padding: 0;
text-decoration: none;
display: block;
position: relative;
transition: .15s ease-out;
font-weight: bold;
&.active {
color: #409EFF;
}
}
.nav-item {
a {
display: block;
height: 40px;
color: #444;
line-height: 40px;
font-size: 14px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-weight: normal;
&:hover,
&.active {
color: #409EFF;
}
}
}
&.sponsors {
&>.sub-nav {
margin-top: -10px;
}
&>a {
color: #777;
font-weight: 300;
font-size: 14px;
}
.nav-item {
display: inline-block;
a {
height: auto;
display: inline-block;
vertical-align: middle;
margin: 8px 12px 12px 0;
img {
width: 42px;
}
}
&:first-child a img {
width: 36px;
}
}
}
}
.nav-group__title {
font-size: 12px;
color: #999;
line-height: 26px;
margin-top: 15px;
}
#code-sponsor-widget {
margin: 0 0 0 -20px;
}
}
.nav-dropdown-list {
width: 120px;
margin-top: -8px;
li {
font-size: 14px;
}
}
</style>

View File

@ -1,709 +0,0 @@
window.data = [
{ html: `
<a href='https://gitee.com/maplemei/xm-select'><img src='https://gitee.com/maplemei/xm-select/widgets/widget_6.svg' alt='Fork me on Gitee'></img></a>
<p>xm-select始于layui, 前身formSelects, 此版本引入第三方preact库, 利用jsx渲染页面结构</p>
<p>作者: 热爱前端的Java程序猿</p>
<p>QQ号: 707200833</p>
<p>QQ群: 660408068</p>
<a target="_blank" class="qqicon" href="https://shang.qq.com/wpa/qunwpa?idkey=9f9d4de074f2cb4d13afb3f04b874742a5f400eac2c0648fcfd20afb5413fb0a"><img border="0" src="docs/group.png" alt="技术交流群" title="技术交流群"></a>
<div class="example">
<p> 捐赠作者 </p>
<p>
<img src="docs/wx.jpg" width="230px" style="border: 1px solid #009688">
</p>
<p>你们的支持, 是我们坚持的动力</p>
</div>
<div id="test01"></div>
`, js: `
xmSelect.render({
// 这里是指定渲染的地方
el: '#test01',
// 这里是渲染的数据
data: [{name: '水果', value: 1}, {name: '蔬菜', value: 2}]
})
`, comment: `
简单的使用方法:
1. 引入xm-select.js文件
2. <div id="test01"></div>
3. 使用js渲染指定元素
`, brush: 'html', title: '简介'},
{ html: `
<p>如果有bug欢迎提issues, 或者在群内@群主进行反馈</p>
<h3>更新日志</h3>
`, js: ``, comment: `
[2019-09-23] v1.0.2
1. [修改]搜索时输入中文延迟后才进行回显
2. [修改]远程搜索时, loading状态也能进行输入的问题
3. [修改]单选模式下, 前面的图标变成圆形
4. [修改]修正Windows下的一些样式错乱, 兼容IE10以上
5. [修改]启动分页, 当搜索时, 如果搜索总页码为0, 再次搜索有页码时, 当前页面为0的问题
6. [修改]当底部空间不足时, 再次判断顶部空间是否充足, 优化展开方向
[2019-09-22] v1.0.1
1. [新增]物理分页配置
2. [新增]自定义搜索模式(远程搜索)
3. [新增]下拉选高度配置
4. [修改]调整布局为flex布局
5. [修改]展开下拉选时, 自动聚焦搜索框
[2019-07-29] v1.0.0.0729
1. 更新文档显示问题
[2019-07-27] v1.0.0.0727
1. 新增单选模式, {radio: true|false}
2. 新增重复选模式, {repeat: true|false}
3. 新增配置, 可以控制是否自动关闭下拉框, {clickClose: true|false}
4. 新增on方法, 可以监听已选择数据, data: {arr, item, selected}
更新文档演示
[---] v1.0.0
很久很久以前...
`, brush: 'html', title: '更新日志'},
{ html: `
<h3>默认配置项options</h3>
`, comment: `
{
//多选数据
data: [],
//默认选中数据, 优先级大于selected
initValue: null,
//默认提示
tips: '请选择', //please selected
//空数据提示
empty: '暂无数据', //no data
//搜索延迟 ms
delay: 500,
//搜索默认提示
searchTips: setting.searchTips,
//是否开始本地搜索
filterable: false,
//本地搜索过滤方法
filterMethod: function(val, item, index, prop){
if(!val) return true;
return item[prop.name].indexOf(val) != -1;
},
//是否开启自定义搜索, 必须设置 filterable: true
remoteSearch: false,
//远程搜索回调
remoteMethod: function(val, cb){
cb([]);
},
//下拉方向
direction: 'auto',
//自定义样式
style: {},
//默认多选的高度
height: '200px',
//是否开启分页
paging: false,
//分页每页的条数
pageSize: 10,
//是否开启单选模式
radio: false,
//是否开启重复选模式
repeat: false,
//是否点击选项后自动关闭下拉框
clickClose: false,
//自定义属性名称
prop: {
name: 'name',
value: 'value',
selected: 'selected',
disabled: 'disabled',
},
//主题配置
theme: {
color: '#009688',
},
//模型
model: {
label: {
type: 'block',
text: {
left: '',
right: '',
separator: ', ',
},
block: {
showCount: 0,
showIcon: true,
},
count: {
template(data, sels){
return '已选中 '+sels.length+' 项, 共 '+data.length+' 项'
}
},
},
},
// 展开下拉框
show(){
},
// 隐藏下拉框
hide(){
},
// 模板组成, 当前option数据, 已经选中的数据, name, value
template({ item, sels, name, value }){
return name;
},
//监听选中事件
on({ arr, item, selected }){
}
}
`, brush: 'js', title: '默认配置项'},
{ html: `
<h3>所有的方法</h3>
`, comment: `
//更新组件
xmSelect: update(options)
//重置组件
xmSelect: reset()
//重新渲染
xmSelect: render(options)
//主动关闭
xmSelect: opened()
//主动关闭
xmSelect: closed()
//获取已选中数据
xmSelect: getValue()
//设置选中数据, array: 选中数据, show: 是否展开下拉框
xmSelect: setValue(array, show)
`, brush: 'js', title: '所有的方法method'},
{ html: `
<h3>这是一个国语版</h3>
<div id="demo1"></div>
`, js: `
var demo1 = xmSelect.render({
el: '#demo1',
language: 'zn',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
})
`, brush: 'js', title: '这是一个国语版'},
{ html: `
<h3>这是一个国际版(English)</h3>
<div id="demo2"></div>
`, js: `
var demo02 = xmSelect.render({
el: '#demo2',
language: 'en',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
})
`, brush: 'js', title: '这是一个国际版(English)'},
{ html: `
<h3>有基础数据</h3>
<div id="demo3"></div>
`, js: `
var demo3 = xmSelect.render({
el: '#demo3',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
]
})
`, brush: 'js', title: '有基础数据'},
{ html: `
<h3>有选中, 禁用的</h3>
<div id="demo4"></div>
`, js: `
var demo4 = xmSelect.render({
el: '#demo4',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
]
})
`, brush: 'js', title: '有选中, 禁用的'},
{ html: `
<h3>自定义key</h3>
<div id="demo5"></div>
`, js: `
var demo5 = xmSelect.render({
el: '#demo5',
data: [
{label: '水果', val: 1, sel: true, dis: true},
{label: '蔬菜', val: 2, sel: true},
{label: '桌子', val: 3, dis: true},
{label: '北京', val: 4},
],
prop: {
name: 'label',
value: 'val',
selected: 'sel',
disabled: 'dis'
}
})
`, brush: 'js', title: '自定义key'},
{ html: `
<h3>使用template自己构建选项1</h3>
<div id="demo6"></div>
`, js: `
var demo6 = xmSelect.render({
el: '#demo6',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
],
template: function({item, arr, name, value}){
return name + '<span style="color: red; margin-left: 20px;">'+value+'</span>'
}
})
`, brush: 'js', title: '使用template自己构建选项1'},
{ html: `
<h3>使用template自己构建选项2</h3>
<div id="demo7"></div>
`, js: `
var demo7 = xmSelect.render({
el: '#demo7',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
],
template: function({item, arr, name, value}){
return name + '<span style="position: absolute; right: 10px; color: red">'+value+'</span>'
}
})
`, brush: 'js', title: '使用template自己构建选项2'},
{ html: `
<h3>简单的展示形式1</h3>
<div id="demo8"></div>
`, js: `
var demo8 = xmSelect.render({
el: '#demo8',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
],
model: {
label: {
type: 'text',
text: {
left: '<',
right: '>',
separator: ', ',
},
}
}
})
`, brush: 'js', title: '简单的展示形式1'},
{ html: `
<h3>简单的展示形式2</h3>
<div id="demo9"></div>
`, js: `
var demo9 = xmSelect.render({
el: '#demo9',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
],
model: {
label: {
type: 'count',
count: {
template: function(data, arr){
return "已选中 " + arr.length + " 项, 共 " + data.length + " 项"
}
}
}
}
})
`, brush: 'js', title: '简单的展示形式2'},
{ html: `
<h3>自定义展示</h3>
<div id="demo10"></div>
`, js: `
var demo10 = xmSelect.render({
el: '#demo10',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
],
model: {
label: {
type: 'count',
count: {
template: function(data, arr){
return "我是自定义的... 已选中 " + arr.length + " 项, 共 " + data.length + " 项"
}
}
}
}
})
`, brush: 'js', title: '自定义展示'},
{ html: `
<h3>多余的用 +隐藏</h3>
<div id="demo11"></div>
`, js: `
var demo11 = xmSelect.render({
el: '#demo11',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
],
model: {
label: {
type: 'block',
block: {
showCount: 1,
showIcon: true,
}
}
}
})
`, brush: 'js', title: '多余的用 +隐藏'},
{ html: `
<h3>不显示删除图标</h3>
<div id="demo12"></div>
`, js: `
var demo12 = xmSelect.render({
el: '#demo12',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
],
model: {
label: {
type: 'block',
block: {
showCount: 1,
showIcon: false,
}
}
}
})
`, brush: 'js', title: '不显示删除图标'},
{ html: `
<h3>换一个主题</h3>
<div id="demo13"></div>
`, js: `
var demo13 = xmSelect.render({
el: '#demo13',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
],
theme: {
color: 'red',
},
})
`, brush: 'js', title: '换一个主题'},
{ html: `
<h3>开启搜索模式</h3>
<div id="demo14"></div>
`, js: `
var demo14 = xmSelect.render({
el: '#demo14',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
],
filterable: true, //开启搜索
})
`, brush: 'js', title: '开启搜索模式'},
{ html: `
<h3>自定义搜索方法</h3>
<div id="demo15"></div>
`, js: `
var demo15 = xmSelect.render({
el: '#demo15',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
],
filterable: true, //开启搜索
filterMethod: function(val, item, index, prop){
if(!val) return true;
return item[prop.name].indexOf(val) != -1;
},
})
`, brush: 'js', title: '自定义搜索方法'},
{ html: `
<h3>自定义搜索延迟 提示</h3>
<div id="demo16"></div>
`, js: `
var demo16 = xmSelect.render({
el: '#demo16',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
],
filterable: true, //开启搜索
delay: 2000,
searchTips: '搜索呀 搜索呀...',
})
`, brush: 'js', title: '自定义搜索延迟 和 提示'},
{ html: `
<h3>1000条数据测试</h3>
<div id="demo17"></div>
`, js: `
var startTime = Date.now();
var demo17 = xmSelect.render({
el: '#demo17',
data: ''.padEnd(1000, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
filterable: true, //开启搜索
})
console.log('1000条数据渲染耗时: ' + (Date.now() - startTime) + 'ms');
`, brush: 'js', title: '1000条数据测试'},
{ html: `
<h3>自动判断下拉方向</h3>
<div id="demo18"></div>
`, js: `
var demo18 = xmSelect.render({
el: '#demo18',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
filterable: true, //开启搜索
direction: 'auto',
})
`, brush: 'js', title: '自动判断下拉方向'},
{ html: `
<h3>只会往下</h3>
<div id="demo19"></div>
`, js: `
var demo19 = xmSelect.render({
el: '#demo19',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
filterable: true, //开启搜索
direction: 'down',
})
`, brush: 'js', title: '只会往下'},
{ html: `
<h3>只会往上</h3>
<div id="demo20"></div>
`, js: `
var demo20 = xmSelect.render({
el: '#demo20',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
filterable: true, //开启搜索
direction: 'up',
})
`, brush: 'js', title: '只会往上'},
{ html: `
<h3>自定义style样式</h3>
<div id="demo21"></div>
`, js: `
var demo21 = xmSelect.render({
el: '#demo21',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
filterable: true, //开启搜索
style: {
width: '200px',
marginLeft: '20px',
}
})
`, brush: 'js', title: '自定义style样式'},
{ html: `
<h3>单选模式</h3>
<div id="demo22"></div>
`, js: `
var demo22 = xmSelect.render({
el: '#demo22',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
radio: true,
clickClose: true,
})
`, brush: 'js', title: '单选模式'},
{ html: `
<h3>重复选模式</h3>
<div id="demo23"></div>
`, js: `
var demo23 = xmSelect.render({
el: '#demo23',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
repeat: true,
})
`, brush: 'js', title: '重复选模式'},
{ html: `
<h3>多选选完即关闭下拉选</h3>
<div id="demo24"></div>
`, js: `
var demo24 = xmSelect.render({
el: '#demo24',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
clickClose: true,
})
`, brush: 'js', title: '多选选完即关闭下拉选'},
{ html: `
<h3>监听已选择数据</h3>
<div id="demo25"></div>
`, js: `
var demo25 = xmSelect.render({
el: '#demo25',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
on: function({ arr, item, selected }){
console.log('已选择: ', arr);
console.log('点击选项: ', item);
console.log('点击状态: ', selected);
alert('选择: ' + JSON.stringify(item) + ', 状态: ' + selected);
}
})
`, brush: 'js', title: '监听已选择数据on'},
{ html: `
<h3>监听下拉框的打开与关闭</h3>
<div id="demo26"></div>
`, js: `
var demo26 = xmSelect.render({
el: '#demo26',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
show: function(){
alert('打开了');
},
hide: function(){
alert('关闭了');
}
})
`, brush: 'js', title: '监听下拉框的打开与关闭'},
{ html: `
<h3>控制下拉框的打开与关闭</h3>
<div id="demo27"></div>
`, js: `
var demo27 = xmSelect.render({
el: '#demo27',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
show: function(){
//这里也可以组件受控
//return false;
},
hide: function(){
var arr = demo27.getValue();
//如果已选择数据小于1, 则不会关闭下拉框
if(arr.length < 1){
return false;//组件受控
}
}
})
`, brush: 'js', title: '控制下拉框的打开与关闭'},
{ html: `
<h3>启用分页</h3>
<div id="demo28"></div>
`, js: `
var demo28 = xmSelect.render({
el: '#demo28',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
paging: true,//开启分页
pageSize: 10,//每页10条
})
`, brush: 'js', title: '启用分页'},
{ html: `
<h3>自定义搜索</h3>
<div id="demo29"></div>
`, js: `
var demo29 = xmSelect.render({
el: '#demo29',
data: ''.padEnd(100, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
filterable: true,//开启搜索
remoteSearch: true,//自定义搜索
remoteMethod: function(val, cb){
//这里模拟2s后回调
setTimeout(() => {
cb([{name: 'xxx' + val, value: 1}])
}, 2000);
},
})
`, brush: 'js', title: '自定义搜索'},
];

39
docs/entry.js Normal file
View File

@ -0,0 +1,39 @@
//引入xm-select
import '@/index.js';
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import hljs from 'highlight.js';
import 'highlight.js/styles/color-brewer.css'
import VueRouter from 'vue-router';
import routes from './router';
import App from './App.vue';
import demoBlock from './components/demo-block.vue';
Vue.use(ElementUI);
Vue.use(VueRouter);
Vue.component('demo-block', demoBlock);
import './assets/common.less'
const router = new VueRouter({
mode: 'hash',
base: __dirname,
routes
});
router.afterEach(route => {
Vue.nextTick(() => {
const blocks = document.querySelectorAll('pre code:not(.hljs)');
Array.prototype.forEach.call(blocks, hljs.highlightBlock);
});
});
new Vue({
el: '#app',
router,
render: h => h(App)
});

View File

@ -1,315 +0,0 @@
(function($, window, undefined) {
var Fathom = function(container, options) {
this.container = container;
this.options = options;
return this.init()
},
$window = $(window),
$document = $(document);
Fathom.prototype = {
defaults: {
portable: undefined,
portableTagName: "div",
portableClass: "fathom-container",
displayMode: "single",
slideTagName: "div",
slideClass: "slide",
activeClass: "activeslide",
inactiveClass: "inactiveslide",
margin: 100,
onScrollInterval: 300,
scrollLength: 600,
easing: "swing",
timeline: undefined,
video: undefined,
onActivateSlide: undefined,
onDeactivateSlide: undefined
},
init: function() {
this.config = $.extend({}, this.defaults, this.options);
this.$container = $(this.container);
this.$slides = this.$container.find(this.config.slideTagName + (this.config.slideClass ? "." + this.config.slideClass :
""));
this.$firstSlide = this.$slides.filter(":first");
this.$lastSlide = this.$slides.filter(":last");
this.$activeSlide = this.activateSlide(this.$firstSlide);
return this._detectPortable()._setStyles()._setClasses()._setMargins()._setupEvents()._setupTimeline()._setupVideo()
._setupScrollHandler()
},
nextSlide: function() {
return this.scrollToSlide(this.$activeSlide.next())
},
prevSlide: function() {
return this.scrollToSlide(this.$activeSlide.prev())
},
scrollToSlide: function($elem) {
var self = this,
$scrollingElement = this.config.portable ? this.$portableContainer : $("html,body"),
$container = this.config.portable ? this.$portableContainer : $window,
portableScrollLeft = this.config.portable ? this.$portableContainer.scrollLeft() : 0;
if ($elem.length !== 1) {
return $elem
}
this.isAutoScrolling = true;
$scrollingElement.stop().animate({
scrollLeft: $elem.position().left + portableScrollLeft - ($container.width() - $elem.innerWidth()) / 2
}, self.config.scrollLength, self.config.easing, function() {
self.isAutoScrolling = false
});
return this.activateSlide($elem)
},
activateSlide: function($elem) {
var elem = $elem.get(0),
activeSlide;
if (this.$activeSlide !== undefined) {
activeSlide = this.$activeSlide.get(0);
if (activeSlide === elem) {
return $elem
}
this.$activeSlide.removeClass(this.config.activeClass).addClass(this.config.inactiveClass).trigger(
"deactivateslide.fathom");
if (typeof this.config.onDeactivateSlide === "function") {
this.config.onDeactivateSlide.call(activeSlide)
}
}
$elem.removeClass(this.config.inactiveClass).addClass(this.config.activeClass);
this.$activeSlide = $elem;
$elem.trigger("activateslide.fathom");
if (typeof this.config.onActivateSlide === "function") {
this.config.onActivateSlide.call(elem)
}
return $elem
},
setTime: function(t) {
var times = this._timeline || [];
for (var i = 0; i < times.length; i++) {
if (times[i].time <= t && times[i + 1].time > t) {
if (this.$activeSlide[0] !== times[i].slide[0]) {
this.scrollToSlide(times[i].slide)
}
break
}
}
},
_detectPortable: function() {
if (this.config.portable === undefined) {
if (this.$container.parent().is("body")) {
this.config.portable = false
} else {
this.config.portable = true
}
}
return this
},
_setupEvents: function() {
var self = this;
this.$container.delegate(this.config.slideTagName + "." + this.config.inactiveClass, "click", function(event) {
event.preventDefault();
self.scrollToSlide($(this))
});
$document.keydown(function(event) {
var key = event.which;
if (key === 39 || key === 32) {
event.preventDefault();
self.nextSlide()
} else if (key === 37) {
event.preventDefault();
self.prevSlide()
}
});
$window.resize(function() {
self._setMargins()
});
return this
},
_setStyles: function() {
this.$container.css("white-space", "nowrap");
this.$slides.css({
"white-space": "normal",
display: "inline-block",
"vertical-align": "top"
});
if (this.config.portable) {
this.$portableContainer = $("<" + this.config.portableTagName + ' class="' + this.config.portableClass + '" />');
this.$container.before(this.$portableContainer).appendTo(this.$portableContainer)
}
return this
},
_setClasses: function() {
this.$slides.addClass(this.config.inactiveClass);
this.$activeSlide.removeClass(this.config.inactiveClass).addClass(this.config.activeClass);
return this
},
_setMargins: function() {
var displayMode = this.config.displayMode,
$container = this.config.portable ? this.$portableContainer : $window,
containerWidth = $container.width(),
verticalSpacing = Math.ceil(($container.height() - this.$firstSlide.innerHeight()) / 2),
firstSlideSpacing = Math.ceil((containerWidth - this.$firstSlide.innerWidth()) / 2),
lastSlideSpacing = Math.ceil((containerWidth - this.$lastSlide.innerWidth()) / 2),
peekabooWidth = Math.ceil(containerWidth / 25);
this.$container.css("margin-top", verticalSpacing);
if (displayMode === "single") {
this.$slides.css("margin-right", firstSlideSpacing)
} else if (displayMode === "multi") {
this.$slides.css("margin-right", this.config.margin)
}
this.$firstSlide.css("margin-left", firstSlideSpacing);
this.$lastSlide.css("margin-right", lastSlideSpacing);
if (this.config.portable) {
var slidesWidth = parseInt(this.$container.css("padding-left")) + parseInt(this.$container.css("padding-right"));
this.$slides.each(function() {
slidesWidth += $(this).outerWidth(true)
});
this.$container.width(slidesWidth)
}
return this
},
_setupTimeline: function() {
var slides = this.$slides;
function parseTime(point) {
for (var m = (point.time || point).toString().match(/(((\d+):)?(\d+):)?(\d+)/), a = 0, i = 3; i <= 5; i++) {
a = a * 60 + parseInt(m[i] || 0)
}
return a
}
var currentSlide = -1;
function parseSlide(point) {
if (point.slide == null) {
currentSlide++
} else if ($.type(point.slide) === "number") {
currentSlide = point.slide
} else {
for (var match = slides.filter(point.slide)[0], i = 0; i < slides.length; i++) {
if (slides[i] === match) {
currentSlide = i;
break
}
}
}
return slides.eq(currentSlide)
}
if (!this.config.timeline) return this;
this._timeline = [];
for (var t = this.config.timeline, i = 0; i < t.length; i++) {
this._timeline.push({
time: parseTime(t[i]),
slide: parseSlide(t[i])
})
}
this._timeline.push({
time: 99999,
slide: t[0].slide
});
return this
},
_setupVideo: function() {
if (!this.config.video) {
this._setupDefaultTimeSource()
} else if (this.config.video.source === "vimeo") {
this._setupVimeoVideo(this.config.video)
} else {
throw "unknown video source, not supported"
}
return this
},
_setupDefaultTimeSource: function() {
var self = this,
t0 = (new Date).getTime();
setInterval(function() {
var t1 = (new Date).getTime();
self.setTime((t1 - t0) / 1e3)
}, 250)
},
_setupVimeoVideo: function(vid) {
var self = this,
vid = this.config.video,
downgrade = false;
if (window.location.protocol === "file:") {
"console" in window && console.log(
"vimeo video player api does not work with local files. Downgrading video support\nsee http://vimeo.com/api/docs/player-js"
);
downgrade = true
}
function loadFrame() {
var id = "p" + vid.id;
var frameSrc = '<iframe id="' + id + '" width="' + (vid.width || 360) + '" height="' + (vid.height || 203) +
'" frameborder="0" src="http://player.vimeo.com/video/' + vid.id + "?api=1&player_id=" + id + '">';
return $(frameSrc).appendTo(vid.parent || "body")[0]
}
if (downgrade) {
$(loadFrame()).bind("load", function() {
self._setupDefaultTimeSource()
})
} else {
$.getScript("http://a.vimeocdn.com/js/froogaloop2.min.js?", function() {
$f(loadFrame()).addEvent("ready", function(player_id) {
var vimeo = $f(player_id),
timer = false;
vimeo.addEvent("play", function(data) {
if (timer === false) {
timer = setInterval(function() {
vimeo.api("getCurrentTime", function(value, player_id) {
self.setTime(value)
})
}, 250)
}
});
vimeo.addEvent("pause", function(data) {
clearInterval(timer);
timer = false
});
vid.autoplay && vimeo.api("play")
})
})
}
},
_setupScrollHandler: function() {
var self = this,
slideSelector = self.config.slideTagName + (self.config.slideClass ? "." + self.config.slideClass : ""),
$scrollContainer = this.config.portable ? this.$portableContainer : $window,
isIOS = navigator.userAgent.match(/like Mac OS X/i) === null ? false : true,
$elem;
self.scrolling = false;
setInterval(function() {
if (self.scrolling && (self.isAutoScrolling === false || self.isAutoScrolling === undefined)) {
self.scrolling = false;
if ($scrollContainer.scrollLeft() === 0) {
self.activateSlide(self.$firstSlide)
} else {
var offsetX = self.config.portable ? $scrollContainer.position().left : 0,
offsetY = self.config.portable ? $scrollContainer.position().top : 0,
midpoint = {
x: offsetX + $scrollContainer.width() / 2 + (isIOS ? $window.scrollLeft() : 0),
y: offsetY + $scrollContainer.height() / 2 + (isIOS ? $window.scrollTop() : 0)
};
$elem = $(document.elementFromPoint(midpoint.x, midpoint.y));
if ($elem.is(slideSelector)) {
self.activateSlide($elem)
} else {
$elem = $elem.parents(slideSelector + ":first").each(function() {
self.activateSlide($(this))
})
}
}
}
}, self.config.onScrollInterval);
$scrollContainer.scroll(function() {
self.scrolling = true
});
return this
}
};
$.fn.fathom = function(options) {
new Fathom(this, options);
return this
};
Fathom.defaults = Fathom.prototype.defaults;
Fathom.setDefaults = function(options) {
$.extend(Fathom.defaults, options)
};
window.Fathom = Fathom
})(jQuery, window);

View File

@ -1,95 +0,0 @@
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
input:focus {
outline: 0;
}
#presentation {
vertical-align: top;
white-space: nowrap;
}
div.slide {
-webkit-box-shadow: 0 0 50px #c0c0c0;
-moz-box-shadow: 0 0 50px #c0c0c0;
box-shadow: 0 0 50px #c0c0c0;
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
border-radius: 20px;
-moz-background-clip: padding;
-webkit-background-clip: padding-box;
background-clip: padding-box;
display: inline-block;
height: 700px;
padding: 20px;
position: relative;
vertical-align: top;
width: 900px;
}
div.inactiveslide {
opacity: 0.4;
}
div.activeslide {
opacity: 1;
}
/* iPad */
@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
div.inactiveslide {
opacity: 1;
}
}
/* iPhone */
@media only screen and (max-device-width: 480px) {
div.inactiveslide {
opacity: 1;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,43 +0,0 @@
;(function()
{
// CommonJS
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
function Brush()
{
var keywords = 'if fi then elif else for do done until while break continue case function return in eq ne ge le';
var commands = 'alias apropos awk basename bash bc bg builtin bzip2 cal cat cd cfdisk chgrp chmod chown chroot' +
'cksum clear cmp comm command cp cron crontab csplit cut date dc dd ddrescue declare df ' +
'diff diff3 dig dir dircolors dirname dirs du echo egrep eject enable env ethtool eval ' +
'exec exit expand export expr false fdformat fdisk fg fgrep file find fmt fold format ' +
'free fsck ftp gawk getopts grep groups gzip hash head history hostname id ifconfig ' +
'import install join kill less let ln local locate logname logout look lpc lpr lprint ' +
'lprintd lprintq lprm ls lsof make man mkdir mkfifo mkisofs mknod more mount mtools ' +
'mv netstat nice nl nohup nslookup open op passwd paste pathchk ping popd pr printcap ' +
'printenv printf ps pushd pwd quota quotacheck quotactl ram rcp read readonly renice ' +
'remsync rm rmdir rsync screen scp sdiff sed select seq set sftp shift shopt shutdown ' +
'sleep sort source split ssh strace su sudo sum symlink sync tail tar tee test time ' +
'times touch top traceroute trap tr true tsort tty type ulimit umask umount unalias ' +
'uname unexpand uniq units unset unshar useradd usermod users uuencode uudecode v vdir ' +
'vi watch wc whereis which who whoami Wget xargs yes'
;
this.regexList = [
{ regex: /^#!.*$/gm, css: 'preprocessor bold' },
{ regex: /\/[\w-\/]+/gm, css: 'plain' },
{ regex: SyntaxHighlighter.regexLib.singleLinePerlComments, css: 'comments' }, // one line comments
{ regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings
{ regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, // keywords
{ regex: new RegExp(this.getKeywords(commands), 'gm'), css: 'functions' } // commands
];
}
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['bash', 'shell'];
SyntaxHighlighter.brushes.Bash = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();

View File

@ -1,52 +0,0 @@
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
;(function()
{
// CommonJS
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
function Brush()
{
var keywords = 'break case catch continue ' +
'default delete do else false ' +
'for function if in instanceof ' +
'new null return super switch ' +
'this throw true try typeof var while with'
;
var r = SyntaxHighlighter.regexLib;
this.regexList = [
{ regex: r.multiLineDoubleQuotedString, css: 'string' }, // double quoted strings
{ regex: r.multiLineSingleQuotedString, css: 'string' }, // single quoted strings
{ regex: r.singleLineCComments, css: 'comments' }, // one line comments
{ regex: r.multiLineCComments, css: 'comments' }, // multiline comments
{ regex: /\s*#.*/gm, css: 'preprocessor' }, // preprocessor tags like #region and #endregion
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keywords
];
this.forHtmlScript(r.scriptScriptTags);
};
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['js', 'jscript', 'javascript'];
SyntaxHighlighter.brushes.JScript = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();

View File

@ -1,54 +0,0 @@
;(function()
{
// CommonJS
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
function Brush()
{
function process(match, regexInfo)
{
var constructor = SyntaxHighlighter.Match,
code = match[0],
tag = new XRegExp('(&lt;|<)[\\s\\/\\?]*(?<name>[:\\w-\\.]+)', 'xg').exec(code),
result = []
;
if (match.attributes != null)
{
var attributes,
regex = new XRegExp('(?<name> [\\w:\\-\\.]+)' +
'\\s*=\\s*' +
'(?<value> ".*?"|\'.*?\'|\\w+)',
'xg');
while ((attributes = regex.exec(code)) != null)
{
result.push(new constructor(attributes.name, match.index + attributes.index, 'color1'));
result.push(new constructor(attributes.value, match.index + attributes.index + attributes[0].indexOf(attributes.value), 'string'));
}
}
if (tag != null)
result.push(
new constructor(tag.name, match.index + tag[0].indexOf(tag.name), 'keyword')
);
return result;
}
this.regexList = [
{ regex: new XRegExp('(\\&lt;|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\&gt;|>)', 'gm'), css: 'color2' }, // <![ ... [ ... ]]>
{ regex: SyntaxHighlighter.regexLib.xmlComments, css: 'comments' }, // <!-- ... -->
{ regex: new XRegExp('(&lt;|<)[\\s\\/\\?]*(\\w+)(?<attributes>.*?)[\\s\\/\\?]*(&gt;|>)', 'sg'), func: process },
{ regex: /^\[[0-9-]+\] [vV0-9\.]+$/gm, css: 'keyword value' }
];
};
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['xml', 'xhtml', 'xslt', 'html'];
SyntaxHighlighter.brushes.Xml = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();

View File

@ -1,226 +0,0 @@
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
.syntaxhighlighter a,
.syntaxhighlighter div,
.syntaxhighlighter code,
.syntaxhighlighter table,
.syntaxhighlighter table td,
.syntaxhighlighter table tr,
.syntaxhighlighter table tbody,
.syntaxhighlighter table thead,
.syntaxhighlighter table caption,
.syntaxhighlighter textarea {
-moz-border-radius: 0 0 0 0 !important;
-webkit-border-radius: 0 0 0 0 !important;
background: none !important;
border: 0 !important;
bottom: auto !important;
float: none !important;
height: auto !important;
left: auto !important;
line-height: 1.1em !important;
margin: 0 !important;
outline: 0 !important;
overflow: visible !important;
padding: 0 !important;
position: static !important;
right: auto !important;
text-align: left !important;
top: auto !important;
vertical-align: baseline !important;
width: auto !important;
box-sizing: content-box !important;
font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important;
font-weight: normal !important;
font-style: normal !important;
font-size: 1em !important;
min-height: inherit !important;
min-height: auto !important;
}
.syntaxhighlighter {
width: 100% !important;
margin: 1em 0 1em 0 !important;
position: relative !important;
overflow: auto !important;
font-size: 1em !important;
}
.syntaxhighlighter.source {
overflow: hidden !important;
}
.syntaxhighlighter .bold {
font-weight: bold !important;
}
.syntaxhighlighter .italic {
font-style: italic !important;
}
.syntaxhighlighter .line {
white-space: pre !important;
}
.syntaxhighlighter table {
width: 100% !important;
}
.syntaxhighlighter table caption {
text-align: left !important;
padding: .5em 0 0.5em 1em !important;
}
.syntaxhighlighter table td.code {
width: 100% !important;
}
.syntaxhighlighter table td.code .container {
position: relative !important;
}
.syntaxhighlighter table td.code .container textarea {
box-sizing: border-box !important;
position: absolute !important;
left: 0 !important;
top: 0 !important;
width: 100% !important;
height: 100% !important;
border: none !important;
background: white !important;
padding-left: 1em !important;
overflow: hidden !important;
white-space: pre !important;
}
.syntaxhighlighter table td.gutter .line {
text-align: right !important;
padding: 0 0.5em 0 1em !important;
}
.syntaxhighlighter table td.code .line {
padding: 0 1em !important;
}
.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line {
padding-left: 0em !important;
}
.syntaxhighlighter.show {
display: block !important;
}
.syntaxhighlighter.collapsed table {
display: none !important;
}
.syntaxhighlighter.collapsed .toolbar {
padding: 0.1em 0.8em 0em 0.8em !important;
font-size: 1em !important;
position: static !important;
width: auto !important;
height: auto !important;
}
.syntaxhighlighter.collapsed .toolbar span {
display: inline !important;
margin-right: 1em !important;
}
.syntaxhighlighter.collapsed .toolbar span a {
padding: 0 !important;
display: none !important;
}
.syntaxhighlighter.collapsed .toolbar span a.expandSource {
display: inline !important;
}
.syntaxhighlighter .toolbar {
position: absolute !important;
right: 1px !important;
top: 1px !important;
width: 11px !important;
height: 11px !important;
font-size: 10px !important;
z-index: 10 !important;
}
.syntaxhighlighter .toolbar span.title {
display: inline !important;
}
.syntaxhighlighter .toolbar a {
display: block !important;
text-align: center !important;
text-decoration: none !important;
padding-top: 1px !important;
}
.syntaxhighlighter .toolbar a.expandSource {
display: none !important;
}
.syntaxhighlighter.ie {
font-size: .9em !important;
padding: 1px 0 1px 0 !important;
}
.syntaxhighlighter.ie .toolbar {
line-height: 8px !important;
}
.syntaxhighlighter.ie .toolbar a {
padding-top: 0px !important;
}
.syntaxhighlighter.printing .line.alt1 .content,
.syntaxhighlighter.printing .line.alt2 .content,
.syntaxhighlighter.printing .line.highlighted .number,
.syntaxhighlighter.printing .line.highlighted.alt1 .content,
.syntaxhighlighter.printing .line.highlighted.alt2 .content {
background: none !important;
}
.syntaxhighlighter.printing .line .number {
color: #bbbbbb !important;
}
.syntaxhighlighter.printing .line .content {
color: black !important;
}
.syntaxhighlighter.printing .toolbar {
display: none !important;
}
.syntaxhighlighter.printing a {
text-decoration: none !important;
}
.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a {
color: black !important;
}
.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a {
color: #008200 !important;
}
.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a {
color: blue !important;
}
.syntaxhighlighter.printing .keyword {
color: #006699 !important;
font-weight: bold !important;
}
.syntaxhighlighter.printing .preprocessor {
color: gray !important;
}
.syntaxhighlighter.printing .variable {
color: #aa7700 !important;
}
.syntaxhighlighter.printing .value {
color: #009900 !important;
}
.syntaxhighlighter.printing .functions {
color: #ff1493 !important;
}
.syntaxhighlighter.printing .constants {
color: #0066cc !important;
}
.syntaxhighlighter.printing .script {
font-weight: bold !important;
}
.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a {
color: gray !important;
}
.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a {
color: #ff1493 !important;
}
.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a {
color: red !important;
}
.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a {
color: black !important;
}

File diff suppressed because one or more lines are too long

View File

@ -1,128 +0,0 @@
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
.syntaxhighlighter {
background-color: white !important;
}
.syntaxhighlighter .line.alt1 {
background-color: white !important;
}
.syntaxhighlighter .line.alt2 {
background-color: white !important;
}
.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 {
background-color: #c3defe !important;
}
.syntaxhighlighter .line.highlighted.number {
color: white !important;
}
.syntaxhighlighter table caption {
color: black !important;
}
.syntaxhighlighter .gutter {
color: #787878 !important;
}
.syntaxhighlighter .gutter .line {
border-right: 3px solid #d4d0c8 !important;
}
.syntaxhighlighter .gutter .line.highlighted {
background-color: #d4d0c8 !important;
color: white !important;
}
.syntaxhighlighter.printing .line .content {
border: none !important;
}
.syntaxhighlighter.collapsed {
overflow: visible !important;
}
.syntaxhighlighter.collapsed .toolbar {
color: #3f5fbf !important;
background: white !important;
border: 1px solid #d4d0c8 !important;
}
.syntaxhighlighter.collapsed .toolbar a {
color: #3f5fbf !important;
}
.syntaxhighlighter.collapsed .toolbar a:hover {
color: #aa7700 !important;
}
.syntaxhighlighter .toolbar {
color: #a0a0a0 !important;
background: #d4d0c8 !important;
border: none !important;
}
.syntaxhighlighter .toolbar a {
color: #a0a0a0 !important;
}
.syntaxhighlighter .toolbar a:hover {
color: red !important;
}
.syntaxhighlighter .plain, .syntaxhighlighter .plain a {
color: black !important;
}
.syntaxhighlighter .comments, .syntaxhighlighter .comments a {
color: #3f5fbf !important;
}
.syntaxhighlighter .string, .syntaxhighlighter .string a {
color: #2a00ff !important;
}
.syntaxhighlighter .keyword {
color: #7f0055 !important;
}
.syntaxhighlighter .preprocessor {
color: #646464 !important;
}
.syntaxhighlighter .variable {
color: #aa7700 !important;
}
.syntaxhighlighter .value {
color: #009900 !important;
}
.syntaxhighlighter .functions {
color: #ff1493 !important;
}
.syntaxhighlighter .constants {
color: #0066cc !important;
}
.syntaxhighlighter .script {
font-weight: bold !important;
color: #7f0055 !important;
background-color: none !important;
}
.syntaxhighlighter .color1, .syntaxhighlighter .color1 a {
color: gray !important;
}
.syntaxhighlighter .color2, .syntaxhighlighter .color2 a {
color: #ff1493 !important;
}
.syntaxhighlighter .color3, .syntaxhighlighter .color3 a {
color: red !important;
}
.syntaxhighlighter .keyword {
font-weight: bold !important;
}
.syntaxhighlighter .xml .keyword {
color: #3f7f7f !important;
font-weight: normal !important;
}
.syntaxhighlighter .xml .color1, .syntaxhighlighter .xml .color1 a {
color: #7f007f !important;
}
.syntaxhighlighter .xml .string {
font-style: italic !important;
color: #2a00ff !important;
}

View File

@ -1,18 +0,0 @@
.syntaxhighlighter a, .syntaxhighlighter div, .syntaxhighlighter code, .syntaxhighlighter table, .syntaxhighlighter table td, .syntaxhighlighter table tr, .syntaxhighlighter table tbody, .syntaxhighlighter table thead, .syntaxhighlighter table caption, .syntaxhighlighter textarea{line-height: 1.3em !important;}
.syntaxhighlighter {overflow-y: hidden !important;}
.syntaxhighlighter .toolbar{background: none!important;}
.syntaxhighlighter .toolbar a{display: none!important;}
.syntaxhighlighter .line.alt1,.syntaxhighlighter .line.alt2{background-color: #FAFAFA !important;}
.syntaxhighlighter{background-color: #FAFAFA !important; padding: 10px; width: calc(100% - 20px) !important; border-radius: 5px;}
/* div.slide{width: 90vw; overflow: auto;} */
h3{font-size: 20px; font-weight: bold; margin-bottom: 20px;}
.dcode{margin-top: 100px;}
.mt10{margin-top: 10px;}
p{font-size: 14px; color: #5e6d82; line-height: 1.5em;margin: 15px 0 10px;}
a{color: #409eff; text-decoration: none;}
#content{height: calc(100vh - 99px); overflow: auto; padding: 10px 50px;}
/* #header{left: 5vw; right: 5vw; top: 20px; position: fixed;} */
#header{padding: 20px 50px; background-color: #0B0D10; top: 0; left: 0; right: 0; z-index: 99999; border-bottom: 1px solid #DCDFE5;}
#header xm-select{background-color: #17191C; color: #FFF;}
body{margin: 0;}

21
docs/index.ejs Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<% for (var chunk in htmlWebpackPlugin.files.css) { %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.css[chunk] %>" as="style">
<% } %>
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>" as="script">
<% } %>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<!-- <link rel="stylesheet" href="//shadow.elemecdn.com/npm/highlight.js@9.3.0/styles/color-brewer.css"> -->
<!-- <link rel="stylesheet" href="//shadow.elemecdn.com/npm/element-ui@2.12.0/lib/theme-chalk/index.css"> -->
<title>xm-select</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@ -1,64 +0,0 @@
var htmls = [], js = [];
data.forEach(function(item, index){
htmls.push([
'<div class="slide" id="XM'+index+'">',
item.html,
'<div class="dcode mt10"><script type="syntaxhighlighter" class="brush:html"><![CDATA[',
item.comment ? item.comment.replace(/</g, '&lt;') : item.html.replace(/</g, '&lt;'),
']]></script></div>',
item.js && ['<div class="dcode mt10"><script type="syntaxhighlighter" class="brush:js"><![CDATA[',
item.js.replace(/</g, '&lt;'),
']]></script></div>'].join(''),
'</div>',
].join(''));
js.push(item.js);
});
var box = $('#content');
box.append($(htmls.join('')));
// var box = document.getElementById('content');
js.forEach(function(item){
eval(item);
});
SyntaxHighlighter.defaults["quick-code"] = false;
SyntaxHighlighter.defaults["gutter"] = false;
SyntaxHighlighter.all();
// var ele = new Fathom('#content')
xmSelect.render({
el: '#header',
data: data.map(function(item, index){
return {
name: (index + 1) + '. ' + item.title,
value: index,
empty: !!item.title
}
}).filter(function(item){
return item.empty;
}),
filterable: true,
model: {
label: {
type: 'text',
text: {
left: '',
right: '',
separator: ', ',
},
},
},
radio: true,
clickClose: true,
on: function(data){
window.location.hash = '#XM' + data.item.value;
}
});
var hash = window.location.hash;
window.location.hash = '';
window.location.hash = hash;

3
docs/jquery.min.js vendored

File diff suppressed because one or more lines are too long

26
docs/mds/XM01.md Normal file
View File

@ -0,0 +1,26 @@
## 基础使用
:::tip
只需引入`xm-select.js`, 剩下的就只有渲染了
:::
### 一个小栗子
:::demo `el`绑定的不一定是id, 也可以是其他css选择器
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::

28
docs/mds/XM02.md Normal file
View File

@ -0,0 +1,28 @@
## 国际化
### 英语
:::demo 目前仅支持`中文`和`英文`, 如需更多语言, 可以`clone`代码进行二次开发
```html
<div id="demo1" class="xm-select-demo"></div>
<div xid="demo2" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
language: 'en',
data: []
})
var demo2 = xmSelect.render({
el: '[xid=demo2]',
language: 'en',
data: [
{name: 'apple', value: 1},
{name: 'banana', value: 2},
{name: 'orange', value: 3},
]
})
</script>
```
:::

47
docs/mds/XM03.md Normal file
View File

@ -0,0 +1,47 @@
## 默认选中
### 使用`selected`属性
:::demo 当然`selected`是选中, `disabled`是禁用
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 使用initValue进行初始化
:::demo `initValue`的优先级大于选项中的`selected`
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo5 = xmSelect.render({
el: '#demo1',
initValue: [4],
data: [
{name: '水果', value: 1, selected: true, disabled: true},
{name: '蔬菜', value: 2, selected: true},
{name: '桌子', value: 3, disabled: true},
{name: '北京', value: 4},
]
})
</script>
```
:::

64
docs/mds/XM04.md Normal file
View File

@ -0,0 +1,64 @@
## 修改提示
### 修改选项提示文字
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
tips: '你喜欢什么水果呢?',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 修改空数据提示文字
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
empty: '呀, 没有数据呢',
data: [ ]
})
</script>
```
:::
### 修改搜索提示文字
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
filterable: true,
searchTips: '你想吃什么水果吧',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::

118
docs/mds/XM05.md Normal file
View File

@ -0,0 +1,118 @@
## 搜索模式
### 默认搜索
:::demo 默认按照`name`进行搜索
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
filterable: true,
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 重写搜索方法
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
filterable: true,
filterMethod: function(val, item, index, prop){
if(val == item.value){//把value相同的搜索出来
return true;
}
if(item.name.indexOf(val) != -1){//名称中包含的搜索出来
return true;
}
return false;//不知道的就不管了
},
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 搜索延迟
为了提高有效搜索, 当停止输入`500ms`后才开始进行过滤搜索, 当然这个`500`你也可以进行修改
:::demo `delay: 2000` 输入停止2s后进行搜索过滤
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
filterable: true,
delay: 2000,
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 自定义搜索 (远程搜索)
第一步: 需要先开启搜索 `filterable: true,`
第二步: 开启自定义搜索 `remoteSearch: true`
第三部: 重写搜索回调
简单吧, 记得Star ^_^
:::demo `render`后, 就会进行一次回调, 用于渲染第一次数据
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
filterable: true,
remoteSearch: true,
remoteMethod: function(val, cb){
//这里模拟3s后返回数据
setTimeout(function(){
//需要回传一个数组
cb([
{name: '水果' + val, value: val + 1},
{name: '蔬菜' + val, value: val + 2},
{name: '桌子' + val, value: val + 3},
{name: '北京' + val, value: val + 4},
])
}, 3000)
},
data: []
})
</script>
```
:::

69
docs/mds/XM06.md Normal file
View File

@ -0,0 +1,69 @@
## 下拉方向
### 自动`auto`
:::demo
```html
<div style="height: 500px">占位div, 演示效果使用, 底部空间不足时会自动向上展开</div>
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
direction: 'auto',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 打卡向上`up`
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
direction: 'up',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::
### 打开向下`down`
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
direction: 'down',
data: [
{name: '水果', value: 1},
{name: '蔬菜', value: 2},
{name: '桌子', value: 3},
{name: '北京', value: 4},
]
})
</script>
```
:::

48
docs/mds/XM07.md Normal file
View File

@ -0,0 +1,48 @@
## 自定义样式
### 随便试试
修改一下背景色和外边距吧
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
style: {
backgroundColor: 'red',
marginLeft: '200px',
},
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 修改下拉框的最大高度
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
height: '50px',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::

110
docs/mds/XM08.md Normal file
View File

@ -0,0 +1,110 @@
## 分页
### 启用分页
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
paging: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::
### 自定义条数
每页3条
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
paging: true,
pageSize: 3,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
{name: '赵六', value: 4},
{name: '苹果', value: 5},
{name: '香蕉', value: 6},
{name: '凤梨', value: 7},
{name: '葡萄', value: 8},
{name: '樱桃', value: 9},
{name: '车厘子', value: 10},
{name: '火龙果', value: 11},
]
})
</script>
```
:::
### 搜索+分页
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<button class="btn" id="demo3-5">每页5条</button>
<button class="btn" id="demo3-10">每页10条</button>
<button class="btn" id="demo3-20">每页20条</button>
<script>
var data = [];
for(var i = 0 ; i < 100 ; i++ ){
data.push({
name: '测试数据' + i,
value: i,
})
}
var demo3 = xmSelect.render({
el: '#demo3',
paging: true,
pageSize: 5,
filterable: true,
data
})
document.getElementById('demo3-5').onclick = function(){
demo3.update({
pageSize: 5
})
}
document.getElementById('demo3-10').onclick = function(){
demo3.update({
pageSize: 10
})
}
document.getElementById('demo3-20').onclick = function(){
demo3.update({
pageSize: 20
})
}
</script>
```
:::

79
docs/mds/XM09.md Normal file
View File

@ -0,0 +1,79 @@
## 单选
### 开启单选
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
radio: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 单选完关闭下拉
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
radio: true,
clickClose: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 更换显示方式
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
radio: true,
clickClose: true,
model: {
label: {
type: 'text',
text: {
//左边拼接的字符
left: '',
//右边拼接的字符
right: '',
//中间的分隔符
separator: ', ',
},
}
},
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::

83
docs/mds/XM10.md Normal file
View File

@ -0,0 +1,83 @@
## 重复选
### 开启重复选
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
repeat: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 重复选完关闭下拉
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
repeat: true,
clickClose: true,
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 更换显示方式
:::demo 好像这样只能增不能减了~~ 有待完善
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
repeat: true,
model: {
label: {
type: 'count',
count: {
template: function(data, sels){
var res = {};
sels.forEach(item => {
var name = item.name;
!res[name] && (res[name] = 0);
res[name] += 1;
});
return Object.keys(res).map(key => {
return `${key} (${res[key]})`
}).join(',');
}
},
}
},
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::

35
docs/mds/XM11.md Normal file
View File

@ -0,0 +1,35 @@
## 自定义属性
### 更换属性key
也许你的数据库返回的并不是`name`和`value`, 也许你提交的时候不止`name`和`value`, 怎么办? 自定义就行
:::demo 我的`name`是`label`, 我的`value`是`id`, 我有其他属性`group`
```html
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" id="demo1-getValue">获取选中值</button>
<pre id="demo1-value"></pre>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
prop: {
name: 'label',
value: 'id',
},
data: [
{label: '张三', id: 1, group: 1},
{label: '李四', id: 2, group: 1},
{label: '王五', id: 3, group: 2},
]
})
document.getElementById('demo1-getValue').onclick = function(){
//获取当前多选选中的值
var selectArr = demo1.getValue();
document.getElementById('demo1-value').innerHTML = JSON.stringify(selectArr, null, 2);
}
</script>
```
:::

329
docs/mds/XM12.md Normal file
View File

@ -0,0 +1,329 @@
## 主题
### 经典绿 ( #009688 )
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 嫣红 ( #e54d42 )
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
theme: {
color: '#e54d42',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 桔橙 ( #f37b1d )
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
theme: {
color: '#f37b1d',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 明黄 ( #fbbd08 )
:::demo
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
theme: {
color: '#fbbd08',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 橄榄 ( #8dc63f )
:::demo
```html
<div id="demo5" class="xm-select-demo"></div>
<script>
var demo5 = xmSelect.render({
el: '#demo5',
theme: {
color: '#8dc63f',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 天青 ( #1cbbb4 )
:::demo
```html
<div id="demo6" class="xm-select-demo"></div>
<script>
var demo6 = xmSelect.render({
el: '#demo6',
theme: {
color: '#1cbbb4',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 海蓝 ( #0081ff )
:::demo
```html
<div id="demo7" class="xm-select-demo"></div>
<script>
var demo7 = xmSelect.render({
el: '#demo7',
theme: {
color: '#0081ff',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 姹紫 ( #6739b6 )
:::demo
```html
<div id="demo8" class="xm-select-demo"></div>
<script>
var demo8 = xmSelect.render({
el: '#demo8',
theme: {
color: '#6739b6',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 木槿 ( #9c26b0 )
:::demo
```html
<div id="demo9" class="xm-select-demo"></div>
<script>
var demo9 = xmSelect.render({
el: '#demo9',
theme: {
color: '#9c26b0',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 桃粉 ( #e03997 )
:::demo
```html
<div id="demo10" class="xm-select-demo"></div>
<script>
var demo10 = xmSelect.render({
el: '#demo10',
theme: {
color: '#e03997',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 棕褐 ( #a5673f )
:::demo
```html
<div id="demo11" class="xm-select-demo"></div>
<script>
var demo11 = xmSelect.render({
el: '#demo11',
theme: {
color: '#a5673f',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 玄灰 ( #8799a3 )
:::demo
```html
<div id="demo12" class="xm-select-demo"></div>
<script>
var demo12 = xmSelect.render({
el: '#demo12',
theme: {
color: '#8799a3',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 草灰 ( #aaaaaa )
:::demo
```html
<div id="demo13" class="xm-select-demo"></div>
<script>
var demo13 = xmSelect.render({
el: '#demo13',
theme: {
color: '#aaaaaa',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 墨黑 ( #333333 )
:::demo
```html
<div id="demo14" class="xm-select-demo"></div>
<script>
var demo14 = xmSelect.render({
el: '#demo14',
theme: {
color: '#333333',
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
</script>
```
:::
:::warning
颜色值来源于[ColorUI](https://github.com/weilanwl/ColorUI), 有兴趣的可以看看
:::

63
docs/mds/XM13.md Normal file
View File

@ -0,0 +1,63 @@
## 显示与隐藏
### 主动打开/关闭下拉框
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" id="demo1-open">打开下拉框</button>
<button class="btn" id="demo1-close">关闭下拉框</button>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
document.getElementById('demo1-open').onclick = function(){
//这里延迟1S, 是因为, 点击下拉框外边的位置 会出发关闭事件, 所以延迟演示效果
setTimeout(function(){
demo1.opened();
}, 1000);
}
document.getElementById('demo1-close').onclick = function(){
//先点一下关闭, 然后把下拉框点开, 3S后会自动关闭
setTimeout(function(){
demo1.closed();
}, 3000);
}
</script>
```
:::
### 监听打开/关闭下拉框
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
],
show(){
alert('打开了')
},
hide(){
alert('关闭了')
}
})
</script>
```
:::

178
docs/mds/XM14.md Normal file
View File

@ -0,0 +1,178 @@
## 显示方式
### 方块形状
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 方块形状, 隐藏删除图标
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
model: {
label: {
type: 'block',
block: {
//最大显示数量, 0:不限制
showCount: 0,
//是否显示删除图标
showIcon: false,
}
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 方块形状, 超过1个隐藏
:::demo
```html
<div id="demo3" class="xm-select-demo"></div>
<script>
var demo3 = xmSelect.render({
el: '#demo3',
model: {
label: {
type: 'block',
block: {
//最大显示数量, 0:不限制
showCount: 1,
//是否显示删除图标
showIcon: true,
}
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
]
})
</script>
```
:::
### 简单拼接形式
:::demo
```html
<div id="demo4" class="xm-select-demo"></div>
<script>
var demo4 = xmSelect.render({
el: '#demo4',
model: {
label: {
type: 'text',
//使用字符串拼接的方式
text: {
//左边拼接的字符
left: '【',
//右边拼接的字符
right: '】',
//中间的分隔符
separator: '',
},
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
],
})
</script>
```
:::
### 自定义显示
:::demo
```html
<div id="demo5" class="xm-select-demo"></div>
<script>
var demo5 = xmSelect.render({
el: '#demo5',
model: {
label: {
type: 'xxxx', //自定义与下面的对应
xxxx: {
template(data, sels){
return "已选中 " + sels.length + " 项, 共 " + data.length + " 项"
}
},
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
],
})
</script>
```
:::
### 自定义显示HTML
:::demo
```html
<div id="demo6" class="xm-select-demo"></div>
<script>
var demo6 = xmSelect.render({
el: '#demo6',
model: {
label: {
type: 'xxxx', //自定义与下面的对应
xxxx: {
template(data, sels){
//也可以是html
return `<div style="color: red;">${sels.length} / ${data.length}</div>`
}
},
}
},
data: [
{name: '张三', value: 1, selected: true},
{name: '李四', value: 2, selected: true},
{name: '王五', value: 3},
],
})
</script>
```
:::

44
docs/mds/XM15.md Normal file
View File

@ -0,0 +1,44 @@
## 构建选项
### 默认渲染
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
data: [
{name: '张三', value: 'zhangsan', selected: true},
{name: '李四', value: 'lisi', selected: true},
{name: '王五', value: 'wangwu'},
]
})
</script>
```
:::
### 自定义渲染
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
template({ item, sels, name, value }){
return name + '<span style="position: absolute; right: 10px; color: #8799a3">'+value+'</span>'
},
data: [
{name: '张三', value: 'zhangsan', selected: true},
{name: '李四', value: 'lisi', selected: true},
{name: '王五', value: 'wangwu'},
]
})
</script>
```
:::

56
docs/mds/XM16.md Normal file
View File

@ -0,0 +1,56 @@
## 监听选择
### 实时监听
实时监听多选的选中状态变化
:::demo
```html
<div id="demo1" class="xm-select-demo"></div>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
on({ arr, item, selected }){
alert(`name: ${item.name}, 状态: ${selected}`)
},
data: [
{name: '张三', value: 'zhangsan', selected: true},
{name: '李四', value: 'lisi', selected: true},
{name: '王五', value: 'wangwu'},
]
})
</script>
```
:::
### 监听动态复制
选中北京后, 不能选中上海, 二者互斥
:::demo
```html
<div id="demo2" class="xm-select-demo"></div>
<script>
var demo2 = xmSelect.render({
el: '#demo2',
on({ arr, item, selected }){
if(selected){
var index = arr.findIndex(i => i.mutex == item.mutex && i.value != item.value);
if(index != -1){
arr.splice(index, 1);
}
}
},
data: [
{name: '北京', value: 1, mutex: 1, selected: true},
{name: '上海', value: 2, mutex: 1},
{name: '广州', value: 3},
]
})
</script>
```
:::

57
docs/mds/XM17.md Normal file
View File

@ -0,0 +1,57 @@
## 性能测试
### 数据渲染耗时测试
:::demo 事实证明分页是好使的 ^_^
```html
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" id="demo1-test1">测试1000条</button>
<button class="btn" id="demo1-test2">测试10000条</button>
<button class="btn" id="demo1-test3">测试10000条+分页</button>
<pre id="demo1-result"></pre>
<script>
function run(count, paging){
//生成数据
var data = [];
for(var i = 0; i < count; i++){
data.push({
name: '测试数据' + i,
value: i,
})
}
//记录开始渲染时间
var startTime = Date.now();
var demo1 = xmSelect.render({
el: '#demo1',
paging,
data
})
//记录结束时间
var endTime = Date.now();
document.getElementById('demo1-result').innerText = `渲染耗时: ${endTime - startTime} ms`
}
document.getElementById('demo1-test1').onclick = function(){
run(1000, false)
};
document.getElementById('demo1-test2').onclick = function(){
run(10000, false)
};
document.getElementById('demo1-test3').onclick = function(){
run(10000, true)
};
run(1000, false);
</script>
```
:::

72
docs/mds/install.md Normal file
View File

@ -0,0 +1,72 @@
## 安装
### 简介
:::tip
基于 [layui](https://layui.com) 的一个多选解决方案。前身 [formSelects](https://github.com/hnzzmsf/layui-formSelects/)经历了4个大版本的更新迭代移除了对 `jquery` 的依赖,以一种全新的面貌诞生了。
:::
- 唯一依赖库[preactjs](https://preactjs.com/)
- 打包方式[webpack](https://www.webpackjs.com/)
- 文档借鉴于[ElementUI](https://element.eleme.cn/#/zh-CN)的编写方式
- [Fly社区交流贴](https://fly.layui.com/jie/57776/)
- QQ交流群: `660408068`
> 作者: maplemei, 热爱前端的Java程序猿, 如果喜欢作者的插件, 可以请作者吃雪糕 ^_^
<p>
<a href="javascript:;">
<img src="../assets/wx.jpg" alt="打赏" width="300">
</a>
</p>
### 下载
[![star](https://gitee.com/maplemei/xm-select/badge/star.svg?theme=dark)](https://gitee.com/maplemei/xm-select/stargazers)
[![fork](https://gitee.com/maplemei/xm-select/badge/fork.svg?theme=dark)](https://gitee.com/maplemei/xm-select/members)
[https://gitee.com/maplemei/xm-select](https://gitee.com/maplemei/xm-select)
### 二次开发
```
$ git clone https://gitee.com/maplemei/xm-select.git
$ cd xm-select
$ npm install && npm run dev
```
### Hello World
:::demo 只需引入`xm-select.js`
```html
<div id="demo1" class="xm-select-demo"></div>
<button class="btn" id="demo1-getValue">获取选中值</button>
<pre id="demo1-value"></pre>
<script>
var demo1 = xmSelect.render({
el: '#demo1',
language: 'zn',
data: [
{name: '张三', value: 1},
{name: '李四', value: 2},
{name: '王五', value: 3},
]
})
document.getElementById('demo1-getValue').onclick = function(){
//获取当前多选选中的值
var selectArr = demo1.getValue();
document.getElementById('demo1-value').innerHTML = JSON.stringify(selectArr, null, 2);
}
</script>
```
:::

107
docs/mds/options.md Normal file
View File

@ -0,0 +1,107 @@
## 配置项与方法
### 配置项
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------- | ------------------------------ | --------------- | ------ | ------ |
| el | 渲染对象, css选择器 | string | - | - |
| language | 语言选择 | string | zn / en | zn |
| data | 显示的数据 | array | - | [ ] |
| initValue | 初始化选中的数据, 需要在data中存在 | array | - | null |
| tips | 默认提示, 类似于placeholder | string | - | 请选择 |
| empty | 空数据提示 | string | - | 暂无数据 |
| filterable | 是否开启搜索 | boolean | true / false | false |
| searchTips | 搜索提示 | string | - | 请选择 |
| delay | 搜索延迟 ms | int | - | 500 |
| filterMethod | 搜索回调函数 | function(val, item, index, prop) val: 当前搜索值, item: 每个option选项, index: 位置数据中的下标, prop: 定义key | - | - |
| remoteSearch | 是否开启自定义搜索 (远程搜索)| boolean | true / false | false |
| remoteMethod | 自定义搜索回调函数 | function(val, cb) val: 当前搜索值, cb: 回调函数, 需要回调一个数组, 结构同data | - | - |
| direction | 下拉方向| string | auto / up / down | auto |
| style | 自定义样式| object | - | { } |
| height | 默认最大高度| string | - | 200px |
| paging | 是否开启自定义分页 | boolean | true / false | false |
| pageSize | 分页条数 | int | - | 10 |
| radio | 是否开启单选模式 | boolean | true / false | false |
| repeat | 是否开启重复性模式 | boolean | true / false | false |
| clickClose | 是否点击选项后自动关闭下拉框 | boolean | true / false | false |
| prop | 自定义属性名称, 具体看下表 | object | - | |
| theme | 主题配置, 具体看下表 | object | - | |
| model | 模型, 多选的展示方式, 具体见下表 | object | - | |
| show | 展开下拉的回调 | function | - | - |
| hide | 隐藏下拉的回调 | function | - | - |
| template | 自定义渲染选项 | function({ item, sels, name, value }) | - | - |
| on | 监听选中变化 | function({ arr, item, selected }) | - | - |
### prop
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------- | ------------------------------ | --------------- | ------ | ------ |
| name | 显示名称 | string | - | name |
| value | 选中值 | string | - | value |
| selected | 是否选中 | string | - | selected |
| disabled | 是否警用 | string | - | disabled |
### theme
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------- | ------------------------------ | --------------- | ------ | ------ |
| color | 颜色 | string | - | #009688 |
### model
目前仅配置label即可
```
model: {
label: {
//使用方式
type: 'block',
//使用字符串拼接的方式
text: {
//左边拼接的字符
left: '',
//右边拼接的字符
right: '',
//中间的分隔符
separator: ', ',
},
//使用方块显示
block: {
//最大显示数量, 0:不限制
showCount: 0,
//是否显示删除图标
showIcon: true,
},
//自定义文字
count: {
//函数处理
template(data, sels){
//data: 所有的数据
//sels: 选中的数据
return `已选中 ${sels.length} 项, 共 ${data.length} 项`
}
},
},
},
```
### 方法
:::warning
xmSelect.render()后会返回一个xmSelect对象, 可以进行方法调用
:::
| 事件名 | 说明 | 参数 |
| ------ | ------------------ | -------- |
| getValue | 获取当前选中的数据 | - |
| setValue | 动态设置数据 | array: 选中的数据, show: 是否展开下拉 |
| opened | 主动展开下拉 | - |
| closed | 主动关闭下拉 | - |
| render | 重新渲染多选 | (options):见配置项 |
| reset | 重置为上一次的render状态 | - |
| update | 更新多选选中, reset不保留 | - |

17
docs/mds/question.md Normal file
View File

@ -0,0 +1,17 @@
## 常见问题
### 1.在哪里下载
[Gitee码云下载](https://gitee.com/maplemei/xm-select), 使用时引入`xm-select.js`即可, 具体请看[入门指南](/#/component/install)
### 2.为什么多选不显示
重要的事情说三遍, 需要渲染, 需要渲染, 需要渲染
### 3.渲染后还是不显示
打开控制台查看是否报错, 加群: 660408068, 询问

188
docs/pages/changelog.vue Normal file
View File

@ -0,0 +1,188 @@
<template>
<div class="page-changelog">
<div class="heading">
<el-button class="fr">
<a href="https://gitee.com/maplemei/xm-select" target="_blank">Gitee</a>
</el-button>
更新日志
</div>
<ul class="timeline" ref="timeline"></ul>
<change-log ref="changeLog"></change-log>
</div>
</template>
<script>
import ChangeLog from '../../CHANGELOG.md';
export default {
components: { ChangeLog },
data() {
return {
count: 3
};
},
mounted() {
const changeLog = this.$refs.changeLog;
const changeLogNodes = changeLog.$el.children;
let a = changeLogNodes[1].querySelector('a');
a && a.remove();
let release = changeLogNodes[1].textContent.trim();
let fragments =
`<li><h3><a href="javascript:;">${release}</a></h3>`;
for (let len = changeLogNodes.length, i = 2; i < len; i++) {
let node = changeLogNodes[i];
a = changeLogNodes[i].querySelector('a');
a && a.getAttribute('class') === 'header-anchor' && a.remove();
if (node.tagName !== 'H3') {
fragments += changeLogNodes[i].outerHTML;
} else {
release = changeLogNodes[i].textContent.trim();
fragments +=
`</li><li><h3><a href="javascript:;">${release}</a></h3>`;
}
}
// fragments = fragments.replace(/#(\d+)/g,
// '<a href="https://github.com/ElemeFE/element/issues/$1" target="_blank">#$1</a>');
// fragments = fragments.replace(/@(\w+)/g, '<a href="https://github.com/$1" target="_blank">@$1</a>');
this.$refs.timeline.innerHTML = `${fragments}</li>`;
changeLog.$el.remove();
}
};
</script>
<style lang="less">
.page-changelog {
padding-bottom: 100px;
.fr {
float: right;
padding: 0;
&.el-button {
transform: translateY(-3px);
}
a {
display: block;
padding: 10px 15px;
color: #333;
}
&:hover a {
color: #409EFF;
}
}
.heading {
font-size: 24px;
margin-bottom: 60px;
color: #333;
}
.timeline {
padding: 0;
padding-bottom: 10px;
position: relative;
color: #5e6d82;
>li {
position: relative;
padding-bottom: 15px;
list-style: none;
line-height: 1.8;
border: 1px solid #ddd;
border-radius: 4px;
&:not(:last-child) {
margin-bottom: 50px;
}
}
ul {
padding: 30px 30px 15px;
ul {
padding: 0;
padding-top: 5px;
padding-left: 27px;
li {
padding-left: 0;
color: #555;
word-break: normal;
}
li::before {
content: '';
circle: 4px #fff;
border: solid 1px #333;
margin-right: -12px;
display: inline-block;
vertical-align: middle;
}
}
}
li li {
font-size: 16px;
list-style: none;
padding-left: 20px;
padding-bottom: 5px;
color: #333;
word-break: break-all;
&:before {
content: '';
circle: 6px #333;
transform: translateX(-20px);
display: inline-block;
vertical-align: middle;
}
}
i {
padding: 0 20px;
display: inline-block;
}
h3 {
margin: 0;
padding: 15px 30px;
border-bottom: 1px solid #ddd;
font-size: 20px;
color: #333;
font-weight: bold;
a {
opacity: 1;
font-size: 20px;
float: none;
margin-left: 0;
color: #333;
}
}
h4 {
margin: 0;
margin-bottom: -10px;
font-size: 18px;
padding-left: 54px;
padding-top: 30px;
font-weight: bold;
}
p {
margin: 0;
}
em {
position: absolute;
right: 30px;
font-style: normal;
top: 23px;
font-size: 16px;
color: #666;
}
}
}
</style>

73
docs/router.js Normal file
View File

@ -0,0 +1,73 @@
import Component from './components/component.vue';
function importVue(path) {
return r => require.ensure([], () => r(require(`./pages${path}.vue`)));
}
function importMd(path) {
return r => require.ensure([], () => r(require(`./mds${path}.md`)));
}
export default [{
path: '*',
hidden: true,
redirect: '/',
},{
path: '/',
name: '/',
hidden: true,
redirect: '/component',
}, {
path: '/changelog',
name: '更新日志',
component: importVue('/changelog'),
}, {
path: '/add',
name: 'QQ群: 660408068',
redirect: '/',
}, {
path: '/component',
name: '入门指南',
redirect: '/component/install',
component: Component,
children: [{
path: 'install',
name: '安装与使用',
component: importMd('/install'),
}, {
path: 'options',
name: '配置项与方法',
component: importMd('/options'),
}]
}, {
path: '/example',
name: '示例',
redirect: '/example/XM01',
component: Component,
children: [
{ path: '/example/XM01', name: '基础使用', component: importMd('/XM01') },
{ path: '/example/XM02', name: '国际化', component: importMd('/XM02') },
{ path: '/example/XM03', name: '默认选中', component: importMd('/XM03') },
{ path: '/example/XM04', name: '修改提示', component: importMd('/XM04') },
{ path: '/example/XM05', name: '搜索模式', component: importMd('/XM05') },
{ path: '/example/XM06', name: '下拉方向', component: importMd('/XM06') },
{ path: '/example/XM07', name: '自定义样式', component: importMd('/XM07') },
{ path: '/example/XM08', name: '分页', component: importMd('/XM08') },
{ path: '/example/XM09', name: '单选', component: importMd('/XM09') },
{ path: '/example/XM10', name: '重复选', component: importMd('/XM10') },
{ path: '/example/XM11', name: '自定义属性', component: importMd('/XM11') },
{ path: '/example/XM12', name: '主题', component: importMd('/XM12') },
{ path: '/example/XM13', name: '显示与隐藏', component: importMd('/XM13') },
{ path: '/example/XM14', name: '显示方式', component: importMd('/XM14') },
{ path: '/example/XM15', name: '构建选项', component: importMd('/XM15') },
{ path: '/example/XM16', name: '监听选择', component: importMd('/XM16') },
{ path: '/example/XM17', name: '性能测试', component: importMd('/XM17') },
]
}, {
path: '/question',
name: '常见问题',
component: importMd('/question'),
},
];

7
docs/vue.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,28 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>xm-select</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link rel="stylesheet" type="text/css" href="docs/highlighter/shCore.css"/>
<link rel="stylesheet" type="text/css" href="docs/highlighter/shThemeEclipse.css"/>
<!-- <link rel="stylesheet" type="text/css" href="docs/fathom/fathom.sample.css"/> -->
<link rel="stylesheet" type="text/css" href="docs/index.css"/>
</head>
<body>
<div id="header"></div>
<div id="content"></div>
<script src="docs/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<script src="docs/highlighter/shCore.js" type="text/javascript" charset="utf-8"></script>
<script src="docs/highlighter/shBrushJScript.js" type="text/javascript" charset="utf-8"></script>
<script src="docs/highlighter/shBrushXml.js" type="text/javascript" charset="utf-8"></script>
<!-- <script src="docs/fathom/fathom.min.js" type="text/javascript" charset="utf-8"></script> -->
<script src="dist/xm-select.js" type="text/javascript" charset="utf-8"></script>
<script src="docs/data.js" type="text/javascript" charset="utf-8"></script>
<script src="docs/index.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>

View File

@ -1,28 +1,43 @@
{
"name": "xm-select",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "node_modules/.bin/webpack-dev-server",
"build": "webpack"
},
"author": "",
"license": "ISC",
"dependencies": {
"@babel/core": "^7.4.0",
"@babel/preset-env": "^7.4.2",
"babel-loader": "^8.0.5",
"babel-plugin-transform-react-jsx": "^6.24.1",
"css-loader": "^2.1.1",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"style-loader": "^0.23.1",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1"
},
"devDependencies": {
"html-webpack-plugin": "^3.2.0"
}
}
{
"name": "xm-select",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "cross-env NODE_ENV=dev node_modules/.bin/webpack-dev-server --config build/webpack.config.js",
"build": "cross-env NODE_ENV=prod webpack --config build/webpack.config.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"@babel/core": "^7.4.0",
"@babel/preset-env": "^7.4.2",
"babel-loader": "^8.0.5",
"babel-plugin-transform-react-jsx": "^6.24.1",
"clean-webpack-plugin": "^3.0.0",
"cross-env": "^6.0.0",
"css-loader": "^3.0.0",
"element-ui": "^2.12.0",
"file-loader": "^4.2.0",
"highlight.js": "^9.15.10",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"markdown-it": "^10.0.0",
"markdown-it-anchor": "^5.2.4",
"markdown-it-chain": "^1.3.0",
"markdown-it-container": "^2.0.0",
"style-loader": "^0.23.1",
"transliteration": "^2.1.7",
"url-loader": "^2.1.0",
"vue": "^2.6.10",
"vue-loader": "^15.7.1",
"vue-router": "^3.1.3",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1"
},
"devDependencies": {
"html-webpack-plugin": "^3.2.0"
}
}

View File

@ -32,14 +32,14 @@ class xmOptions {
//开始渲染数据
this.update(options, true);
}
/**
* 更新数据 + 重新渲染
*/
update(options = {}, isNew){
//记录最新的配置项
this.options = {...this.options, ...options};
//如果dom不存在, 则不进行渲染事项
let dom = selector(this.options.el);
if(!dom){
@ -48,21 +48,21 @@ class xmOptions {
}
//如果是历史渲染过的数据, 重置一下数据
isNew && childs[this.options.el] && childs[this.options.el].reset();
let isRender = false;
const onRef = (ref) => childs[this.options.el] = ref;
const onReset = result => {
this.options.data = result;
}
render(<Framework { ...this.options } onReset={ onReset } onClose={ onClose } onRef={ onRef } />, dom);
//记录数据
data[this.options.el] = this;
//返回多选对象
return this;
}
/**
* 重置多选, 回到初始化的状态
*/
@ -76,7 +76,7 @@ class xmOptions {
childs[this.options.el].reset();
return this;
}
/**
* 主动打开多选
*/
@ -94,14 +94,14 @@ class xmOptions {
ref.state.show && ref.onClick();
return this;
}
/**
* 获取多选选中的数据
*/
getValue(){
return safety(childs[this.options.el].state.sels);
}
/**
* 设置多选数据
*/
@ -113,8 +113,8 @@ class xmOptions {
childs[this.options.el].value(sels, !!show);
return this;
}
}
export default xmOptions;
export default xmOptions;

View File

@ -142,7 +142,7 @@ class Framework extends Component{
}
}
on && on({ arr: sels, item, selected: !selected });
on && on({ arr: this.state.sels, item, selected: !selected });
//检查是否为选择即关闭状态, 强制删除情况下不做处理
clickClose && !mandatoryDelete && this.onClick();

View File

@ -4,35 +4,37 @@ import { h, Component, render } from '@/components/preact'
* 标签的渲染
*/
class Label extends Component{
constructor(options){
super(options);
}
iconClick(item, selected, disabled, e){
this.props.ck(item, selected, disabled, true);
//阻止父组件上的事件冒泡
e.stopPropagation();
}
render({ data, prop, theme, model, sels }) {
//获取变换属性
const { name, disabled } = prop;
//获取配置项
const label = model.label;
const type = label.type;
const conf = label[type];
//渲染结果
let html = '';
let innerHTML = true;
if(type === 'text'){
html = sels.map(sel => `${conf.left}${sel[name]}${conf.right}`).join(conf.separator)
}else if(type === 'block'){
innerHTML = false;
//已选择的数据
let arr = [...sels];
const style = { backgroundColor: theme.color }
//显示的个数
const count = conf.showCount <= 0 ? arr.length : conf.showCount;
@ -47,7 +49,7 @@ class Label extends Component{
</div>
)
})
//剩余没显示的数据
if(arr.length){
html.push(
@ -63,16 +65,19 @@ class Label extends Component{
html = sels.map(sel => sel[name]).join(',')
}
}
return (
<div class="xm-label">
<div class="scroll">
<div class="label-content">{ html }</div>
<div class="scroll">
{ innerHTML ?
<div class="label-content" dangerouslySetInnerHTML={{__html: html}}></div> :
<div class="label-content">{ html }</div>
}
</div>
</div>
)
}
}
export default Label;
export default Label;

View File

@ -1,40 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<% for (var chunk in htmlWebpackPlugin.files.css) { %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.css[chunk] %>" as="style">
<% } %>
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>" as="script">
<% } %>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title>xm-select</title>
</head>
<body>
<div id="demo1"></div>
<script type="text/javascript">
setTimeout(() => {
var demo1 = xmSelect.render({
// 这里绑定css选择器
el: '#demo1',
// 渲染的数据
data: ''.padEnd(11, ' ').split('').map((a, i) => ( {name: 'name' + i, value: i} )),
filterable: true,
radio: true,
// remoteSearch: true,
// remoteMethod: function(val, cb){
// setTimeout(() => {
// cb([{name: 'xxx' + val, value: 1}])
// }, 2000);
// },
paging: true,
})
demo1.opened()
}, 1000);
</script>
</body>
</html>

View File

@ -22,6 +22,5 @@ if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'objec
layui.define(function(exports) {
exports('xmSelect', xmSelect);
});
} else {
window.xmSelect = xmSelect;
}
}
window.xmSelect = xmSelect;

View File

@ -129,6 +129,7 @@ xm-select{
& > span{
display: flex;
color: #FFF;
white-space: nowrap;
}
& > i{

View File

@ -1,52 +0,0 @@
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, 'dist'),
filename: "xm-select.js"
},
module: {
rules: [{
test: /\.css$/,
use: 'css-loader'
}, {
test: /\.less$/,
exclude: /node_modules/,
loader: 'style-loader!css-loader!less-loader'
}, {
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}]
},
resolve: {
alias: {
'@': path.resolve(__dirname, "src"),
'components': path.resolve(__dirname, "src/components"),
'style': path.resolve(__dirname, "src/style"),
}
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.ejs',
minify: {
collapseWhitespace: true
}
}),
],
devServer: {
contentBase: path.join(__dirname, "./dist"),
compress: true,
host: '0.0.0.0',
port: 9000,
open: true,
hot: true,
}
};