├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .postcssrc.js ├── Dockerfile ├── LICENSE ├── README.md ├── build ├── build.js ├── check-versions.js ├── package.config.js ├── package.dev.config.js ├── package.prod.config.js ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js ├── webpack.prod.conf.js └── webpack.test.conf.js ├── config ├── dev.env.js ├── index.js ├── prod.env.js └── test.env.js ├── docs ├── .nojekyll ├── README.md ├── _coverpage.md ├── _navbar.md ├── _sidebar.md ├── components │ ├── actionsheet.md │ ├── button.md │ ├── cell.md │ ├── datetimepicker.md │ ├── flexbox.md │ ├── form.md │ ├── grid.md │ ├── icons.md │ ├── keyboard.md │ ├── layout.md │ ├── lazy.md │ ├── loading.md │ ├── loadmore.md │ ├── modal.md │ ├── navbar.md │ ├── popup.md │ ├── seamlessscroll.md │ ├── search.md │ ├── skeleton.md │ ├── step.md │ ├── swiper.md │ ├── tab.md │ ├── tabbar.md │ ├── tag.md │ └── toast.md ├── dist │ ├── index.html │ └── static │ │ ├── css │ │ ├── app.31b0fdd0a12259e269cdd7c0c0f121b9.css │ │ └── app.31b0fdd0a12259e269cdd7c0c0f121b9.css.map │ │ ├── js │ │ ├── 0.60c58761755b3a4d262a.js │ │ ├── 0.60c58761755b3a4d262a.js.map │ │ ├── app.4145bd74658c1ac1c023.js │ │ ├── app.4145bd74658c1ac1c023.js.map │ │ ├── manifest.0232e92aecc83200b279.js │ │ ├── manifest.0232e92aecc83200b279.js.map │ │ ├── vendor.89f9a2ce9587be6b2ad6.js │ │ └── vendor.89f9a2ce9587be6b2ad6.js.map │ │ └── logo.jpg ├── guide.md ├── imgs │ ├── logo.png │ └── xq.jpeg └── index.html ├── index.html ├── package.json ├── package ├── comps │ ├── components │ │ ├── actionsheet │ │ │ ├── actionsheet.scss │ │ │ ├── actionsheet.vue │ │ │ └── index.js │ │ ├── button │ │ │ ├── button-group.vue │ │ │ ├── button.scss │ │ │ ├── button.vue │ │ │ └── index.js │ │ ├── buttongroup │ │ │ └── index.js │ │ ├── cell │ │ │ ├── cell-group.vue │ │ │ ├── cell-item.vue │ │ │ ├── cell.scss │ │ │ └── index.js │ │ ├── cellitem │ │ │ └── index.js │ │ ├── checkbox │ │ │ ├── checkbox-group.vue │ │ │ ├── checkbox.scss │ │ │ ├── checkbox.vue │ │ │ └── index.js │ │ ├── checkboxgroup │ │ │ └── index.js │ │ ├── flexbox │ │ │ ├── flexbox-item.vue │ │ │ ├── flexbox.scss │ │ │ ├── flexbox.vue │ │ │ └── index.js │ │ ├── flexboxitem │ │ │ └── index.js │ │ ├── globalmodal │ │ │ ├── ModalMixin.js │ │ │ ├── global-modal.vue │ │ │ ├── index.js │ │ │ └── modal.scss │ │ ├── grid │ │ │ ├── grid.scss │ │ │ ├── grid.vue │ │ │ ├── grids.vue │ │ │ └── index.js │ │ ├── grids │ │ │ └── index.js │ │ ├── input │ │ │ ├── index.js │ │ │ ├── input.scss │ │ │ └── input.vue │ │ ├── keyboard │ │ │ ├── index.js │ │ │ ├── keyboard.scss │ │ │ └── keyboard.vue │ │ ├── lazy │ │ │ ├── index.js │ │ │ ├── lazy.scss │ │ │ └── lazy.vue │ │ ├── loading │ │ │ ├── index.js │ │ │ ├── loading.scss │ │ │ └── loading.vue │ │ ├── loadmore │ │ │ ├── index.js │ │ │ ├── loadMore.scss │ │ │ └── loadMore.vue │ │ ├── modal │ │ │ ├── index.js │ │ │ └── modal.vue │ │ ├── navbar │ │ │ ├── index.js │ │ │ ├── navbar.scss │ │ │ └── navbar.vue │ │ ├── popup │ │ │ ├── index.js │ │ │ ├── popup.scss │ │ │ └── popup.vue │ │ ├── radio │ │ │ ├── index.js │ │ │ ├── radio-group.vue │ │ │ ├── radio.scss │ │ │ └── radio.vue │ │ ├── radiogroup │ │ │ └── index.js │ │ ├── seamlessscroll │ │ │ ├── index.js │ │ │ ├── seamlessscroll-item.vue │ │ │ ├── seamlessscroll.scss │ │ │ └── seamlessscroll.vue │ │ ├── seamlessscrollitem │ │ │ └── index.js │ │ ├── search │ │ │ ├── index.js │ │ │ ├── search.scss │ │ │ └── search.vue │ │ ├── select │ │ │ ├── index.js │ │ │ ├── select.scss │ │ │ └── select.vue │ │ ├── skeleton │ │ │ ├── index.js │ │ │ ├── skeleton.scss │ │ │ └── skeleton.vue │ │ ├── spmodal │ │ │ ├── index.js │ │ │ ├── sp-modal.vue │ │ │ └── spmodal.scss │ │ ├── step │ │ │ ├── index.js │ │ │ ├── step.scss │ │ │ └── step.vue │ │ ├── switch │ │ │ ├── index.js │ │ │ ├── switch.scss │ │ │ └── switch.vue │ │ ├── tabbar │ │ │ ├── index.js │ │ │ ├── tabbar-item.vue │ │ │ ├── tabbar.scss │ │ │ └── tabbar.vue │ │ ├── tabbaritem │ │ │ └── index.js │ │ ├── tag │ │ │ ├── index.js │ │ │ ├── tag.scss │ │ │ └── tag.vue │ │ ├── textarea │ │ │ ├── index.js │ │ │ ├── textarea.scss │ │ │ └── textarea.vue │ │ └── toast │ │ │ ├── ToastMixin.js │ │ │ ├── index.js │ │ │ ├── toast.scss │ │ │ └── toast.vue │ ├── index.js │ └── styles │ │ ├── animation.scss │ │ ├── common.scss │ │ ├── icon.scss │ │ ├── index.scss │ │ ├── mixin.scss │ │ ├── normalize.scss │ │ └── varibles.scss ├── xmui.min.css ├── xmui.min.css.map └── xmui.min.js ├── src ├── App.vue ├── assets │ ├── 3333.png │ └── logo.png ├── comps │ ├── components │ │ ├── actionsheet │ │ │ ├── actionsheet.scss │ │ │ ├── actionsheet.vue │ │ │ └── index.js │ │ ├── button │ │ │ ├── button-group.vue │ │ │ ├── button.scss │ │ │ ├── button.vue │ │ │ └── index.js │ │ ├── buttongroup │ │ │ └── index.js │ │ ├── cell │ │ │ ├── cell-group.vue │ │ │ ├── cell-item.vue │ │ │ ├── cell.scss │ │ │ └── index.js │ │ ├── cellitem │ │ │ └── index.js │ │ ├── checkbox │ │ │ ├── checkbox-group.vue │ │ │ ├── checkbox.scss │ │ │ ├── checkbox.vue │ │ │ └── index.js │ │ ├── checkboxgroup │ │ │ └── index.js │ │ ├── flexbox │ │ │ ├── flexbox-item.vue │ │ │ ├── flexbox.scss │ │ │ ├── flexbox.vue │ │ │ └── index.js │ │ ├── flexboxitem │ │ │ └── index.js │ │ ├── globalmodal │ │ │ ├── ModalMixin.js │ │ │ ├── global-modal.vue │ │ │ ├── index.js │ │ │ └── modal.scss │ │ ├── grid │ │ │ ├── grid.scss │ │ │ ├── grid.vue │ │ │ ├── grids.vue │ │ │ └── index.js │ │ ├── grids │ │ │ └── index.js │ │ ├── input │ │ │ ├── index.js │ │ │ ├── input.scss │ │ │ └── input.vue │ │ ├── keyboard │ │ │ ├── index.js │ │ │ ├── keyboard.scss │ │ │ └── keyboard.vue │ │ ├── lazy │ │ │ ├── index.js │ │ │ ├── lazy.scss │ │ │ └── lazy.vue │ │ ├── loading │ │ │ ├── index.js │ │ │ ├── loading.scss │ │ │ └── loading.vue │ │ ├── loadmore │ │ │ ├── index.js │ │ │ ├── loadMore.scss │ │ │ └── loadMore.vue │ │ ├── modal │ │ │ ├── index.js │ │ │ └── modal.vue │ │ ├── navbar │ │ │ ├── index.js │ │ │ ├── navbar.scss │ │ │ └── navbar.vue │ │ ├── popup │ │ │ ├── index.js │ │ │ ├── popup.scss │ │ │ └── popup.vue │ │ ├── radio │ │ │ ├── index.js │ │ │ ├── radio-group.vue │ │ │ ├── radio.scss │ │ │ └── radio.vue │ │ ├── radiogroup │ │ │ └── index.js │ │ ├── seamlessscroll │ │ │ ├── index.js │ │ │ ├── seamlessscroll-item.vue │ │ │ ├── seamlessscroll.scss │ │ │ └── seamlessscroll.vue │ │ ├── seamlessscrollitem │ │ │ └── index.js │ │ ├── search │ │ │ ├── index.js │ │ │ ├── search.scss │ │ │ └── search.vue │ │ ├── select │ │ │ ├── index.js │ │ │ ├── select.scss │ │ │ └── select.vue │ │ ├── skeleton │ │ │ ├── index.js │ │ │ ├── skeleton.scss │ │ │ └── skeleton.vue │ │ ├── spmodal │ │ │ ├── index.js │ │ │ ├── sp-modal.vue │ │ │ └── spmodal.scss │ │ ├── step │ │ │ ├── index.js │ │ │ ├── step.scss │ │ │ └── step.vue │ │ ├── switch │ │ │ ├── index.js │ │ │ ├── switch.scss │ │ │ └── switch.vue │ │ ├── tabbar │ │ │ ├── index.js │ │ │ ├── tabbar-item.vue │ │ │ ├── tabbar.scss │ │ │ └── tabbar.vue │ │ ├── tabbaritem │ │ │ └── index.js │ │ ├── tag │ │ │ ├── index.js │ │ │ ├── tag.scss │ │ │ └── tag.vue │ │ ├── textarea │ │ │ ├── index.js │ │ │ ├── textarea.scss │ │ │ └── textarea.vue │ │ └── toast │ │ │ ├── ToastMixin.js │ │ │ ├── index.js │ │ │ ├── toast.scss │ │ │ └── toast.vue │ ├── index.js │ └── styles │ │ ├── animation.scss │ │ ├── common.scss │ │ ├── icon.scss │ │ ├── index.scss │ │ ├── mixin.scss │ │ ├── normalize.scss │ │ └── varibles.scss ├── main.js ├── router │ └── index.js └── views │ └── home.vue ├── static ├── .gitkeep └── logo.jpg └── test ├── e2e ├── custom-assertions │ └── elementCount.js ├── nightwatch.conf.js ├── runner.js └── specs │ └── test.js └── unit ├── .eslintrc ├── index.js ├── karma.conf.js └── specs └── HelloWorld.spec.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }], 6 | "stage-2" 7 | ], 8 | "plugins": ["transform-runtime"], 9 | "env": { 10 | "test": { 11 | "presets": ["env", "stage-2"], 12 | "plugins": ["istanbul"] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /*.js 5 | /test/unit/coverage/ 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md 13 | extends: 'standard', 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'html', 17 | 'vue' 18 | ], 19 | // add your custom rules here 20 | 'rules': { 21 | // allow paren-less arrow functions 22 | 'arrow-parens': 0, 23 | // allow async-await 24 | 'generator-star-spacing': 0, 25 | // allow debugger during development 26 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log* 4 | yarn-debug.log* 5 | yarn-error.log* 6 | /test/unit/coverage/ 7 | /test/e2e/reports/ 8 | selenium-debug.log 9 | package/style.js 10 | package/style.min.js 11 | 12 | # Editor directories and files 13 | .idea 14 | .vscode 15 | *.suo 16 | *.ntvs* 17 | *.njsproj 18 | *.sln -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | index.html 3 | build/ 4 | config/ 5 | dist/ 6 | node_modules/ 7 | package/style.js 8 | package/style.min.js 9 | src/ 10 | static/ 11 | test/ 12 | docs/ 13 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "postcss-import": {}, 7 | "autoprefixer": {} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:9.0.0 2 | MAINTAINER Mon <505038730@qq.com> 3 | 4 | # 将根目录下的文件都copy到container(运行此镜像的容器)文件系统的src文件夹下 5 | ADD . /src 6 | # cd到src文件夹下 7 | WORKDIR /src 8 | 9 | # 安装项目依赖包 10 | RUN npm config set registry https://registry.npmmirror.com 11 | RUN npm install 12 | #RUN npm rebuild node-sass --force 13 | 14 | # 配置环境变量 15 | ENV HOST 192.168.100.102 16 | ENV PORT 8000 17 | 18 | # 容器对外暴露的端口号 19 | EXPOSE 8000 20 | 21 | # 容器启动时执行的命令,类似npm run dev 22 | CMD ["npm", "dev"] 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 mon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, function (err, stats) { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | function exec (cmd) { 7 | return require('child_process').execSync(cmd).toString().trim() 8 | } 9 | 10 | const versionRequirements = [ 11 | { 12 | name: 'node', 13 | currentVersion: semver.clean(process.version), 14 | versionRequirement: packageConfig.engines.node 15 | } 16 | ] 17 | 18 | if (shell.which('npm')) { 19 | versionRequirements.push({ 20 | name: 'npm', 21 | currentVersion: exec('npm --version'), 22 | versionRequirement: packageConfig.engines.npm 23 | }) 24 | } 25 | 26 | module.exports = function () { 27 | const warnings = [] 28 | for (let i = 0; i < versionRequirements.length; i++) { 29 | const mod = versionRequirements[i] 30 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 31 | warnings.push(mod.name + ': ' + 32 | chalk.red(mod.currentVersion) + ' should be ' + 33 | chalk.green(mod.versionRequirement) 34 | ) 35 | } 36 | } 37 | 38 | if (warnings.length) { 39 | console.log('') 40 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 41 | console.log() 42 | for (let i = 0; i < warnings.length; i++) { 43 | const warning = warnings[i] 44 | console.log(' ' + warning) 45 | } 46 | console.log() 47 | process.exit(1) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /build/package.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | 4 | module.exports = { 5 | entry: { 6 | 'xmui': './src/comps/index.js' 7 | }, 8 | output: { 9 | path: path.resolve(__dirname, '../package'), 10 | publicPath: '/package/', 11 | library: 'xmui', 12 | libraryTarget: 'umd', 13 | umdNamedDefine: true 14 | }, 15 | externals: { 16 | vue: { 17 | root: 'Vue', 18 | commonjs: 'vue', 19 | commonjs2: 'vue', 20 | amd: 'vue' 21 | } 22 | }, 23 | resolve: { 24 | extensions: ['.js', '.vue'] 25 | }, 26 | module: { 27 | loaders: [{ 28 | test: /\.vue$/, 29 | loader: 'vue-loader', 30 | options: { 31 | loaders: { 32 | css: 'vue-style-loader!css-loader', 33 | sass: 'vue-style-loader!css-loader!sass-loader' 34 | }, 35 | postLoaders: { 36 | html: 'babel-loader' 37 | } 38 | } 39 | }, { 40 | test: /\.js$/, 41 | loader: 'babel-loader', 42 | exclude: /node_modules/ 43 | }, { 44 | test: /\.css$/, 45 | use: [ 46 | 'style-loader', 47 | 'css-loader', 48 | 'autoprefixer-loader' 49 | ] 50 | }, { 51 | test: /\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/, 52 | loader: 'url-loader?limit=8192' 53 | }] 54 | }, 55 | plugins: [ 56 | new webpack.optimize.ModuleConcatenationPlugin() 57 | ] 58 | } -------------------------------------------------------------------------------- /build/package.dev.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const merge = require('webpack-merge') 3 | const baseWebpackConfig = require('./package.config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | const extractScss = new ExtractTextPlugin('/xmui.min.css') 6 | 7 | module.exports = merge(baseWebpackConfig, { 8 | output: { 9 | filename: '[name].js' 10 | }, 11 | module: { 12 | loaders: [{ 13 | test: /\.scss$/i, 14 | loader: extractScss.extract(['css-loader','sass-loader']) 15 | }] 16 | }, 17 | plugins: [ 18 | new webpack.DefinePlugin({ 19 | 'process.env': { 20 | NODE_ENV: '"development"' 21 | } 22 | }), 23 | extractScss 24 | ] 25 | }) -------------------------------------------------------------------------------- /build/package.prod.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const merge = require('webpack-merge') 3 | const config = require('../config') 4 | const baseWebpackConfig = require('./package.config') 5 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 6 | const extractScss = new ExtractTextPlugin('/xmui.min.css') 7 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 8 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 9 | 10 | module.exports = merge(baseWebpackConfig, { 11 | output: { 12 | filename: '[name].min.js' 13 | }, 14 | module: { 15 | loaders: [{ 16 | test: /\.scss$/i, 17 | loader: extractScss.extract(['css-loader','sass-loader']) 18 | }] 19 | }, 20 | plugins: [ 21 | new webpack.DefinePlugin({ 22 | 'process.env': { 23 | NODE_ENV: '"production"' 24 | } 25 | }), 26 | //new webpack.optimize.OccurrenceOrderPlugin(), 27 | new webpack.optimize.UglifyJsPlugin({ 28 | uglifyOptions: { 29 | ie8: false, 30 | output: { 31 | comments: false, 32 | beautify: false, 33 | }, 34 | mangle: { 35 | keep_fnames: true 36 | }, 37 | compress: { 38 | warnings: false, 39 | drop_console: true 40 | } 41 | } 42 | }), 43 | extractScss, 44 | new OptimizeCSSPlugin({ 45 | cssProcessorOptions: config.build.productionSourceMap 46 | ? { safe: true, map: { inline: false } } 47 | : { safe: true } 48 | }), 49 | new CopyWebpackPlugin([ 50 | // {output}/file.txt 51 | { from: `./src/comps`,to:`./comps`} 52 | ]), 53 | ] 54 | }) -------------------------------------------------------------------------------- /build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | 10 | module.exports = { 11 | loaders: utils.cssLoaders({ 12 | sourceMap: sourceMapEnabled, 13 | extract: isProduction 14 | }), 15 | cssSourceMap: sourceMapEnabled, 16 | cacheBusting: config.dev.cacheBusting, 17 | transformToRequire: { 18 | video: 'src', 19 | source: 'src', 20 | img: 'src', 21 | image: 'xlink:href' 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | 7 | function resolve (dir) { 8 | return path.join(__dirname, '..', dir) 9 | } 10 | 11 | module.exports = { 12 | context: path.resolve(__dirname, '../'), 13 | entry: { 14 | app: './src/main.js' 15 | }, 16 | output: { 17 | path: config.build.assetsRoot, 18 | filename: '[name].js', 19 | publicPath: process.env.NODE_ENV === 'production' 20 | ? config.build.assetsPublicPath 21 | : config.dev.assetsPublicPath 22 | }, 23 | resolve: { 24 | extensions: ['.js', '.vue', '.json'], 25 | alias: { 26 | 'vue$': 'vue/dist/vue.esm.js', 27 | '@': resolve('src'), 28 | // 'xmui': path.resolve(__dirname, '../src/comps/index'), 29 | // 'assets': path.resolve(__dirname, '../src/assets'), 30 | // 'components': path.resolve(__dirname, '../src/components') 31 | } 32 | }, 33 | module: { 34 | rules: [ 35 | ...(config.dev.useEslint? [{ 36 | test: /\.(js|vue)$/, 37 | loader: 'eslint-loader', 38 | enforce: 'pre', 39 | include: [resolve('src'), resolve('test')], 40 | options: { 41 | formatter: require('eslint-friendly-formatter'), 42 | emitWarning: !config.dev.showEslintErrorsInOverlay 43 | } 44 | }] : []), 45 | { 46 | test: /\.vue$/, 47 | loader: 'vue-loader', 48 | options: vueLoaderConfig 49 | }, 50 | { 51 | test: /\.js$/, 52 | loader: 'babel-loader', 53 | include: [resolve('src'), resolve('test')] 54 | }, 55 | { 56 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 57 | loader: 'url-loader', 58 | options: { 59 | limit: 10000, 60 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 61 | } 62 | }, 63 | { 64 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 65 | loader: 'url-loader', 66 | options: { 67 | limit: 10000, 68 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 69 | } 70 | }, 71 | { 72 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 73 | loader: 'url-loader', 74 | options: { 75 | limit: 10000, 76 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 77 | } 78 | } 79 | ] 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /build/webpack.test.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // This is the webpack config used for unit tests. 3 | 4 | const utils = require('./utils') 5 | const webpack = require('webpack') 6 | const merge = require('webpack-merge') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | 9 | const webpackConfig = merge(baseWebpackConfig, { 10 | // use inline sourcemap for karma-sourcemap-loader 11 | module: { 12 | rules: utils.styleLoaders() 13 | }, 14 | devtool: '#inline-source-map', 15 | resolveLoader: { 16 | alias: { 17 | // necessary to to make lang="scss" work in test when using vue-loader's ?inject option 18 | // see discussion at https://github.com/vuejs/vue-loader/issues/724 19 | 'scss-loader': 'sass-loader' 20 | } 21 | }, 22 | plugins: [ 23 | new webpack.DefinePlugin({ 24 | 'process.env': require('../config/test.env') 25 | }) 26 | ] 27 | }) 28 | 29 | // no need for app entry during tests 30 | delete webpackConfig.entry 31 | 32 | module.exports = webpackConfig 33 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /config/test.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const devEnv = require('./dev.env') 4 | 5 | module.exports = merge(devEnv, { 6 | NODE_ENV: '"testing"' 7 | }) 8 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monw3c/xmui/9b389127a94b5838a71bc5f3bb9cfff41a1cbef0/docs/.nojekyll -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 基于vue 2+ ,为公司产品打(zao)造(lun)的(zi)可复用UI组件,适用于 移动 和 部分PC 端,其中包括 基础组件 和 应用组件,目前 组件 和 文档 在不断完善中。 4 | 5 | ## 特性 6 | 7 | - 基于 [Vue](http://vuejs.org/)`>=v2.1.4` 开发的可复用 UI 组件,并且可随产品需要扩展 8 | - 使用Vue官方的工作流,支持 ES6 9 | - 一系列产品线都在使用中 10 | - 关于SEO问题推荐使用插件 [prerender-spa-plugin](https://github.com/chrisvfritz/prerender-spa-plugin) 11 | 12 | ## 浏览器支持 13 | 14 | - 适用于 移动 和 部分PC 端 15 | 16 | ## 通用项目工程 17 | 18 | - 基于官方扩展的项目工程,集成了Axios,Dayjs和可选的XMUI,Vuex https://github.com/monw3c/vue-wp-cli 19 | 20 | ## 开发 21 | > 全局引入 -- 在 webpack 入口文件 main.js 中如下配置: 22 | 23 | ``` bash 24 | # 安装 25 | cnpm install x-m-ui --save 26 | 27 | # 引入css 28 | import 'x-m-ui/package/xmui.min.css' 29 | 30 | # 引入xmui.min.js 31 | import xmui from 'x-m-ui' 32 | 33 | # 注入到vue 34 | Vue.use(xmui) 35 | ``` 36 | 37 | > 按需引入 -- 在 入口文件 main.js 或 组件内 中如下配置: 38 | 39 | ``` bash 40 | # 全局组件 main.js引入 41 | import Toast from 'x-m-ui/package/comps/components/toast' 42 | Vue.prototype.$toast = Toast 43 | 44 | # 一般组件 45 | import xmButton from 'x-m-ui/package/comps/components/button' 46 | import xmButtonGroup from 'x-m-ui/package/comps/components/buttongroup' 47 | import xmModal from 'x-m-ui/package/comps/components/modal' 48 | ... 49 | 50 | components: { 51 | xmButton, 52 | xmButtonGroup, 53 | xmModal 54 | ... 55 | } 56 | ``` 57 | ## 查看示例 58 | 59 | [在线示例](https://monw3c.github.io/xmui/dist/) 60 | 61 | 62 | ## 组件列表 63 | - [x] 按钮 64 | - [x] 标签 65 | - [x] 加载更多 66 | - [x] 搜索框 67 | - [x] 单元格 68 | - [x] 表单 69 | - [x] 网格和图标 70 | - [x] flexbox 71 | - [x] Modal 72 | - [x] Toast 73 | - [x] Loading 74 | - [x] 工单流程 75 | - [x] skeleton骨架 76 | - [x] Lazy延迟加载 77 | - [ ] 轮播 78 | - [x] ActionSheet 79 | - [x] Popup 80 | - [x] 数字键盘 81 | - [x] 无缝滚动 82 | - [ ] 左右滑菜单 83 | - [ ] 时间选择器 84 | - [ ] 标签页 85 | - [x] 导航栏(顶部) 86 | - [x] 标签栏(底部) 87 | 88 | ## 贡献 89 | 90 | 在此不一一感谢所有付出脑力体力的同仁,如有疑问,请与我们联系 91 | 如果你在使用时遇到问题,或者有好的建议,欢迎给我们提 [Issue](https://github.com/monw3c/xmui/issues) 或 [Pull Request](https://github.com/monw3c/xmui/pulls) 92 | -------------------------------------------------------------------------------- /docs/_coverpage.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monw3c/xmui/9b389127a94b5838a71bc5f3bb9cfff41a1cbef0/docs/_coverpage.md -------------------------------------------------------------------------------- /docs/_navbar.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monw3c/xmui/9b389127a94b5838a71bc5f3bb9cfff41a1cbef0/docs/_navbar.md -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | - 开发指北 2 | - [介绍](/README.md) 3 | 4 | - 基础组件 5 | - [按钮](/components/button.md) 6 | - [标签](/components/tag.md) 7 | - [加载更多](/components/loadmore.md) 8 | - [搜索框](/components/search.md) 9 | - [单元格](/components/cell.md) 10 | - [Flexbox](/components/flexbox.md) 11 | - [表单](/components/form.md) 12 | - [网格](/components/grid.md) 13 | - [图标](/components/icons.md) 14 | - [轮播](/components/swiper.md) 15 | - [时间选择器](/components/datetimepicker.md) 16 | - [导航栏(顶部)](/components/navbar.md) 17 | - [标签栏(底部)](/components/tabbar.md) 18 | - [标签页](/components/tab.md) 19 | - [无缝滚动](/components/seamlessscroll.md) 20 | - [数字键盘](/components/keyboard.md) 21 | 22 | - 弹出层 23 | - [Modal](/components/modal.md) 24 | - [Toast](/components/toast.md) 25 | - [Loading](/components/loading.md) 26 | - [ActionSheet](/components/actionsheet.md) 27 | - [Popup](/components/popup.md) 28 | 29 | - 应用组件 30 | - [工单流程](/components/step.md) 31 | - [skeleton骨架](/components/skeleton.md) 32 | - [Lazy延迟加载](/components/lazy.md) -------------------------------------------------------------------------------- /docs/components/actionsheet.md: -------------------------------------------------------------------------------- 1 | # ActionSheet 上拉菜单 2 | ---- 3 | ### 基础用法 4 | 使用```item-list```、```cancel```、```cancel-color```、```v-model```、```has-icon```和```header```属性来定义 ActionSheet 的样式。 5 | ``` html 6 | 7 | 8 | ``` 9 | 10 | ```js 11 | export default { 12 | data () { 13 | return { 14 | itemList: [ 15 | { text: '顺风车', 16 | icon: '', 17 | callBack: () => { 18 | this.$modal.alert({ 19 | title: '提示', 20 | content: '我是actionsheet弹出来的', 21 | color: '#19be6b' 22 | }) 23 | } 24 | }, 25 | { text: '巴士', icon: '', callBack: () => {} }, 26 | { text: '快车', 27 | icon: '

“别打算XSS攻击”

', 28 | callBack: () => { 29 | this.$modal.alert({ 30 | title: '提示', 31 | content: '想了解vue XSS攻击点确定', 32 | color: '#19be6b', 33 | callBack: () => { 34 | location.href = 'https://segmentfault.com/q/1010000009844447' 35 | } 36 | }) 37 | } 38 | }, 39 | { text: '专车', callBack: () => {} } 40 | ], 41 | actionSheetVisible1: false, 42 | actionSheetVisible2: false 43 | } 44 | } 45 | } 46 | ``` 47 | 48 | ### 属性 49 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 50 | |---------- |-------- |---------- |------------- |-------- | 51 | | item-list | 传入数组数据 | Array | — | — | 52 | | v-model | 绑定状态 | string | — | — | 53 | | cancel | 取消按钮文字 | string | —| — | 54 | | cancel-color | 取消文字颜色 | string | — | — | 55 | | header | 标题文字 | string | — | — | 56 | | has-icon | 是否带图标或图片 | Boolean | — | false | 57 | -------------------------------------------------------------------------------- /docs/components/button.md: -------------------------------------------------------------------------------- 1 | # Button 按钮 2 | ---- 3 | ### 基础用法 4 | 使用```type```、```plain```、```icon```、```loading```、```long```、```bg-color```、```color```、```border-color```、```no-radius```、```block```和```round```属性来定义 Button 的样式。 5 | ``` html 6 | 普通按钮 7 | primary按钮 8 | 9 | 禁止按钮 10 | 简约按钮 11 | 文字按钮 12 | loading状态按钮 13 | 自定义颜色 14 | 块按钮 15 | 长按钮 16 | 17 | 警告按钮 18 | primary按钮 19 | 20 | ``` 21 | 22 | ### 属性 23 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 24 | |---------- |-------- |---------- |------------- |-------- | 25 | | long | 长按钮 | Boolean | — | false | 26 | | loading | 是否有加载效果 | Boolean | — | false | 27 | | type | 类型 | string | primary,success,warning,danger,info | — | 28 | | plain | 是否简约按钮 | Boolean | — | false | 29 | | disabled | 是否禁用状态 | Boolean | — | false | 30 | | icon | 图标,已有的图标库中的图标名 | string | — | — | 31 | | round | 圆角 | Boolean | — | false | 32 | | block | 块级按钮 | Boolean | — | false | 33 | | bg-color | 背景颜色 | string | 自定义 | — | 34 | | color | 文字颜色 | string | 自定义 | — | 35 | | border-color | 边框颜色 | string | 自定义 | — | 36 | | no-radius | 无边框 | string | 自定义 | — | 37 | 38 | -------------------------------------------------------------------------------- /docs/components/cell.md: -------------------------------------------------------------------------------- 1 | # Cell 单元格 2 | ---- 3 | 4 | ###### 基础用法 5 | xm-cell-group 组件有```title```属性和```top```、```bottom```②个slot 6 | 7 | xm-cell-item 组件有```type```、```href```属性和```leftIcon```、```left```、```right```、```rightIcon```④个slot,具体表现可以查看在线示例 8 | ``` html 9 | # type='link'时,为链接形式 10 | 11 |
12 | 13 | 14 | 联系方式 15 | 400517517 16 | 17 | 18 | 19 | 20 | 我的消息 21 | 8 22 | 23 | 24 |
25 |
26 | ``` 27 | ###### xm-cell-group属性 28 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 29 | |---------- |-------- |---------- |------------- |-------- | 30 | | title | 设置标题 | String | — | — | 31 | 32 | ###### xm-cell-item属性 33 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 34 | |---------- |-------- |---------- |------------- |-------- | 35 | | type | 设置类型 | String | link | — | 36 | | href | 设置href | String | — | — | 37 | 38 | -------------------------------------------------------------------------------- /docs/components/datetimepicker.md: -------------------------------------------------------------------------------- 1 | # datetimePicker 时间选择器 2 | ---- 3 | 23 | -------------------------------------------------------------------------------- /docs/components/flexbox.md: -------------------------------------------------------------------------------- 1 | # Flexbox flex布局 2 | ---- 3 | ### 配合 xm-flexbox 使用 4 | ### 基础用法 5 | 使用```direction```属性来定义 Flexbox 的样式 6 | ``` html 7 | 8 |
普通div
9 | 默认的水平flex div 10 |
普通div
11 |
12 |
13 | 14 |
普通div
15 | direction="vertical" 的垂直flex div 16 |
普通div
17 |
18 | ``` 19 | 20 | ### 属性 21 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 22 | |---------- |-------- |---------- |------------- |-------- | 23 | | direction | 设置垂直布局 | String | horizontal,vertical | horizontal | 24 | -------------------------------------------------------------------------------- /docs/components/grid.md: -------------------------------------------------------------------------------- 1 | # Grid 网格 2 | ---- 3 | ### 配合 xm-grids 使用 4 | ``` html 5 | ... 6 | ``` 7 | ### 属性 8 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 9 | |---------- |-------- |---------- |------------- |-------- | 10 | | row | 每行显示列数 | String | 2,3,4,5,6 | 4 | 11 | 12 | 13 | ### 基础用法 14 | 使用```href```属性来定义 Grid 的样式,icon 和 text 两个slot 15 | ``` html 16 | 17 | 18 | 19 | 手机 20 | 21 | 22 | 23 | 位置 24 | 25 | 26 | 27 | 密码 28 | 29 | 30 | 31 | 扫码 32 | 33 | 34 | 35 | 时间 36 | 37 | 38 | 39 | 电话 40 | 41 | 42 | ``` 43 | 44 | ### 属性 45 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 46 | |---------- |-------- |---------- |------------- |-------- | 47 | | href | 设置链接 | String | — | javascript:; | 48 | -------------------------------------------------------------------------------- /docs/components/icons.md: -------------------------------------------------------------------------------- 1 | # Icons 图标 2 | ---- 3 | 23 | -------------------------------------------------------------------------------- /docs/components/keyboard.md: -------------------------------------------------------------------------------- 1 | # Keyboard 数字键盘 2 | ---- 3 | ### 基础用法 4 | 使用```visible```、```tips```、```len```、```confirmText```和```styleName```属性来定义 Keyboard 的样式。 5 | ``` html 6 | 7 | 8 | 房间租金 9 |
10 | 11 |
12 |
13 | 14 | 身份证号码 15 |
16 | 17 |
18 |
19 |
20 | 21 | 22 | ``` 23 | 24 | 25 | ### 属性 26 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 27 | |---------- |-------- |---------- |------------- |-------- | 28 | | visible | 输入框的显示隐藏 | Boolean | — | false | 29 | | len | 限制输出值的长度 | Number | — | 6 | 30 | | confirmText | 确定按钮文字 | String | — | 确定 | 31 | | tips | 输入框传入的字典,isCard:true适合身份证键盘,否则为带单位小数点数字键盘 | Object | 例如:{"title":"房间面积", "placeholder":"请输入房间面积", "name":"roomAreaVal", "unit":"㎡", "isCard":false}' | — | 32 | 33 | 34 | ### 方法 35 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 36 | |---------- |-------- |---------- |------------- |-------- | 37 | | confirm | 确定操作 | Function | 自定义 | — | 38 | | close | 关闭操作 | Function | 自定义 | — | 39 | -------------------------------------------------------------------------------- /docs/components/layout.md: -------------------------------------------------------------------------------- 1 | # Layout 栅格布局 2 | ---- 3 | 4 | 38 | -------------------------------------------------------------------------------- /docs/components/lazy.md: -------------------------------------------------------------------------------- 1 | # Lazy 延迟加载组件 2 | ---- 3 | ### 基础用法 4 | 使用```time```和```loaded```属性来定义 Lazy 的样式。 5 | ``` html 6 | 7 | 8 |
9 |
10 | 11 |
12 |
13 | 14 |
15 |
16 | 17 |
18 | ``` 19 | 20 | 21 | ### 属性 22 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 23 | |---------- |-------- |---------- |------------- |-------- | 24 | | time | 延迟时间 (毫秒) | Number | — | 16 | 25 | 26 | ### 方法 27 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 28 | |---------- |-------- |---------- |------------- |-------- | 29 | | loaded | 完成操作 | Function | 自定义 | — | 30 | -------------------------------------------------------------------------------- /docs/components/loading.md: -------------------------------------------------------------------------------- 1 | # Loading 加载组件 2 | ---- 3 | ### 基础用法 4 | 使用```width```、```height```、```color```、```fullScreen```、```border-width```、```vertical```、```closable```和```has-text```属性来定义 Loading 的样式。 5 | ``` html 6 | 7 | 8 | 9 | 自定义文字 10 | 11 | 全屏的loading 12 | 垂直的loading 13 | 可关闭的loading 14 |

自定义效果

15 | ``` 16 | 17 | ### 属性 18 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 19 | |---------- |-------- |---------- |------------- |-------- | 20 | | width | 设置大小 | String | — | - | 21 | | height | 设置大小 | String | — | - | 22 | | color | 颜色 | string | 自定义 | — | 23 | | has-text | 是否有文字 | Boolean | — | false | 24 | | fullScreen | 是否为全局效果 | Boolean | — | false | 25 | | vertical | 垂直排列icon和文字 | Boolean | — | false | 26 | | closable | 当fullScreen时才出现可关闭按钮 | Boolean | — | — | 27 | | slot="cus" | 可自定义传入内容 | — | — | — | 28 | 29 | ### 方法 30 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 31 | |---------- |-------- |---------- |------------- |-------- | 32 | | close | 关闭操作 | Function | 自定义 | — | 33 | 34 | -------------------------------------------------------------------------------- /docs/components/loadmore.md: -------------------------------------------------------------------------------- 1 | # LoadMore 加载更多 2 | ---- 3 | ### 基础用法 4 | 使用```icon```、```color```和```no-data```属性来定义 LoadMore 的样式。 5 | ``` html 6 | 7 | loading... 8 | 暂无数据 9 | ``` 10 | 11 | ### 属性 12 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 13 | |---------- |-------- |---------- |------------- |-------- | 14 | | no-data | 是否为暂无数据 | Boolean | — | false | 15 | | icon | 是否有loading效果 | Boolean | — | false | 16 | | color | 文字颜色 | string | 自定义 | — | 17 | 18 | ### 方法 19 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 20 | |---------- |-------- |---------- |------------- |-------- | 21 | | action | 操作 | string | 自定义 | — | 22 | -------------------------------------------------------------------------------- /docs/components/navbar.md: -------------------------------------------------------------------------------- 1 | # Navbar 导航栏 2 | ---- 3 | ### 基础用法 4 | 使用```title```、```bgcolor```、```color```、```left-text```、```left-icon```、```right-text```、```right-icon```和```img-src```属性来定义 Navbar 的样式。 5 | ``` html 6 | 7 | 8 | #有title的时候设置img-src无效 9 | 10 | ``` 11 | 12 | ### 属性 13 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 14 | |---------- |-------- |---------- |------------- |-------- | 15 | | title | 设置导航标题 | String | — | — | 16 | | img-src | 设置导航标题为图片,有title的时候设置无效 | String | — | — | 17 | | bgcolor | 设置导航背景颜色 | String | — | — | 18 | | color | 设置文字颜色 | String | — | — | 19 | | left-text | 设置左文字 | String | — | — | 20 | | left-icon | 设置左图标 | String | — | — | 21 | | right-text | 设置右文字 | String | — | — | 22 | | right-icon | 设置右图标 | String | — | — | 23 | 24 | 25 | ### API 26 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 27 | |---------- |-------- |---------- |------------- |-------- | 28 | | left-action | 左点击方法 | Function | — | — | 29 | | right-action | 右点击方法 | Function | — | — | -------------------------------------------------------------------------------- /docs/components/popup.md: -------------------------------------------------------------------------------- 1 | # Popup 上滑弹出框 2 | ---- 3 | ### 基础用法 4 | 使用```cancel```、```cancel-color```、```v-model```和```header```属性来定义 Popup 的样式。 5 | ``` html 6 | 7 | 8 | 9 | 10 |
11 |

电子提案

12 |

通过在网上进行电子提案

13 |
14 |
15 | 16 | 17 |
18 |

原始提案

19 |

采用原始方式进行提案,平台只进行记录

20 |
21 |
22 |
23 |
24 | ``` 25 | 26 | ```js 27 | export default { 28 | data () { 29 | return { 30 | popupVisible1: false 31 | } 32 | } 33 | } 34 | ``` 35 | 36 | ### 属性 37 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 38 | |---------- |-------- |---------- |------------- |-------- | 39 | | v-model | 绑定状态 | string | — | — | 40 | | cancel | 取消按钮文字 | string | —| — | 41 | | cancel-color | 取消文字颜色 | string | — | — | 42 | | header | 标题文字 | string | — | — | 43 | 44 | -------------------------------------------------------------------------------- /docs/components/seamlessscroll.md: -------------------------------------------------------------------------------- 1 | # Seamlessscroll 无缝滚动 2 | ---- 3 | ### 基础用法 4 | 使用```height```、```speed```、```autoplay```、```align```和```direction```属性来定义 Seamlessscroll 的样式。 5 | ``` html 6 | 7 | 只有一条的时候不滚动,默认向上滚动 8 | 9 | 10 | 11 | 邵逸夫奖名单公布 12 | 女星玛戈基德去世 13 | 多国谴责美搬使馆 14 | 15 | ``` 16 | 17 | ### 属性 18 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 19 | |---------- |-------- |---------- |------------- |-------- | 20 | | height | 设置行高 | String | — | 30 | 21 | | speed | 设置速率 | Number | — | 500 | 22 | | autoplay | 设置滚动间隔 | Number | — | 3000 | 23 | | align | 设置对齐方向 | String | left,center,right | left | 24 | | direction | 设置方向 | String | up,down | up | 25 | -------------------------------------------------------------------------------- /docs/components/search.md: -------------------------------------------------------------------------------- 1 | # Search 搜索框 2 | ---- 3 | ### 基础用法 4 | 使用```action-text-color```、```cancel-text-color```、```bg-color```、```has-clear```和```placeholder```属性来定义 Search 的样式。 5 | ``` html 6 |
确定
7 | 8 | 搜索取消 9 | ``` 10 | 11 | ### 属性 12 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 13 | |---------- |-------- |---------- |------------- |-------- | 14 | | action-text-color | 方法文字颜色 | string | 自定义 | — | 15 | | cancel-text-color | 取消文字颜色 | string | 自定义 | — | 16 | | bg-color | 背景颜色 | string | 自定义 | — | 17 | | placeholder | placeholder | string | 自定义 | 请输入搜索关键字 | 18 | | has-clear | 是否可清空 | Boolean | true,false | true | 19 | 20 | 21 | ### 方法 22 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 23 | |---------- |-------- |---------- |------------- |-------- | 24 | | action | 按钮操作 | string | 自定义 | — | 25 | | input | input监听方法 | string | 自定义 | — | 26 | | clear | clear监听方法 | string | 自定义 | — | 27 | 28 | -------------------------------------------------------------------------------- /docs/components/skeleton.md: -------------------------------------------------------------------------------- 1 | # Skeleton 骨架 2 | ---- 3 | ### 基础用法 4 | 使用```type```、```width```、```height```和```animate```属性来定义 Skeleton 的样式。 5 | ``` html 6 | 7 | 8 | ``` 9 | 10 | ### 属性 11 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 12 | |---------- |-------- |---------- |------------- |-------- | 13 | | type | 设置类型 | String | circle,bar | bar | 14 | | width | 设置宽度 | String | — | — | 15 | | height | 设置高度 | String | — | — | 16 | | animate | 设置动画样式 | String | opacity,loading | opacity | 17 | -------------------------------------------------------------------------------- /docs/components/step.md: -------------------------------------------------------------------------------- 1 | # Step 工单流程 2 | ---- 3 | ### 基础用法 4 | 使用```step```和```step-list```属性来定义 Step 的样式。 5 | ``` html 6 | 7 | 8 | export default { 9 | data () { 10 | return { 11 | stepList: ['发起工单', '主管审批', '经理审批', '总监核查', '结束'], 12 | step: 2 13 | } 14 | } 15 | } 16 | ``` 17 | 18 | ### 属性 19 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 20 | |---------- |-------- |---------- |------------- |-------- | 21 | | step | 设置当前在第几步流程 | Number | — | 0 | 22 | | step-list | 总流程列表 | Array | — | — | 23 | -------------------------------------------------------------------------------- /docs/components/swiper.md: -------------------------------------------------------------------------------- 1 | # Swiper 轮播 2 | ---- 3 | 23 | -------------------------------------------------------------------------------- /docs/components/tab.md: -------------------------------------------------------------------------------- 1 | # Tab 标签页 2 | ---- 3 | 23 | -------------------------------------------------------------------------------- /docs/components/tabbar.md: -------------------------------------------------------------------------------- 1 | # Tabbar 标签栏 2 | ---- 3 | ### 基础用法 4 | 使用```icon```、```type```、```href```、```bagde```、```img-src```和```active```属性来定义 Tabbar 的样式。 5 | ``` html 6 | 7 | 首页 8 | 商城 9 | 10 | 自定义图标 11 | 我的 12 | 13 | 14 | export default { 15 | data () { 16 | return { 17 | hrefObj: { path: '/mall', name: 'mall', params: { userId: 123 } } 18 | } 19 | } 20 | } 21 | ``` 22 | 23 | ### 属性 24 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 25 | |---------- |-------- |---------- |------------- |-------- | 26 | | type | 设置类型 | String | link为单纯a链接,router基于vue-router的链接 | router | 27 | | href | 设置链接 | String,Object | — | — | 28 | | icon | 设置图标(样式) | String | — | — | 29 | | img-src | 自定义图标地址 | String | — | — | 30 | | bagde | 设置角标 | String | — | — | 31 | | active | 设置选中状态 | Boolean | — | false | 32 | | img-src | img-src图标 | String | — | — | 33 | 34 | ### API 35 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 36 | |---------- |-------- |---------- |------------- |-------- | 37 | | click | 点击方法 | Function | — | — | -------------------------------------------------------------------------------- /docs/components/tag.md: -------------------------------------------------------------------------------- 1 | # Tag 标签 2 | ---- 3 | ### 基础用法 4 | 使用```type```、```bg-color```、```color```、```border-color```、```closable```和```round```属性来定义 Tag 的样式。 5 | ``` html 6 | 普通 7 | primary 8 | success 9 | warning 10 | error 11 | 自定义颜色 12 | ``` 13 | 14 | ### 属性 15 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 16 | |---------- |-------- |---------- |------------- |-------- | 17 | | type | 类型 | string | primary,success,warning,danger,info | — | 18 | | round | 圆角 | Boolean | — | false | 19 | | bg-color | 背景颜色 | string | 自定义 | — | 20 | | color | 文字颜色 | string | 自定义 | — | 21 | | border-color | 边框颜色 | string | 自定义 | — | 22 | 23 | ### API 24 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 25 | |---------- |-------- |---------- |------------- |-------- | 26 | | closable | 可关闭 | Boolean | — | false | -------------------------------------------------------------------------------- /docs/components/toast.md: -------------------------------------------------------------------------------- 1 | # Toast 轻提示层 2 | ---- 3 | ### 基础用法 4 | 使用```content```、```direction```、```mask```和```autoClose```属性来定义 Toast 的样式。 5 | ``` js 6 | this.$toast.text(content, direction, mask, autoClose, callBack) 7 | this.$toast.loading(mask, autoClose, callBack) 8 | 9 | methods: { 10 | toastClick1 () { 11 | this.$toast.text({ 12 | content: '太长会换行呢,15个字以内最好', 13 | direction: 'bottom', 14 | callBack () { 15 | setTimeout(() => { 16 | this.$toast.text({content: '关闭后回调操作', direction: 'bottom'}) 17 | }, 2000) 18 | } 19 | }) 20 | }, 21 | toastClick2 () { 22 | this.$toast.loading({ 23 | mask: false 24 | }) 25 | } 26 | } 27 | ``` 28 | 29 | ### 属性 30 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 31 | |---------- |-------- |---------- |------------- |-------- | 32 | | content | 内容 | string | 自定义 | loading无 | 33 | | mask | 是否有背景 | Boolean | - | text为false,loading为true | 34 | | direction | 方向 | string | top,bottom,center | text独有,默认center | 35 | | autoClose | 自动关闭 | Boolean | - | 默认为3秒,alert有,confirm无 | 36 | | callBack | 回调函数 | Function | 自定义 | - | 37 | 38 | -------------------------------------------------------------------------------- /docs/dist/index.html: -------------------------------------------------------------------------------- 1 | xmui - 基于vue2,可复用UI组件
-------------------------------------------------------------------------------- /docs/dist/static/js/manifest.0232e92aecc83200b279.js: -------------------------------------------------------------------------------- 1 | !function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,a){for(var i,u,f,s=0,l=[];s 2 | 3 | 4 | 5 | xmui - 基于vue2,可复用UI组件 6 | 7 | 8 | 9 | 10 | 11 | 26 | 27 | 28 |
加载中
29 | 38 | 39 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <%= htmlWebpackPlugin.options.title%> 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /package/comps/components/actionsheet/actionsheet.scss: -------------------------------------------------------------------------------- 1 | .xm__mask { 2 | @include mask 3 | } 4 | 5 | .xm__actionsheet { 6 | text-align: center; 7 | position: fixed; 8 | bottom: 0; 9 | left: 0; 10 | width: 100%; 11 | z-index: $zindex-popover; 12 | background-color: #efeff4; 13 | transform: translate(0, 100%); 14 | transition: transform .3s; 15 | 16 | &.xm__actionsheet--active { 17 | transform: translate(0, 0); 18 | } 19 | 20 | & header{ 21 | font-size: 1.3rem; 22 | color: $text-color; 23 | height: 40px; 24 | line-height: 40px; 25 | background-color: $body-background; 26 | } 27 | 28 | & ul { 29 | margin: 0; 30 | padding: 0; 31 | } 32 | 33 | & .xm__actionsheet--item { 34 | display: flex; 35 | justify-content: center; 36 | align-items: center; 37 | position: relative; 38 | font-size: $font-size-big; 39 | color: $text-color; 40 | height: 50px; 41 | // line-height: 50px; 42 | background-color: $body-background; 43 | 44 | & .xm__actionsheet--icon{ 45 | max-height: 40px; 46 | margin-right: 5px; 47 | 48 | & img{ 49 | max-height: 40px; 50 | } 51 | 52 | & p{ 53 | margin: 0; 54 | } 55 | } 56 | 57 | &:after { 58 | content: ""; 59 | position: absolute; 60 | z-index: 2; 61 | bottom: 0; 62 | left: 0; 63 | width: 100%; 64 | border-bottom: $border-width-default $border-style-default $border-color-base; 65 | transform: scaleY(.5); 66 | transform-origin: 0 0; 67 | } 68 | 69 | &:first-child:before { 70 | content: ""; 71 | position: absolute; 72 | z-index: 2; 73 | top: 0; 74 | left: 0; 75 | width: 100%; 76 | border-bottom: $border-width-default $border-style-default $border-color-base; 77 | transform: scaleY(.5); 78 | transform-origin: 0 0; 79 | } 80 | 81 | } 82 | 83 | & .xm__actionsheet--action { 84 | display: block; 85 | margin-top: 10px; 86 | font-size: $font-size-big; 87 | color: $text-color; 88 | height: 50px; 89 | line-height: 50px; 90 | background-color: $body-background; 91 | } 92 | 93 | } -------------------------------------------------------------------------------- /package/comps/components/actionsheet/actionsheet.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 93 | 94 | 97 | -------------------------------------------------------------------------------- /package/comps/components/actionsheet/index.js: -------------------------------------------------------------------------------- 1 | import Actionsheet from './actionsheet.vue' 2 | 3 | export default Actionsheet 4 | -------------------------------------------------------------------------------- /package/comps/components/button/button-group.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /package/comps/components/button/button.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 72 | 73 | 76 | -------------------------------------------------------------------------------- /package/comps/components/button/index.js: -------------------------------------------------------------------------------- 1 | import Button from './button.vue' 2 | import ButtonGroup from './button-group.vue' 3 | 4 | Button.group = ButtonGroup 5 | export default Button 6 | -------------------------------------------------------------------------------- /package/comps/components/buttongroup/index.js: -------------------------------------------------------------------------------- 1 | import ButtonGroup from '../button/button-group.vue' 2 | 3 | export default ButtonGroup 4 | -------------------------------------------------------------------------------- /package/comps/components/cell/cell-group.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /package/comps/components/cell/cell-item.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 62 | 63 | 66 | -------------------------------------------------------------------------------- /package/comps/components/cell/index.js: -------------------------------------------------------------------------------- 1 | import CellItem from './cell-item.vue' 2 | import CellGroup from './cell-group.vue' 3 | 4 | CellGroup.item = CellItem 5 | export default CellGroup 6 | -------------------------------------------------------------------------------- /package/comps/components/cellitem/index.js: -------------------------------------------------------------------------------- 1 | import CellItem from '../cell/cell-item.vue' 2 | 3 | export default CellItem 4 | -------------------------------------------------------------------------------- /package/comps/components/checkbox/checkbox-group.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 51 | 52 | 55 | -------------------------------------------------------------------------------- /package/comps/components/checkbox/checkbox.scss: -------------------------------------------------------------------------------- 1 | .xm__checkbox--group { 2 | width: 100%; 3 | position: relative; 4 | vertical-align: middle; 5 | line-height: normal; 6 | 7 | & .xm__checkbox { 8 | width: 100%; 9 | display: flex; 10 | line-height: $line-height-computed*2.4; 11 | position: relative; 12 | 13 | & .xm__checkbox--icon { 14 | flex: 1; 15 | width: 100%; 16 | color: #525252; 17 | text-align: right; 18 | font-size: $font-size-base; 19 | padding-right: 10px; 20 | justify-content: flex-end; 21 | } 22 | 23 | & > input[type=checkbox] { 24 | position: absolute; 25 | left: -9999em; 26 | 27 | & + .xm__checkbox--icon:before { 28 | color: #ccc; 29 | display: inline; 30 | content: "\E668"; 31 | font-size: $font-size-base*1.5; 32 | position: absolute; 33 | right: 0; 34 | } 35 | 36 | &:checked + .xm__checkbox--icon:before { 37 | color: currentColor; 38 | content: "\E730"; 39 | } 40 | 41 | } 42 | 43 | &.disabled .xm__checkbox--text { 44 | color: #ccc; 45 | } 46 | 47 | &:not(:last-child):after { 48 | content: ""; 49 | position: absolute; 50 | z-index: 1; 51 | bottom: 0; 52 | left: 0; 53 | width: 100%; 54 | border-bottom: $border-width-default $border-style-default $border-color-split; 55 | transform: scaleY(.5) scaleX(1.5); 56 | transform-origin: 0 0; 57 | } 58 | 59 | } 60 | 61 | } 62 | 63 | -------------------------------------------------------------------------------- /package/comps/components/checkbox/checkbox.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 33 | 34 | 37 | -------------------------------------------------------------------------------- /package/comps/components/checkbox/index.js: -------------------------------------------------------------------------------- 1 | import Checkbox from './checkbox.vue' 2 | import CheckboxGroup from './checkbox-group.vue' 3 | 4 | Checkbox.group = CheckboxGroup 5 | export default Checkbox 6 | -------------------------------------------------------------------------------- /package/comps/components/checkboxgroup/index.js: -------------------------------------------------------------------------------- 1 | import CheckboxGroup from '../checkbox/checkbox-group.vue' 2 | 3 | export default CheckboxGroup 4 | -------------------------------------------------------------------------------- /package/comps/components/flexbox/flexbox-item.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /package/comps/components/flexbox/flexbox.scss: -------------------------------------------------------------------------------- 1 | .xm__flexbox { 2 | @include flex() 3 | } -------------------------------------------------------------------------------- /package/comps/components/flexbox/flexbox.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | 25 | 28 | -------------------------------------------------------------------------------- /package/comps/components/flexbox/index.js: -------------------------------------------------------------------------------- 1 | import FlexboxItem from './flexbox-item.vue' 2 | import Flexbox from './flexbox.vue' 3 | 4 | Flexbox.item = FlexboxItem 5 | export default Flexbox 6 | -------------------------------------------------------------------------------- /package/comps/components/flexboxitem/index.js: -------------------------------------------------------------------------------- 1 | import FlexboxItem from '../flexbox/flexbox-item.vue' 2 | 3 | export default FlexboxItem 4 | -------------------------------------------------------------------------------- /package/comps/components/globalmodal/ModalMixin.js: -------------------------------------------------------------------------------- 1 | const ModalMixin = { 2 | props: { 3 | isVisible: { 4 | type: Boolean, 5 | default: false 6 | } 7 | }, 8 | data () { 9 | return { 10 | isActive: false 11 | } 12 | }, 13 | methods: { 14 | active () { 15 | this.isActive = true 16 | }, 17 | close () { 18 | this.$emit('close') 19 | this.isActive = false 20 | } 21 | }, 22 | 23 | watch: { 24 | isVisible (val) { 25 | this.isActive = val 26 | if (val) { 27 | document.body.classList.add('xm--overflow--hidden') 28 | } else { 29 | document.body.classList.remove('xm--overflow--hidden') 30 | } 31 | } 32 | }, 33 | 34 | mounted () { 35 | this.$nextTick(() => { 36 | document.body.appendChild(this.$el) 37 | if (this.isVisible) { 38 | this.active() 39 | } 40 | }) 41 | }, 42 | 43 | beforeDestroy () { 44 | this.$el.remove() 45 | } 46 | } 47 | 48 | export default ModalMixin 49 | -------------------------------------------------------------------------------- /package/comps/components/globalmodal/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import globalModal from './global-modal.vue' 3 | 4 | function open (propsData) { 5 | const ModalComponent = Vue.extend(globalModal) 6 | return new ModalComponent({ 7 | el: document.createElement('div'), 8 | propsData 9 | }) 10 | } 11 | 12 | export default { 13 | confirm (opts) { 14 | const defaultOpts = {title: '', content: '', type: 'confirm', maskClosable: true, color: '', confirmText: '确定', cancelText: '取消', callBack () {}, closeAction () {}} 15 | const propsOpts = Object.assign(defaultOpts, opts) 16 | return open(propsOpts) 17 | }, 18 | 19 | prompt (opts) { 20 | const defaultOpts = {title: '', placeholder: '', type: 'prompt', maskClosable: true, color: '', confirmText: '确定', cancelText: '取消', readonly: false, callBack () {}, closeAction () {}} 21 | const propsOpts = Object.assign(defaultOpts, opts) 22 | return open(propsOpts) 23 | }, 24 | 25 | alert (opts) { 26 | const defaultOpts = {title: '', content: '', type: 'alert', maskClosable: true, color: '', confirmText: '确定', autoClose: false, callBack () {}} 27 | const propsOpts = Object.assign(defaultOpts, opts) 28 | return open(propsOpts) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /package/comps/components/grid/grid.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 27 | 28 | 31 | -------------------------------------------------------------------------------- /package/comps/components/grid/grids.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /package/comps/components/grid/index.js: -------------------------------------------------------------------------------- 1 | import Grid from './grid.vue' 2 | import Grids from './grids.vue' 3 | 4 | Grid.group = Grids 5 | export default Grid 6 | -------------------------------------------------------------------------------- /package/comps/components/grids/index.js: -------------------------------------------------------------------------------- 1 | import Grids from '../grid/grids.vue' 2 | 3 | export default Grids 4 | -------------------------------------------------------------------------------- /package/comps/components/input/index.js: -------------------------------------------------------------------------------- 1 | import Input from './input.vue' 2 | 3 | export default Input 4 | -------------------------------------------------------------------------------- /package/comps/components/input/input.scss: -------------------------------------------------------------------------------- 1 | .xm__input--wrap { 2 | display: flex; 3 | width: 100%; 4 | position: relative; 5 | vertical-align: middle; 6 | line-height: normal; 7 | flex: 1; 8 | } 9 | 10 | .xm__input { 11 | display: flex; 12 | @include size(100%,100%); 13 | align-items: center; 14 | position: relative; 15 | 16 | > input { 17 | display: block; 18 | @include size(100%,100%); 19 | border: none; 20 | font-size: inherit; 21 | background: transparent; 22 | &::-webkit-search-cancel-button { 23 | -webkit-appearance: none; 24 | } 25 | 26 | &.is-right{ 27 | text-align: right; 28 | } 29 | } 30 | 31 | &:before { 32 | content: "*"; 33 | position: absolute; 34 | left: -7px; 35 | font-size: 14px; 36 | color: rgb(255, 68, 68); 37 | display: none; 38 | } 39 | 40 | & .xm__input--close{ 41 | height: 2rem; 42 | width: 2rem; 43 | position: absolute; 44 | top: 0; 45 | bottom: 0; 46 | right: 0; 47 | margin: auto; 48 | 49 | & span{ 50 | margin-left: 0; 51 | font-size: 1.5rem; 52 | color: #c8c8c8; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /package/comps/components/keyboard/index.js: -------------------------------------------------------------------------------- 1 | import KeyBoard from './keyboard.vue' 2 | 3 | export default KeyBoard 4 | -------------------------------------------------------------------------------- /package/comps/components/lazy/index.js: -------------------------------------------------------------------------------- 1 | import Lazy from './lazy.vue' 2 | 3 | export default Lazy 4 | -------------------------------------------------------------------------------- /package/comps/components/lazy/lazy.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monw3c/xmui/9b389127a94b5838a71bc5f3bb9cfff41a1cbef0/package/comps/components/lazy/lazy.scss -------------------------------------------------------------------------------- /package/comps/components/lazy/lazy.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 48 | 49 | 52 | -------------------------------------------------------------------------------- /package/comps/components/loading/index.js: -------------------------------------------------------------------------------- 1 | import Loading from './loading.vue' 2 | 3 | export default Loading 4 | -------------------------------------------------------------------------------- /package/comps/components/loading/loading.scss: -------------------------------------------------------------------------------- 1 | .xm__loading--wrap{ 2 | text-align: center; 3 | } 4 | 5 | .xm__loading{ 6 | 7 | // ripple效果预留 8 | .ripple { 9 | display: inline-block; 10 | position: relative; 11 | @include size(32px,32px); 12 | 13 | & div { 14 | position: absolute; 15 | border: 4px solid #fff; 16 | opacity: 1; 17 | border-radius: 50%; 18 | animation: ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite; 19 | 20 | &:nth-child(2) { 21 | animation-delay: -0.5s; 22 | } 23 | } 24 | } 25 | 26 | & .xm__loading--loader { 27 | animation: spin 1250ms linear infinite; 28 | border: 2px solid $primary-color; 29 | border-right-color: transparent; 30 | @include border-radius(100px); 31 | box-sizing: border-box; 32 | display: inline-block; 33 | position: relative; 34 | overflow: hidden; 35 | text-indent: -9999px; 36 | @include size(32px,32px); 37 | 38 | &.borderRightTransparent { 39 | border-right-color: transparent!important; 40 | } 41 | } 42 | 43 | //非行内的时候 44 | &.xm__loading--fullScreen{ 45 | position: fixed; 46 | top: 50%; 47 | left: 50%; 48 | width: auto; 49 | transform: translate(-50%, -50%); 50 | background: $body-background; 51 | padding: 14px 10px 10px; 52 | @include border-radius(); 53 | z-index: $zindex-loading; 54 | 55 | } 56 | // 垂直显示 57 | & .xm__loading--vertical{ 58 | margin: 0 auto; 59 | display: block; 60 | } 61 | 62 | & .xm__loading--text{ 63 | display: inline-block; 64 | height: 34px; 65 | line-height: 36px; 66 | font-size: $font-size-base; 67 | vertical-align: top; 68 | } 69 | 70 | &.customize{ 71 | padding: 10px; 72 | } 73 | 74 | & .xm__loading--close{ 75 | font-size: $font-size-small*0.9; 76 | vertical-align: middle; 77 | position: absolute; 78 | right: -0.5rem; 79 | top: -0.5rem; 80 | width: 1.5rem; 81 | height: 1.5rem; 82 | line-height: 1.5rem; 83 | text-align: center; 84 | background: $body-background; 85 | @include border-radius(30px); 86 | color: $close-color; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /package/comps/components/loading/loading.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 75 | 76 | 79 | -------------------------------------------------------------------------------- /package/comps/components/loadmore/index.js: -------------------------------------------------------------------------------- 1 | import LoadMore from './loadMore.vue' 2 | 3 | export default LoadMore 4 | -------------------------------------------------------------------------------- /package/comps/components/loadmore/loadMore.scss: -------------------------------------------------------------------------------- 1 | .xm__loadMore { 2 | display: inline-block; 3 | line-height: 1em; 4 | cursor: pointer; 5 | color: rgb(31, 45, 61); 6 | -webkit-appearance: none; 7 | box-sizing: border-box; 8 | text-align: center; 9 | white-space: nowrap; 10 | font-size: $font-size-base; 11 | padding: 5px 8px; 12 | width: 100%; 13 | margin: 1em auto; 14 | } 15 | 16 | .xm__loadmore--line { 17 | border-top: 1px solid #E5E5E5; 18 | margin-top: 2em; 19 | 20 | & .xm__loadmore--tips { 21 | position: relative; 22 | top: -0.9em; 23 | padding: 0 .55em; 24 | background-color: #FFFFFF; 25 | color: #999999; 26 | } 27 | } -------------------------------------------------------------------------------- /package/comps/components/loadmore/loadMore.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 40 | 41 | 44 | -------------------------------------------------------------------------------- /package/comps/components/modal/index.js: -------------------------------------------------------------------------------- 1 | import Modal from './modal.vue' 2 | 3 | export default Modal 4 | -------------------------------------------------------------------------------- /package/comps/components/navbar/index.js: -------------------------------------------------------------------------------- 1 | import Navbar from './navbar.vue' 2 | 3 | export default Navbar 4 | -------------------------------------------------------------------------------- /package/comps/components/navbar/navbar.scss: -------------------------------------------------------------------------------- 1 | .xm__navbar{ 2 | @include size(100%,4rem); 3 | background-color: $body-background; 4 | position: relative; 5 | user-select: none; 6 | text-align: center; 7 | line-height: 4rem; 8 | display: flex; 9 | 10 | &:after{ 11 | content: ""; 12 | position: absolute; 13 | bottom: 0; 14 | left: 0; 15 | width: 100%; 16 | border-bottom: $border-width-default $border-style-default $border-color-base; 17 | transform: scaleY(.5); 18 | transform-origin: 0 0; 19 | } 20 | 21 | & .xm__navbar--left, 22 | & .xm__navbar--right { 23 | font-size: $font-size-base; 24 | min-width: 3.5rem; 25 | } 26 | 27 | & .xm__navbar--left { 28 | 29 | & .xm__navbar--icon{ 30 | margin-left: 5px; 31 | } 32 | } 33 | 34 | & .xm__navbar--right { 35 | 36 | & .xm__navbar--icon{ 37 | margin-right: 5px; 38 | font-size: 1.8rem; 39 | } 40 | } 41 | 42 | & .xm__navbar--title { 43 | font-size: 1.8rem; 44 | white-space: nowrap; 45 | overflow: hidden; 46 | text-overflow: ellipsis; 47 | flex: 1; 48 | color: #555; 49 | margin: 0 20px; 50 | 51 | & img{ 52 | max-height: 3.5rem; 53 | height: 3.5rem; 54 | vertical-align: middle; 55 | } 56 | } 57 | } 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /package/comps/components/navbar/navbar.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 79 | 80 | 83 | -------------------------------------------------------------------------------- /package/comps/components/popup/index.js: -------------------------------------------------------------------------------- 1 | import Popup from './popup.vue' 2 | 3 | export default Popup 4 | -------------------------------------------------------------------------------- /package/comps/components/popup/popup.scss: -------------------------------------------------------------------------------- 1 | .xm__mask { 2 | @include mask 3 | } 4 | 5 | .xm__popup { 6 | text-align: center; 7 | position: fixed; 8 | bottom: 0; 9 | left: 0; 10 | width: 100%; 11 | z-index: $zindex-popover; 12 | background-color: $body-background; 13 | transform: translate(0, 100%); 14 | transition: transform .3s; 15 | 16 | &.xm__popup--active { 17 | transform: translate(0, 0); 18 | } 19 | 20 | & header{ 21 | font-size: $font-size-small; 22 | color: $text-color; 23 | height: 40px; 24 | line-height: 40px; 25 | background-color: $body-background; 26 | border-bottom: $border-width-default $border-style-default $border-color-base; 27 | } 28 | 29 | & .xm__popup--action { 30 | display: block; 31 | font-size: 1.3rem; 32 | color: $text-color; 33 | position: absolute; 34 | top: 0; 35 | right: 0; 36 | width: 4rem; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /package/comps/components/popup/popup.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 72 | 73 | 76 | -------------------------------------------------------------------------------- /package/comps/components/radio/index.js: -------------------------------------------------------------------------------- 1 | import Radio from './radio.vue' 2 | import RadioGroup from './radio-group.vue' 3 | 4 | Radio.group = RadioGroup 5 | export default Radio 6 | -------------------------------------------------------------------------------- /package/comps/components/radio/radio-group.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 55 | 56 | 59 | -------------------------------------------------------------------------------- /package/comps/components/radio/radio.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 39 | 40 | 43 | -------------------------------------------------------------------------------- /package/comps/components/radiogroup/index.js: -------------------------------------------------------------------------------- 1 | import RadioGroup from '../radio/radio-group.vue' 2 | 3 | export default RadioGroup 4 | -------------------------------------------------------------------------------- /package/comps/components/seamlessscroll/index.js: -------------------------------------------------------------------------------- 1 | import SeamlessScrollItem from './seamlessscroll-item.vue' 2 | import SeamlessScroll from './seamlessscroll.vue' 3 | 4 | SeamlessScroll.item = SeamlessScrollItem 5 | export default SeamlessScroll 6 | -------------------------------------------------------------------------------- /package/comps/components/seamlessscroll/seamlessscroll-item.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 18 | -------------------------------------------------------------------------------- /package/comps/components/seamlessscroll/seamlessscroll.scss: -------------------------------------------------------------------------------- 1 | .xm__seamlessscroll { 2 | overflow: hidden; 3 | width: 100%; 4 | background-color: #fff; 5 | 6 | &--box { 7 | height: inherit; 8 | } 9 | 10 | &--align { 11 | &-left { 12 | justify-content: flex-start; 13 | } 14 | 15 | &-right { 16 | justify-content: flex-end; 17 | } 18 | 19 | &-center { 20 | justify-content: center; 21 | } 22 | } 23 | 24 | &--item { 25 | height: inherit; 26 | display: flex; 27 | align-items: center; 28 | justify-content: inherit; 29 | font-size: $font-size-small; 30 | } 31 | } -------------------------------------------------------------------------------- /package/comps/components/seamlessscrollitem/index.js: -------------------------------------------------------------------------------- 1 | import SeamlessScrollItem from '../seamlessscroll/seamlessscroll-item.vue' 2 | 3 | export default SeamlessScrollItem 4 | -------------------------------------------------------------------------------- /package/comps/components/search/index.js: -------------------------------------------------------------------------------- 1 | import Search from './search.vue' 2 | 3 | export default Search 4 | -------------------------------------------------------------------------------- /package/comps/components/search/search.scss: -------------------------------------------------------------------------------- 1 | .xm__search { 2 | display: flex; 3 | align-items: center; 4 | box-sizing: border-box; 5 | padding: 4px; 6 | 7 | & .xm__icon--search { 8 | color: #666; 9 | position: absolute; 10 | top: 50%; 11 | transform: translateY(-50%); 12 | left: 10px; 13 | font-size: $font-size-base; 14 | } 15 | } 16 | 17 | .xm__search--action,.xm__search--cancel { 18 | line-height: $line-height-computed; 19 | font-size: $font-size-small; 20 | letter-spacing: 1px; 21 | 22 | & div{ 23 | padding: 0 0 0 10px; 24 | } 25 | } 26 | 27 | .xm__search--input--wrap{ 28 | position: relative; 29 | flex: 1; 30 | height: 34px; 31 | box-sizing: border-box; 32 | padding: 4px 24px 4px 35px; 33 | border: 1px solid #e5e5e5; 34 | @include border-radius(30px); 35 | background-color: #fff; 36 | } 37 | 38 | .xm__search--input { 39 | display: block; 40 | width: 100%; 41 | height: 24px; 42 | line-height: 24px; 43 | padding: 0; 44 | font-size: $font-size-base; 45 | color: #666; 46 | border: none; 47 | } 48 | 49 | .xm__icon--clear { 50 | color: #c8c8c8; 51 | position: absolute; 52 | top: 50%; 53 | transform: translateY(-50%); 54 | right: 1rem; 55 | font-size: $font-size-base; 56 | } -------------------------------------------------------------------------------- /package/comps/components/select/index.js: -------------------------------------------------------------------------------- 1 | import Select from './select.vue' 2 | 3 | export default Select 4 | -------------------------------------------------------------------------------- /package/comps/components/select/select.scss: -------------------------------------------------------------------------------- 1 | .xm__select { 2 | flex: 1; 3 | height: 40px; 4 | border: none; 5 | display: block; 6 | 7 | 8 | & select { 9 | border: none; 10 | display: block; 11 | @include size(100%,40px); 12 | color: $text-color; 13 | font-size: $font-size-base; 14 | background-color: $body-background; 15 | outline: none; 16 | -webkit-appearance:none; 17 | 18 | &.is-right{ 19 | direction: rtl; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /package/comps/components/select/select.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 49 | 50 | 53 | -------------------------------------------------------------------------------- /package/comps/components/skeleton/index.js: -------------------------------------------------------------------------------- 1 | import Skeleton from './skeleton.vue' 2 | 3 | export default Skeleton 4 | -------------------------------------------------------------------------------- /package/comps/components/skeleton/skeleton.scss: -------------------------------------------------------------------------------- 1 | .xm__skeleton--circle { 2 | @include size(50px,50px); 3 | @include border-radius(100px); 4 | background: $skeleton-bg; 5 | opacity: .5; 6 | } 7 | 8 | .xm__skeleton--bar { 9 | opacity: .5; 10 | @include size(100%,24px); 11 | background: $skeleton-bg; 12 | } 13 | 14 | .xm__skeleton--opacity{ 15 | animation: opacity 1s ease-in-out infinite; 16 | } 17 | 18 | .xm__skeleton--loading{ 19 | animation: bar-loading 1s ease-in-out infinite; 20 | } -------------------------------------------------------------------------------- /package/comps/components/skeleton/skeleton.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 28 | 29 | 32 | -------------------------------------------------------------------------------- /package/comps/components/spmodal/index.js: -------------------------------------------------------------------------------- 1 | import SpModal from './sp-modal.vue' 2 | 3 | export default SpModal 4 | -------------------------------------------------------------------------------- /package/comps/components/spmodal/sp-modal.vue: -------------------------------------------------------------------------------- 1 | /* special modal特殊的弹出层,可用于活动专题 */ 2 | 20 | 21 | 81 | 82 | 85 | -------------------------------------------------------------------------------- /package/comps/components/spmodal/spmodal.scss: -------------------------------------------------------------------------------- 1 | .xm__mask { 2 | @include mask 3 | } 4 | 5 | .xm__dialog--special{ 6 | position: fixed; 7 | text-align: center; 8 | top: 50%; 9 | left: 50%; 10 | width: 85%; 11 | max-width: 300px; 12 | font-size: 16px; 13 | overflow: hidden; 14 | transition: .2s; 15 | border-radius: 4px; 16 | background-color: transparent; 17 | transform: translate3d(-50%, -50%, 0); 18 | z-index: 1000; 19 | 20 | & .xm__dialog--bd{ 21 | max-height: 320px; 22 | overflow: hidden; 23 | 24 | & img{ 25 | width: 100%; 26 | border-radius: 4px; 27 | } 28 | } 29 | 30 | & .xm__dialog--ft { 31 | margin-bottom: 0; 32 | 33 | & button.xm__btn--default{ 34 | background: transparent; 35 | margin: 0 auto; 36 | 37 | &::before{ 38 | border: none; 39 | } 40 | 41 | &:hover, 42 | &:active { 43 | background-color: transparent; 44 | text-decoration: none; 45 | border: none; 46 | } 47 | 48 | & .xm__icon--close-outline { 49 | font-size: 34px; 50 | color: #fff; 51 | } 52 | 53 | &::before { 54 | border: none; 55 | } 56 | 57 | &:first-child { 58 | background-color: transparent; 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /package/comps/components/step/index.js: -------------------------------------------------------------------------------- 1 | import Step from './step.vue' 2 | 3 | export default Step 4 | -------------------------------------------------------------------------------- /package/comps/components/step/step.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 49 | 50 | 53 | -------------------------------------------------------------------------------- /package/comps/components/switch/index.js: -------------------------------------------------------------------------------- 1 | import Switch from './switch.vue' 2 | 3 | export default Switch 4 | -------------------------------------------------------------------------------- /package/comps/components/switch/switch.scss: -------------------------------------------------------------------------------- 1 | .xm__switch { 2 | position: relative; 3 | z-index: 10; 4 | display: block; 5 | @include size(52px,28px); 6 | left: 0; 7 | border: $border-width-default $border-style-default $border-color-base; 8 | @include border-radius(16px); 9 | background-color: #dfdfdf; 10 | -webkit-appearance: none; 11 | color: #4cd864; 12 | 13 | &:checked { 14 | border-color: currentColor; 15 | background-color: currentColor; 16 | 17 | &:before { 18 | transform: scale(0); 19 | transition: transform .3s; 20 | } 21 | &:after { 22 | transform: translateX(24px); 23 | transition: transform .3s; 24 | } 25 | } 26 | 27 | &[disabled] { 28 | opacity: 0.5; 29 | } 30 | 31 | &:after, 32 | &:before { 33 | content: ""; 34 | position: absolute; 35 | top: 0; 36 | left: 0; 37 | height: 26px; 38 | @include border-radius(15px); 39 | transition: transform .3s; 40 | } 41 | 42 | &:before { 43 | width: 50px; 44 | background-color: #FDFDFD; 45 | } 46 | 47 | &:after { 48 | width: 26px; 49 | background-color: $body-background; 50 | box-shadow: 0 1px 3px rgba(0, 0, 0, .4); 51 | } 52 | } -------------------------------------------------------------------------------- /package/comps/components/switch/switch.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 31 | 32 | 35 | -------------------------------------------------------------------------------- /package/comps/components/tabbar/index.js: -------------------------------------------------------------------------------- 1 | import TabbarItem from './tabbar-item.vue' 2 | import Tabbar from './tabbar.vue' 3 | 4 | Tabbar.item = TabbarItem 5 | export default Tabbar 6 | -------------------------------------------------------------------------------- /package/comps/components/tabbar/tabbar.scss: -------------------------------------------------------------------------------- 1 | .xm__tabbar{ 2 | @include size(100%,5rem); 3 | display: flex; 4 | background-color: $body-background; 5 | } 6 | 7 | 8 | 9 | .xm__tabbar--item { 10 | flex: 1; 11 | color: $text-color; 12 | display: flex; 13 | line-height: $line-height-base; 14 | font-size: $font-size-small; 15 | align-items: center; 16 | flex-direction: column; 17 | justify-content: center; 18 | 19 | &.xm__tabbar--item-active { 20 | color: $success-color; 21 | } 22 | 23 | &.router-link-active{ 24 | color: $success-color; 25 | } 26 | 27 | & .xm__tabbar--item-icon { 28 | position: relative; 29 | display: flex; 30 | align-items: center; 31 | height: 3rem; 32 | 33 | & img { 34 | width: 2.2rem; 35 | 36 | } 37 | 38 | & .xm__icon { 39 | display: block; 40 | font-size: 2.2rem; 41 | padding: 0 2px; 42 | } 43 | 44 | & .xm__tabbar--item-badge { 45 | display: inline-block; 46 | padding: 2px 4px; 47 | min-width: 8px; 48 | @include border-radius(18px); 49 | background-color: $error-color; 50 | color: #fff; 51 | line-height: 1.2; 52 | text-align: center; 53 | font-size: .7em; 54 | vertical-align: middle; 55 | position: absolute; 56 | top: 2px; 57 | right: -10px; 58 | } 59 | 60 | & .xm__tabbar--item-dot { 61 | display: inline-block; 62 | @include size(6px,6px); 63 | @include border-radius(100px); 64 | background-color: $error-color; 65 | position: absolute; 66 | top: 5px; 67 | right: -5px; 68 | } 69 | 70 | } 71 | 72 | 73 | } 74 | 75 | -------------------------------------------------------------------------------- /package/comps/components/tabbar/tabbar.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 22 | 23 | 26 | -------------------------------------------------------------------------------- /package/comps/components/tabbaritem/index.js: -------------------------------------------------------------------------------- 1 | import TabbarItem from '../tabbar/tabbar-item.vue' 2 | 3 | export default TabbarItem 4 | -------------------------------------------------------------------------------- /package/comps/components/tag/index.js: -------------------------------------------------------------------------------- 1 | import Tag from './tag.vue' 2 | 3 | export default Tag 4 | -------------------------------------------------------------------------------- /package/comps/components/tag/tag.scss: -------------------------------------------------------------------------------- 1 | .xm__tag { 2 | display: inline-block; 3 | line-height: 1.2; 4 | cursor: pointer; 5 | color: rgb(31, 45, 61); 6 | -webkit-appearance: none; 7 | box-sizing: border-box; 8 | text-align: center; 9 | white-space: nowrap; 10 | font-size: $font-size-small; 11 | margin: 0px; 12 | @include border-radius; 13 | padding: 3px 8px; 14 | 15 | & .xm__tag--close{ 16 | font-size: 1.2rem; 17 | vertical-align: middle; 18 | } 19 | 20 | &.is-round{ 21 | @include border-radius(100px); 22 | } 23 | 24 | &.xm__tag--default { 25 | color: $btn-default-color; 26 | background: $btn-default-bg; 27 | border: $border-width-default $border-style-default $border-color-base; 28 | } 29 | 30 | &.xm__tag--success { 31 | @extend .xm__tag--default; 32 | color: $btn-success-color; 33 | background: $btn-success-bg; 34 | border: $border-width-default $border-style-default $btn-success-bg; 35 | } 36 | 37 | &.xm__tag--primary { 38 | @extend .xm__tag--default; 39 | color: $btn-primary-color; 40 | background: $btn-primary-bg; 41 | border: $border-width-default $border-style-default $btn-primary-bg; 42 | } 43 | 44 | &.xm__tag--warning { 45 | @extend .xm__tag--default; 46 | color: $btn-warning-color; 47 | background: $btn-warning-bg; 48 | border: $border-width-default $border-style-default $btn-warning-bg; 49 | } 50 | 51 | &.xm__tag--warning { 52 | @extend .xm__tag--default; 53 | color: $btn-warning-color; 54 | background: $btn-warning-bg; 55 | border: $border-width-default $border-style-default $btn-warning-bg; 56 | } 57 | 58 | &.xm__tag--error { 59 | @extend .xm__tag--default; 60 | color: $btn-error-color; 61 | background: $btn-error-bg; 62 | border: $border-width-default $border-style-default $btn-error-bg; 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /package/comps/components/tag/tag.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 49 | 50 | 53 | -------------------------------------------------------------------------------- /package/comps/components/textarea/index.js: -------------------------------------------------------------------------------- 1 | import Textarea from './textarea.vue' 2 | 3 | export default Textarea 4 | -------------------------------------------------------------------------------- /package/comps/components/textarea/textarea.scss: -------------------------------------------------------------------------------- 1 | .xm__textarea{ 2 | padding: 10px 0; 3 | background-color: $body-background; 4 | width: 100%; 5 | 6 | & textarea { 7 | border: none; 8 | display: block; 9 | @include size(100%,100px); 10 | font-size: $font-size-base; 11 | outline: none; 12 | resize: none; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /package/comps/components/textarea/textarea.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 47 | 48 | 51 | -------------------------------------------------------------------------------- /package/comps/components/toast/ToastMixin.js: -------------------------------------------------------------------------------- 1 | const ModalMixin = { 2 | props: { 3 | isVisible: { 4 | type: Boolean, 5 | default: false 6 | } 7 | }, 8 | data () { 9 | return { 10 | isActive: false 11 | } 12 | }, 13 | methods: { 14 | active () { 15 | this.isActive = true 16 | } 17 | }, 18 | 19 | watch: { 20 | isVisible (val) { 21 | this.isActive = val 22 | } 23 | }, 24 | 25 | mounted () { 26 | this.$nextTick(() => { 27 | document.body.appendChild(this.$el) 28 | if (this.isVisible) { 29 | this.active() 30 | } 31 | }) 32 | }, 33 | 34 | beforeDestroy () { 35 | this.$el.remove() 36 | } 37 | } 38 | 39 | export default ModalMixin 40 | -------------------------------------------------------------------------------- /package/comps/components/toast/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Toast from './toast.vue' 3 | 4 | function open (propsData) { 5 | const ToastComponent = Vue.extend(Toast) 6 | return new ToastComponent({ 7 | el: document.createElement('div'), 8 | propsData 9 | }) 10 | } 11 | 12 | export default { 13 | text (opts) { 14 | const defaultOpts = {content: '', mask: false, direction: '', callBack () {}} 15 | const propsOpts = Object.assign(defaultOpts, opts) 16 | return open(propsOpts) 17 | }, 18 | 19 | loading (opts) { 20 | const defaultOpts = {content: '', type: 'default', mask: true, callBack () {}} 21 | const propsOpts = Object.assign(defaultOpts, opts) 22 | return open(propsOpts) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /package/comps/components/toast/toast.scss: -------------------------------------------------------------------------------- 1 | .xm__toast { 2 | position: fixed; 3 | top: 50%; 4 | left: 50%; 5 | display: flex; 6 | color: #fff; 7 | z-index: 3001; 8 | font-size: $font-size-small; 9 | line-height: 1.2; 10 | @include border-radius; 11 | align-items: center; 12 | justify-content: center; 13 | flex-direction: column; 14 | box-sizing: border-box; 15 | transform: translate3d(-50%, -50%, 0); 16 | background-color: rgba(39, 39, 39, .7); 17 | 18 | 19 | &.xm__toast--text { 20 | padding: 12px; 21 | min-width: 220px; 22 | } 23 | 24 | &.xm__toast--loading { 25 | width: 120px; 26 | min-height: 120px; 27 | padding: 15px; 28 | } 29 | 30 | & .xm__loading { 31 | font-size: 0; 32 | line-height: 0; 33 | z-index: 0; 34 | position: relative; 35 | } 36 | 37 | & .xm__toast--loading .xm__loading { 38 | margin: 10px 0 5px; 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /package/comps/components/toast/toast.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | -------------------------------------------------------------------------------- /package/comps/styles/animation.scss: -------------------------------------------------------------------------------- 1 | .fade-enter-active { 2 | animation-name: fade-in; 3 | animation-duration: .5s; 4 | } 5 | .fade-leave-active { 6 | animation-name: fade-out; 7 | animation-duration: .5s; 8 | } 9 | 10 | .lazy-enter { 11 | opacity: 0; 12 | } 13 | .lazy-enter-to { 14 | opacity: 1; 15 | } 16 | .lazy-enter-active { 17 | transition: opacity 0.3s 0.2s; 18 | width: 100%; 19 | } 20 | .lazy-leave { 21 | opacity: 1; 22 | } 23 | .lazy-leave-to { 24 | opacity: 0; 25 | } 26 | .lazy-leave-active { 27 | transition: opacity 0.5s; 28 | } 29 | 30 | .slide-up-enter-active, .slide-up-leave-active { 31 | transform: translate(-50%, 0); 32 | } 33 | 34 | .slide-up-enter, .slide-up-leave-to { 35 | transform: translate(-50%, 70%); 36 | } 37 | 38 | .slide-up-leave-active { 39 | transform: translate(-50%, 100%); 40 | } 41 | 42 | @keyframes fade-in { 43 | from { 44 | opacity: 0; 45 | } 46 | 47 | to { 48 | opacity: 1; 49 | } 50 | } 51 | 52 | 53 | 54 | @keyframes fade-out { 55 | from { 56 | opacity: 1; 57 | } 58 | to { 59 | opacity: 0; 60 | } 61 | } 62 | 63 | // loading样式 64 | @keyframes spin { 65 | 0% { 66 | transform: rotate(0deg); 67 | } 68 | 100% { 69 | transform: rotate(360deg); 70 | } 71 | } 72 | 73 | // opacity样式 74 | @keyframes opacity { 75 | 0% {opacity: 1;} 76 | 10% {opacity: 0.9;} 77 | 20% {opacity: 0.8;} 78 | 30% {opacity: 0.7;} 79 | 40% {opacity: 0.6;} 80 | 50% {opacity: 0.5;} 81 | 60% {opacity: 0.6;} 82 | 70% {opacity: 0.7;} 83 | 80% {opacity: 0.8;} 84 | 90% {opacity: 0.9;} 85 | 100% {opacity: 0.95;} 86 | } 87 | 88 | @keyframes bar-loading { 89 | 0% { 90 | width:60% 91 | } 92 | 50% { 93 | width:100% 94 | } 95 | 100% { 96 | width:60% 97 | } 98 | } 99 | 100 | @keyframes ripple { 101 | 0% { 102 | top: 28px; 103 | left: 28px; 104 | width: 0; 105 | height: 0; 106 | opacity: 1; 107 | } 108 | 100% { 109 | top: -1px; 110 | left: -1px; 111 | width: 58px; 112 | height: 58px; 113 | opacity: 0; 114 | } 115 | } -------------------------------------------------------------------------------- /package/comps/styles/common.scss: -------------------------------------------------------------------------------- 1 | 2 | html{ 3 | font-size: 62.5%; 4 | -webkit-tap-highlight-color: transparent; 5 | } 6 | input, button{ 7 | outline: none; 8 | } 9 | 10 | a{ 11 | text-decoration: none; 12 | } 13 | 14 | .xm--overflow--hidden{ 15 | overflow: hidden!important; 16 | } -------------------------------------------------------------------------------- /package/comps/styles/index.scss: -------------------------------------------------------------------------------- 1 | @import "varibles"; 2 | @import "mixin"; 3 | @import "normalize"; 4 | @import "animation"; 5 | @import "common"; 6 | @import "icon"; 7 | 8 | @import "../components/button/button.scss"; 9 | @import "../components/loadmore/loadMore.scss"; 10 | @import "../components/tag/tag.scss"; 11 | @import "../components/search/search.scss"; 12 | @import "../components/globalmodal/modal.scss"; 13 | @import "../components/spmodal/spmodal.scss"; 14 | @import "../components/loading/loading.scss"; 15 | @import "../components/step/step.scss"; 16 | @import "../components/toast/toast.scss"; 17 | @import "../components/cell/cell.scss"; 18 | @import "../components/input/input.scss"; 19 | @import "../components/textarea/textarea.scss"; 20 | @import "../components/select/select.scss"; 21 | @import "../components/switch/switch.scss"; 22 | @import "../components/skeleton/skeleton.scss"; 23 | @import "../components/grid/grid.scss"; 24 | @import "../components/radio/radio.scss"; 25 | @import "../components/checkbox/checkbox.scss"; 26 | @import "../components/tabbar/tabbar.scss"; 27 | @import "../components/navbar/navbar.scss"; 28 | @import "../components/actionsheet/actionsheet.scss"; 29 | @import "../components/flexbox/flexbox.scss"; 30 | @import "../components/seamlessscroll/seamlessscroll.scss"; 31 | @import "../components/popup/popup.scss"; 32 | @import "../components/lazy/lazy.scss"; 33 | @import "../components/keyboard/keyboard.scss"; 34 | -------------------------------------------------------------------------------- /package/comps/styles/mixin.scss: -------------------------------------------------------------------------------- 1 | // border圆角 2 | @mixin border-radius($radius:$border-radius-small){ 3 | -webkit-border-radius: $radius; 4 | border-radius: $radius; 5 | } 6 | 7 | // 宽高 8 | @mixin size($width,$height){ 9 | width: $width; 10 | height: $height; 11 | } 12 | 13 | // 遮罩层 14 | @mixin mask(){ 15 | position: fixed; 16 | top: 0; 17 | bottom: 0; 18 | left: 0; 19 | right: 0; 20 | background-color: rgba(55, 55, 55, 0.6); 21 | height: 100%; 22 | z-index: $zindex-modal-mask; 23 | transition: opacity .2s ease-in; 24 | pointer-events: auto; 25 | 26 | &--hidden { 27 | display: none; 28 | } 29 | } 30 | 31 | // 按下去背景颜色 32 | @mixin tap-color($bgcolor, $opacity:.9) { 33 | 34 | &:active { 35 | background-color: $bgcolor * $opacity; 36 | } 37 | } 38 | 39 | // flex布局 40 | @mixin flex(){ 41 | display: flex; 42 | align-items: center; 43 | 44 | & .xm__flex--item { 45 | flex: 1; 46 | } 47 | 48 | &.xm__flex--vertical { 49 | flex-direction: column; 50 | height: 100%; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | 37 | -------------------------------------------------------------------------------- /src/assets/3333.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monw3c/xmui/9b389127a94b5838a71bc5f3bb9cfff41a1cbef0/src/assets/3333.png -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monw3c/xmui/9b389127a94b5838a71bc5f3bb9cfff41a1cbef0/src/assets/logo.png -------------------------------------------------------------------------------- /src/comps/components/actionsheet/actionsheet.scss: -------------------------------------------------------------------------------- 1 | .xm__mask { 2 | @include mask 3 | } 4 | 5 | .xm__actionsheet { 6 | text-align: center; 7 | position: fixed; 8 | bottom: 0; 9 | left: 0; 10 | width: 100%; 11 | z-index: $zindex-popover; 12 | background-color: #efeff4; 13 | transform: translate(0, 100%); 14 | transition: transform .3s; 15 | 16 | &.xm__actionsheet--active { 17 | transform: translate(0, 0); 18 | } 19 | 20 | & header{ 21 | font-size: 1.3rem; 22 | color: $text-color; 23 | height: 40px; 24 | line-height: 40px; 25 | background-color: $body-background; 26 | } 27 | 28 | & ul { 29 | margin: 0; 30 | padding: 0; 31 | } 32 | 33 | & .xm__actionsheet--item { 34 | display: flex; 35 | justify-content: center; 36 | align-items: center; 37 | position: relative; 38 | font-size: $font-size-big; 39 | color: $text-color; 40 | height: 50px; 41 | // line-height: 50px; 42 | background-color: $body-background; 43 | 44 | & .xm__actionsheet--icon{ 45 | max-height: 40px; 46 | margin-right: 5px; 47 | 48 | & img{ 49 | max-height: 40px; 50 | } 51 | 52 | & p{ 53 | margin: 0; 54 | } 55 | } 56 | 57 | &:after { 58 | content: ""; 59 | position: absolute; 60 | z-index: 2; 61 | bottom: 0; 62 | left: 0; 63 | width: 100%; 64 | border-bottom: $border-width-default $border-style-default $border-color-base; 65 | transform: scaleY(.5); 66 | transform-origin: 0 0; 67 | } 68 | 69 | &:first-child:before { 70 | content: ""; 71 | position: absolute; 72 | z-index: 2; 73 | top: 0; 74 | left: 0; 75 | width: 100%; 76 | border-bottom: $border-width-default $border-style-default $border-color-base; 77 | transform: scaleY(.5); 78 | transform-origin: 0 0; 79 | } 80 | 81 | } 82 | 83 | & .xm__actionsheet--action { 84 | display: block; 85 | margin-top: 10px; 86 | font-size: $font-size-big; 87 | color: $text-color; 88 | height: 50px; 89 | line-height: 50px; 90 | background-color: $body-background; 91 | } 92 | 93 | } -------------------------------------------------------------------------------- /src/comps/components/actionsheet/actionsheet.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 93 | 94 | 97 | -------------------------------------------------------------------------------- /src/comps/components/actionsheet/index.js: -------------------------------------------------------------------------------- 1 | import Actionsheet from './actionsheet.vue' 2 | 3 | export default Actionsheet 4 | -------------------------------------------------------------------------------- /src/comps/components/button/button-group.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /src/comps/components/button/button.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 72 | 73 | 76 | -------------------------------------------------------------------------------- /src/comps/components/button/index.js: -------------------------------------------------------------------------------- 1 | import Button from './button.vue' 2 | import ButtonGroup from './button-group.vue' 3 | 4 | Button.group = ButtonGroup 5 | export default Button 6 | -------------------------------------------------------------------------------- /src/comps/components/buttongroup/index.js: -------------------------------------------------------------------------------- 1 | import ButtonGroup from '../button/button-group.vue' 2 | 3 | export default ButtonGroup 4 | -------------------------------------------------------------------------------- /src/comps/components/cell/cell-group.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /src/comps/components/cell/cell-item.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 62 | 63 | 66 | -------------------------------------------------------------------------------- /src/comps/components/cell/index.js: -------------------------------------------------------------------------------- 1 | import CellItem from './cell-item.vue' 2 | import CellGroup from './cell-group.vue' 3 | 4 | CellGroup.item = CellItem 5 | export default CellGroup 6 | -------------------------------------------------------------------------------- /src/comps/components/cellitem/index.js: -------------------------------------------------------------------------------- 1 | import CellItem from '../cell/cell-item.vue' 2 | 3 | export default CellItem 4 | -------------------------------------------------------------------------------- /src/comps/components/checkbox/checkbox-group.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 51 | 52 | 55 | -------------------------------------------------------------------------------- /src/comps/components/checkbox/checkbox.scss: -------------------------------------------------------------------------------- 1 | .xm__checkbox--group { 2 | width: 100%; 3 | position: relative; 4 | vertical-align: middle; 5 | line-height: normal; 6 | 7 | & .xm__checkbox { 8 | width: 100%; 9 | display: flex; 10 | line-height: $line-height-computed*2.4; 11 | position: relative; 12 | 13 | & .xm__checkbox--icon { 14 | flex: 1; 15 | width: 100%; 16 | color: #525252; 17 | text-align: right; 18 | font-size: $font-size-base; 19 | padding-right: 10px; 20 | justify-content: flex-end; 21 | } 22 | 23 | & > input[type=checkbox] { 24 | position: absolute; 25 | left: -9999em; 26 | 27 | & + .xm__checkbox--icon:before { 28 | color: #ccc; 29 | display: inline; 30 | content: "\E668"; 31 | font-size: $font-size-base*1.5; 32 | position: absolute; 33 | right: 0; 34 | } 35 | 36 | &:checked + .xm__checkbox--icon:before { 37 | color: currentColor; 38 | content: "\E730"; 39 | } 40 | 41 | } 42 | 43 | &.disabled .xm__checkbox--text { 44 | color: #ccc; 45 | } 46 | 47 | &:not(:last-child):after { 48 | content: ""; 49 | position: absolute; 50 | z-index: 1; 51 | bottom: 0; 52 | left: 0; 53 | width: 100%; 54 | border-bottom: $border-width-default $border-style-default $border-color-split; 55 | transform: scaleY(.5) scaleX(1.5); 56 | transform-origin: 0 0; 57 | } 58 | 59 | } 60 | 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/comps/components/checkbox/checkbox.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 33 | 34 | 37 | -------------------------------------------------------------------------------- /src/comps/components/checkbox/index.js: -------------------------------------------------------------------------------- 1 | import Checkbox from './checkbox.vue' 2 | import CheckboxGroup from './checkbox-group.vue' 3 | 4 | Checkbox.group = CheckboxGroup 5 | export default Checkbox 6 | -------------------------------------------------------------------------------- /src/comps/components/checkboxgroup/index.js: -------------------------------------------------------------------------------- 1 | import CheckboxGroup from '../checkbox/checkbox-group.vue' 2 | 3 | export default CheckboxGroup 4 | -------------------------------------------------------------------------------- /src/comps/components/flexbox/flexbox-item.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/comps/components/flexbox/flexbox.scss: -------------------------------------------------------------------------------- 1 | .xm__flexbox { 2 | @include flex() 3 | } -------------------------------------------------------------------------------- /src/comps/components/flexbox/flexbox.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | 25 | 28 | -------------------------------------------------------------------------------- /src/comps/components/flexbox/index.js: -------------------------------------------------------------------------------- 1 | import FlexboxItem from './flexbox-item.vue' 2 | import Flexbox from './flexbox.vue' 3 | 4 | Flexbox.item = FlexboxItem 5 | export default Flexbox 6 | -------------------------------------------------------------------------------- /src/comps/components/flexboxitem/index.js: -------------------------------------------------------------------------------- 1 | import FlexboxItem from '../flexbox/flexbox-item.vue' 2 | 3 | export default FlexboxItem 4 | -------------------------------------------------------------------------------- /src/comps/components/globalmodal/ModalMixin.js: -------------------------------------------------------------------------------- 1 | const ModalMixin = { 2 | props: { 3 | isVisible: { 4 | type: Boolean, 5 | default: false 6 | } 7 | }, 8 | data () { 9 | return { 10 | isActive: false 11 | } 12 | }, 13 | methods: { 14 | active () { 15 | this.isActive = true 16 | }, 17 | close () { 18 | this.$emit('close') 19 | this.isActive = false 20 | } 21 | }, 22 | 23 | watch: { 24 | isVisible (val) { 25 | this.isActive = val 26 | if (val) { 27 | document.body.classList.add('xm--overflow--hidden') 28 | } else { 29 | document.body.classList.remove('xm--overflow--hidden') 30 | } 31 | } 32 | }, 33 | 34 | mounted () { 35 | this.$nextTick(() => { 36 | document.body.appendChild(this.$el) 37 | if (this.isVisible) { 38 | this.active() 39 | } 40 | }) 41 | }, 42 | 43 | beforeDestroy () { 44 | this.$el.remove() 45 | } 46 | } 47 | 48 | export default ModalMixin 49 | -------------------------------------------------------------------------------- /src/comps/components/globalmodal/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import globalModal from './global-modal.vue' 3 | 4 | function open (propsData) { 5 | const ModalComponent = Vue.extend(globalModal) 6 | return new ModalComponent({ 7 | el: document.createElement('div'), 8 | propsData 9 | }) 10 | } 11 | 12 | export default { 13 | confirm (opts) { 14 | const defaultOpts = {title: '', content: '', type: 'confirm', maskClosable: true, color: '', confirmText: '确定', cancelText: '取消', callBack () {}, closeAction () {}} 15 | const propsOpts = Object.assign(defaultOpts, opts) 16 | return open(propsOpts) 17 | }, 18 | 19 | prompt (opts) { 20 | const defaultOpts = {title: '', placeholder: '', type: 'prompt', maskClosable: true, color: '', confirmText: '确定', cancelText: '取消', readonly: false, callBack () {}, closeAction () {}} 21 | const propsOpts = Object.assign(defaultOpts, opts) 22 | return open(propsOpts) 23 | }, 24 | 25 | alert (opts) { 26 | const defaultOpts = {title: '', content: '', type: 'alert', maskClosable: true, color: '', confirmText: '确定', autoClose: false, callBack () {}} 27 | const propsOpts = Object.assign(defaultOpts, opts) 28 | return open(propsOpts) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/comps/components/grid/grid.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 27 | 28 | 31 | -------------------------------------------------------------------------------- /src/comps/components/grid/grids.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /src/comps/components/grid/index.js: -------------------------------------------------------------------------------- 1 | import Grid from './grid.vue' 2 | import Grids from './grids.vue' 3 | 4 | Grid.group = Grids 5 | export default Grid 6 | -------------------------------------------------------------------------------- /src/comps/components/grids/index.js: -------------------------------------------------------------------------------- 1 | import Grids from '../grid/grids.vue' 2 | 3 | export default Grids 4 | -------------------------------------------------------------------------------- /src/comps/components/input/index.js: -------------------------------------------------------------------------------- 1 | import Input from './input.vue' 2 | 3 | export default Input 4 | -------------------------------------------------------------------------------- /src/comps/components/input/input.scss: -------------------------------------------------------------------------------- 1 | .xm__input--wrap { 2 | display: flex; 3 | width: 100%; 4 | position: relative; 5 | vertical-align: middle; 6 | line-height: normal; 7 | flex: 1; 8 | } 9 | 10 | .xm__input { 11 | display: flex; 12 | @include size(100%,100%); 13 | align-items: center; 14 | position: relative; 15 | 16 | > input { 17 | display: block; 18 | @include size(100%,100%); 19 | border: none; 20 | font-size: inherit; 21 | background: transparent; 22 | &::-webkit-search-cancel-button { 23 | -webkit-appearance: none; 24 | } 25 | 26 | &.is-right{ 27 | text-align: right; 28 | } 29 | } 30 | 31 | &:before { 32 | content: "*"; 33 | position: absolute; 34 | left: -7px; 35 | font-size: 14px; 36 | color: rgb(255, 68, 68); 37 | display: none; 38 | } 39 | 40 | & .xm__input--close{ 41 | height: 2rem; 42 | width: 2rem; 43 | position: absolute; 44 | top: 0; 45 | bottom: 0; 46 | right: 0; 47 | margin: auto; 48 | 49 | & span{ 50 | margin-left: 0; 51 | font-size: 1.5rem; 52 | color: #c8c8c8; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/comps/components/keyboard/index.js: -------------------------------------------------------------------------------- 1 | import KeyBoard from './keyboard.vue' 2 | 3 | export default KeyBoard 4 | -------------------------------------------------------------------------------- /src/comps/components/lazy/index.js: -------------------------------------------------------------------------------- 1 | import Lazy from './lazy.vue' 2 | 3 | export default Lazy 4 | -------------------------------------------------------------------------------- /src/comps/components/lazy/lazy.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monw3c/xmui/9b389127a94b5838a71bc5f3bb9cfff41a1cbef0/src/comps/components/lazy/lazy.scss -------------------------------------------------------------------------------- /src/comps/components/lazy/lazy.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 48 | 49 | 52 | -------------------------------------------------------------------------------- /src/comps/components/loading/index.js: -------------------------------------------------------------------------------- 1 | import Loading from './loading.vue' 2 | 3 | export default Loading 4 | -------------------------------------------------------------------------------- /src/comps/components/loading/loading.scss: -------------------------------------------------------------------------------- 1 | .xm__loading--wrap{ 2 | text-align: center; 3 | } 4 | 5 | .xm__loading{ 6 | 7 | // ripple效果预留 8 | .ripple { 9 | display: inline-block; 10 | position: relative; 11 | @include size(32px,32px); 12 | 13 | & div { 14 | position: absolute; 15 | border: 4px solid #fff; 16 | opacity: 1; 17 | border-radius: 50%; 18 | animation: ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite; 19 | 20 | &:nth-child(2) { 21 | animation-delay: -0.5s; 22 | } 23 | } 24 | } 25 | 26 | & .xm__loading--loader { 27 | animation: spin 1250ms linear infinite; 28 | border: 2px solid $primary-color; 29 | border-right-color: transparent; 30 | @include border-radius(100px); 31 | box-sizing: border-box; 32 | display: inline-block; 33 | position: relative; 34 | overflow: hidden; 35 | text-indent: -9999px; 36 | @include size(32px,32px); 37 | 38 | &.borderRightTransparent { 39 | border-right-color: transparent!important; 40 | } 41 | } 42 | 43 | //非行内的时候 44 | &.xm__loading--fullScreen{ 45 | position: fixed; 46 | top: 50%; 47 | left: 50%; 48 | width: auto; 49 | transform: translate(-50%, -50%); 50 | background: $body-background; 51 | padding: 14px 10px 10px; 52 | @include border-radius(); 53 | z-index: $zindex-loading; 54 | 55 | } 56 | // 垂直显示 57 | & .xm__loading--vertical{ 58 | margin: 0 auto; 59 | display: block; 60 | } 61 | 62 | & .xm__loading--text{ 63 | display: inline-block; 64 | height: 34px; 65 | line-height: 36px; 66 | font-size: $font-size-base; 67 | vertical-align: top; 68 | } 69 | 70 | &.customize{ 71 | padding: 10px; 72 | } 73 | 74 | & .xm__loading--close{ 75 | font-size: $font-size-small*0.9; 76 | vertical-align: middle; 77 | position: absolute; 78 | right: -0.5rem; 79 | top: -0.5rem; 80 | width: 1.5rem; 81 | height: 1.5rem; 82 | line-height: 1.5rem; 83 | text-align: center; 84 | background: $body-background; 85 | @include border-radius(30px); 86 | color: $close-color; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/comps/components/loading/loading.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 75 | 76 | 79 | -------------------------------------------------------------------------------- /src/comps/components/loadmore/index.js: -------------------------------------------------------------------------------- 1 | import LoadMore from './loadMore.vue' 2 | 3 | export default LoadMore 4 | -------------------------------------------------------------------------------- /src/comps/components/loadmore/loadMore.scss: -------------------------------------------------------------------------------- 1 | .xm__loadMore { 2 | display: inline-block; 3 | line-height: 1em; 4 | cursor: pointer; 5 | color: rgb(31, 45, 61); 6 | -webkit-appearance: none; 7 | box-sizing: border-box; 8 | text-align: center; 9 | white-space: nowrap; 10 | font-size: $font-size-base; 11 | padding: 5px 8px; 12 | width: 100%; 13 | margin: 1em auto; 14 | } 15 | 16 | .xm__loadmore--line { 17 | border-top: 1px solid #E5E5E5; 18 | margin-top: 2em; 19 | 20 | & .xm__loadmore--tips { 21 | position: relative; 22 | top: -0.9em; 23 | padding: 0 .55em; 24 | background-color: #FFFFFF; 25 | color: #999999; 26 | } 27 | } -------------------------------------------------------------------------------- /src/comps/components/loadmore/loadMore.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 40 | 41 | 44 | -------------------------------------------------------------------------------- /src/comps/components/modal/index.js: -------------------------------------------------------------------------------- 1 | import Modal from './modal.vue' 2 | 3 | export default Modal 4 | -------------------------------------------------------------------------------- /src/comps/components/navbar/index.js: -------------------------------------------------------------------------------- 1 | import Navbar from './navbar.vue' 2 | 3 | export default Navbar 4 | -------------------------------------------------------------------------------- /src/comps/components/navbar/navbar.scss: -------------------------------------------------------------------------------- 1 | .xm__navbar{ 2 | @include size(100%,4rem); 3 | background-color: $body-background; 4 | position: relative; 5 | user-select: none; 6 | text-align: center; 7 | line-height: 4rem; 8 | display: flex; 9 | 10 | &:after{ 11 | content: ""; 12 | position: absolute; 13 | bottom: 0; 14 | left: 0; 15 | width: 100%; 16 | border-bottom: $border-width-default $border-style-default $border-color-base; 17 | transform: scaleY(.5); 18 | transform-origin: 0 0; 19 | } 20 | 21 | & .xm__navbar--left, 22 | & .xm__navbar--right { 23 | font-size: $font-size-base; 24 | min-width: 3.5rem; 25 | } 26 | 27 | & .xm__navbar--left { 28 | 29 | & .xm__navbar--icon{ 30 | margin-left: 5px; 31 | } 32 | } 33 | 34 | & .xm__navbar--right { 35 | 36 | & .xm__navbar--icon{ 37 | margin-right: 5px; 38 | font-size: 1.8rem; 39 | } 40 | } 41 | 42 | & .xm__navbar--title { 43 | font-size: 1.8rem; 44 | white-space: nowrap; 45 | overflow: hidden; 46 | text-overflow: ellipsis; 47 | flex: 1; 48 | color: #555; 49 | margin: 0 20px; 50 | 51 | & img{ 52 | max-height: 3.5rem; 53 | height: 3.5rem; 54 | vertical-align: middle; 55 | } 56 | } 57 | } 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/comps/components/navbar/navbar.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 79 | 80 | 83 | -------------------------------------------------------------------------------- /src/comps/components/popup/index.js: -------------------------------------------------------------------------------- 1 | import Popup from './popup.vue' 2 | 3 | export default Popup 4 | -------------------------------------------------------------------------------- /src/comps/components/popup/popup.scss: -------------------------------------------------------------------------------- 1 | .xm__mask { 2 | @include mask 3 | } 4 | 5 | .xm__popup { 6 | text-align: center; 7 | position: fixed; 8 | bottom: 0; 9 | left: 0; 10 | width: 100%; 11 | z-index: $zindex-popover; 12 | background-color: $body-background; 13 | transform: translate(0, 100%); 14 | transition: transform .3s; 15 | 16 | &.xm__popup--active { 17 | transform: translate(0, 0); 18 | } 19 | 20 | & header{ 21 | font-size: $font-size-small; 22 | color: $text-color; 23 | height: 40px; 24 | line-height: 40px; 25 | background-color: $body-background; 26 | border-bottom: $border-width-default $border-style-default $border-color-base; 27 | } 28 | 29 | & .xm__popup--action { 30 | display: block; 31 | font-size: 1.3rem; 32 | color: $text-color; 33 | position: absolute; 34 | top: 0; 35 | right: 0; 36 | width: 4rem; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /src/comps/components/popup/popup.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 72 | 73 | 76 | -------------------------------------------------------------------------------- /src/comps/components/radio/index.js: -------------------------------------------------------------------------------- 1 | import Radio from './radio.vue' 2 | import RadioGroup from './radio-group.vue' 3 | 4 | Radio.group = RadioGroup 5 | export default Radio 6 | -------------------------------------------------------------------------------- /src/comps/components/radio/radio-group.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 55 | 56 | 59 | -------------------------------------------------------------------------------- /src/comps/components/radio/radio.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 39 | 40 | 43 | -------------------------------------------------------------------------------- /src/comps/components/radiogroup/index.js: -------------------------------------------------------------------------------- 1 | import RadioGroup from '../radio/radio-group.vue' 2 | 3 | export default RadioGroup 4 | -------------------------------------------------------------------------------- /src/comps/components/seamlessscroll/index.js: -------------------------------------------------------------------------------- 1 | import SeamlessScrollItem from './seamlessscroll-item.vue' 2 | import SeamlessScroll from './seamlessscroll.vue' 3 | 4 | SeamlessScroll.item = SeamlessScrollItem 5 | export default SeamlessScroll 6 | -------------------------------------------------------------------------------- /src/comps/components/seamlessscroll/seamlessscroll-item.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 18 | -------------------------------------------------------------------------------- /src/comps/components/seamlessscroll/seamlessscroll.scss: -------------------------------------------------------------------------------- 1 | .xm__seamlessscroll { 2 | overflow: hidden; 3 | width: 100%; 4 | background-color: #fff; 5 | 6 | &--box { 7 | height: inherit; 8 | } 9 | 10 | &--align { 11 | &-left { 12 | justify-content: flex-start; 13 | } 14 | 15 | &-right { 16 | justify-content: flex-end; 17 | } 18 | 19 | &-center { 20 | justify-content: center; 21 | } 22 | } 23 | 24 | &--item { 25 | height: inherit; 26 | display: flex; 27 | align-items: center; 28 | justify-content: inherit; 29 | font-size: $font-size-small; 30 | } 31 | } -------------------------------------------------------------------------------- /src/comps/components/seamlessscrollitem/index.js: -------------------------------------------------------------------------------- 1 | import SeamlessScrollItem from '../seamlessscroll/seamlessscroll-item.vue' 2 | 3 | export default SeamlessScrollItem 4 | -------------------------------------------------------------------------------- /src/comps/components/search/index.js: -------------------------------------------------------------------------------- 1 | import Search from './search.vue' 2 | 3 | export default Search 4 | -------------------------------------------------------------------------------- /src/comps/components/search/search.scss: -------------------------------------------------------------------------------- 1 | .xm__search { 2 | display: flex; 3 | align-items: center; 4 | box-sizing: border-box; 5 | padding: 4px; 6 | 7 | & .xm__icon--search { 8 | color: #666; 9 | position: absolute; 10 | top: 50%; 11 | transform: translateY(-50%); 12 | left: 10px; 13 | font-size: $font-size-base; 14 | } 15 | } 16 | 17 | .xm__search--action,.xm__search--cancel { 18 | line-height: $line-height-computed; 19 | font-size: $font-size-small; 20 | letter-spacing: 1px; 21 | 22 | & div{ 23 | padding: 0 0 0 10px; 24 | } 25 | } 26 | 27 | .xm__search--input--wrap{ 28 | position: relative; 29 | flex: 1; 30 | height: 34px; 31 | box-sizing: border-box; 32 | padding: 4px 24px 4px 35px; 33 | border: 1px solid #e5e5e5; 34 | @include border-radius(30px); 35 | background-color: #fff; 36 | } 37 | 38 | .xm__search--input { 39 | display: block; 40 | width: 100%; 41 | height: 24px; 42 | line-height: 24px; 43 | padding: 0; 44 | font-size: $font-size-base; 45 | color: #666; 46 | border: none; 47 | } 48 | 49 | .xm__icon--clear { 50 | color: #c8c8c8; 51 | position: absolute; 52 | top: 50%; 53 | transform: translateY(-50%); 54 | right: 1rem; 55 | font-size: $font-size-base; 56 | } -------------------------------------------------------------------------------- /src/comps/components/select/index.js: -------------------------------------------------------------------------------- 1 | import Select from './select.vue' 2 | 3 | export default Select 4 | -------------------------------------------------------------------------------- /src/comps/components/select/select.scss: -------------------------------------------------------------------------------- 1 | .xm__select { 2 | flex: 1; 3 | height: 40px; 4 | border: none; 5 | display: block; 6 | 7 | 8 | & select { 9 | border: none; 10 | display: block; 11 | @include size(100%,40px); 12 | color: $text-color; 13 | font-size: $font-size-base; 14 | background-color: $body-background; 15 | outline: none; 16 | -webkit-appearance:none; 17 | 18 | &.is-right{ 19 | direction: rtl; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/comps/components/select/select.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 49 | 50 | 53 | -------------------------------------------------------------------------------- /src/comps/components/skeleton/index.js: -------------------------------------------------------------------------------- 1 | import Skeleton from './skeleton.vue' 2 | 3 | export default Skeleton 4 | -------------------------------------------------------------------------------- /src/comps/components/skeleton/skeleton.scss: -------------------------------------------------------------------------------- 1 | .xm__skeleton--circle { 2 | @include size(50px,50px); 3 | @include border-radius(100px); 4 | background: $skeleton-bg; 5 | opacity: .5; 6 | } 7 | 8 | .xm__skeleton--bar { 9 | opacity: .5; 10 | @include size(100%,24px); 11 | background: $skeleton-bg; 12 | } 13 | 14 | .xm__skeleton--opacity{ 15 | animation: opacity 1s ease-in-out infinite; 16 | } 17 | 18 | .xm__skeleton--loading{ 19 | animation: bar-loading 1s ease-in-out infinite; 20 | } -------------------------------------------------------------------------------- /src/comps/components/skeleton/skeleton.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 28 | 29 | 32 | -------------------------------------------------------------------------------- /src/comps/components/spmodal/index.js: -------------------------------------------------------------------------------- 1 | import SpModal from './sp-modal.vue' 2 | 3 | export default SpModal 4 | -------------------------------------------------------------------------------- /src/comps/components/spmodal/sp-modal.vue: -------------------------------------------------------------------------------- 1 | /* special modal特殊的弹出层,可用于活动专题 */ 2 | 20 | 21 | 81 | 82 | 85 | -------------------------------------------------------------------------------- /src/comps/components/spmodal/spmodal.scss: -------------------------------------------------------------------------------- 1 | .xm__mask { 2 | @include mask 3 | } 4 | 5 | .xm__dialog--special{ 6 | position: fixed; 7 | text-align: center; 8 | top: 50%; 9 | left: 50%; 10 | width: 85%; 11 | max-width: 300px; 12 | font-size: 16px; 13 | overflow: hidden; 14 | transition: .2s; 15 | border-radius: 4px; 16 | background-color: transparent; 17 | transform: translate3d(-50%, -50%, 0); 18 | z-index: 1000; 19 | 20 | & .xm__dialog--bd{ 21 | max-height: 320px; 22 | overflow: hidden; 23 | 24 | & img{ 25 | width: 100%; 26 | border-radius: 4px; 27 | } 28 | } 29 | 30 | & .xm__dialog--ft { 31 | margin-bottom: 0; 32 | 33 | & button.xm__btn--default{ 34 | background: transparent; 35 | margin: 0 auto; 36 | 37 | &::before{ 38 | border: none; 39 | } 40 | 41 | &:hover, 42 | &:active { 43 | background-color: transparent; 44 | text-decoration: none; 45 | border: none; 46 | } 47 | 48 | & .xm__icon--close-outline { 49 | font-size: 34px; 50 | color: #fff; 51 | } 52 | 53 | &::before { 54 | border: none; 55 | } 56 | 57 | &:first-child { 58 | background-color: transparent; 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/comps/components/step/index.js: -------------------------------------------------------------------------------- 1 | import Step from './step.vue' 2 | 3 | export default Step 4 | -------------------------------------------------------------------------------- /src/comps/components/step/step.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 49 | 50 | 53 | -------------------------------------------------------------------------------- /src/comps/components/switch/index.js: -------------------------------------------------------------------------------- 1 | import Switch from './switch.vue' 2 | 3 | export default Switch 4 | -------------------------------------------------------------------------------- /src/comps/components/switch/switch.scss: -------------------------------------------------------------------------------- 1 | .xm__switch { 2 | position: relative; 3 | z-index: 10; 4 | display: block; 5 | @include size(52px,28px); 6 | left: 0; 7 | border: $border-width-default $border-style-default $border-color-base; 8 | @include border-radius(16px); 9 | background-color: #dfdfdf; 10 | -webkit-appearance: none; 11 | color: #4cd864; 12 | 13 | &:checked { 14 | border-color: currentColor; 15 | background-color: currentColor; 16 | 17 | &:before { 18 | transform: scale(0); 19 | transition: transform .3s; 20 | } 21 | &:after { 22 | transform: translateX(24px); 23 | transition: transform .3s; 24 | } 25 | } 26 | 27 | &[disabled] { 28 | opacity: 0.5; 29 | } 30 | 31 | &:after, 32 | &:before { 33 | content: ""; 34 | position: absolute; 35 | top: 0; 36 | left: 0; 37 | height: 26px; 38 | @include border-radius(15px); 39 | transition: transform .3s; 40 | } 41 | 42 | &:before { 43 | width: 50px; 44 | background-color: #FDFDFD; 45 | } 46 | 47 | &:after { 48 | width: 26px; 49 | background-color: $body-background; 50 | box-shadow: 0 1px 3px rgba(0, 0, 0, .4); 51 | } 52 | } -------------------------------------------------------------------------------- /src/comps/components/switch/switch.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 31 | 32 | 35 | -------------------------------------------------------------------------------- /src/comps/components/tabbar/index.js: -------------------------------------------------------------------------------- 1 | import TabbarItem from './tabbar-item.vue' 2 | import Tabbar from './tabbar.vue' 3 | 4 | Tabbar.item = TabbarItem 5 | export default Tabbar 6 | -------------------------------------------------------------------------------- /src/comps/components/tabbar/tabbar.scss: -------------------------------------------------------------------------------- 1 | .xm__tabbar{ 2 | @include size(100%,5rem); 3 | display: flex; 4 | background-color: $body-background; 5 | } 6 | 7 | 8 | 9 | .xm__tabbar--item { 10 | flex: 1; 11 | color: $text-color; 12 | display: flex; 13 | line-height: $line-height-base; 14 | font-size: $font-size-small; 15 | align-items: center; 16 | flex-direction: column; 17 | justify-content: center; 18 | 19 | &.xm__tabbar--item-active { 20 | color: $success-color; 21 | } 22 | 23 | &.router-link-active{ 24 | color: $success-color; 25 | } 26 | 27 | & .xm__tabbar--item-icon { 28 | position: relative; 29 | display: flex; 30 | align-items: center; 31 | height: 3rem; 32 | 33 | & img { 34 | width: 2.2rem; 35 | 36 | } 37 | 38 | & .xm__icon { 39 | display: block; 40 | font-size: 2.2rem; 41 | padding: 0 2px; 42 | } 43 | 44 | & .xm__tabbar--item-badge { 45 | display: inline-block; 46 | padding: 2px 4px; 47 | min-width: 8px; 48 | @include border-radius(18px); 49 | background-color: $error-color; 50 | color: #fff; 51 | line-height: 1.2; 52 | text-align: center; 53 | font-size: .7em; 54 | vertical-align: middle; 55 | position: absolute; 56 | top: 2px; 57 | right: -10px; 58 | } 59 | 60 | & .xm__tabbar--item-dot { 61 | display: inline-block; 62 | @include size(6px,6px); 63 | @include border-radius(100px); 64 | background-color: $error-color; 65 | position: absolute; 66 | top: 5px; 67 | right: -5px; 68 | } 69 | 70 | } 71 | 72 | 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/comps/components/tabbar/tabbar.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 22 | 23 | 26 | -------------------------------------------------------------------------------- /src/comps/components/tabbaritem/index.js: -------------------------------------------------------------------------------- 1 | import TabbarItem from '../tabbar/tabbar-item.vue' 2 | 3 | export default TabbarItem 4 | -------------------------------------------------------------------------------- /src/comps/components/tag/index.js: -------------------------------------------------------------------------------- 1 | import Tag from './tag.vue' 2 | 3 | export default Tag 4 | -------------------------------------------------------------------------------- /src/comps/components/tag/tag.scss: -------------------------------------------------------------------------------- 1 | .xm__tag { 2 | display: inline-block; 3 | line-height: 1.2; 4 | cursor: pointer; 5 | color: rgb(31, 45, 61); 6 | -webkit-appearance: none; 7 | box-sizing: border-box; 8 | text-align: center; 9 | white-space: nowrap; 10 | font-size: $font-size-small; 11 | margin: 0px; 12 | @include border-radius; 13 | padding: 3px 8px; 14 | 15 | & .xm__tag--close{ 16 | font-size: 1.2rem; 17 | vertical-align: middle; 18 | } 19 | 20 | &.is-round{ 21 | @include border-radius(100px); 22 | } 23 | 24 | &.xm__tag--default { 25 | color: $btn-default-color; 26 | background: $btn-default-bg; 27 | border: $border-width-default $border-style-default $border-color-base; 28 | } 29 | 30 | &.xm__tag--success { 31 | @extend .xm__tag--default; 32 | color: $btn-success-color; 33 | background: $btn-success-bg; 34 | border: $border-width-default $border-style-default $btn-success-bg; 35 | } 36 | 37 | &.xm__tag--primary { 38 | @extend .xm__tag--default; 39 | color: $btn-primary-color; 40 | background: $btn-primary-bg; 41 | border: $border-width-default $border-style-default $btn-primary-bg; 42 | } 43 | 44 | &.xm__tag--warning { 45 | @extend .xm__tag--default; 46 | color: $btn-warning-color; 47 | background: $btn-warning-bg; 48 | border: $border-width-default $border-style-default $btn-warning-bg; 49 | } 50 | 51 | &.xm__tag--warning { 52 | @extend .xm__tag--default; 53 | color: $btn-warning-color; 54 | background: $btn-warning-bg; 55 | border: $border-width-default $border-style-default $btn-warning-bg; 56 | } 57 | 58 | &.xm__tag--error { 59 | @extend .xm__tag--default; 60 | color: $btn-error-color; 61 | background: $btn-error-bg; 62 | border: $border-width-default $border-style-default $btn-error-bg; 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /src/comps/components/tag/tag.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 49 | 50 | 53 | -------------------------------------------------------------------------------- /src/comps/components/textarea/index.js: -------------------------------------------------------------------------------- 1 | import Textarea from './textarea.vue' 2 | 3 | export default Textarea 4 | -------------------------------------------------------------------------------- /src/comps/components/textarea/textarea.scss: -------------------------------------------------------------------------------- 1 | .xm__textarea{ 2 | padding: 10px 0; 3 | background-color: $body-background; 4 | width: 100%; 5 | 6 | & textarea { 7 | border: none; 8 | display: block; 9 | @include size(100%,100px); 10 | font-size: $font-size-base; 11 | outline: none; 12 | resize: none; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/comps/components/textarea/textarea.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 47 | 48 | 51 | -------------------------------------------------------------------------------- /src/comps/components/toast/ToastMixin.js: -------------------------------------------------------------------------------- 1 | const ModalMixin = { 2 | props: { 3 | isVisible: { 4 | type: Boolean, 5 | default: false 6 | } 7 | }, 8 | data () { 9 | return { 10 | isActive: false 11 | } 12 | }, 13 | methods: { 14 | active () { 15 | this.isActive = true 16 | } 17 | }, 18 | 19 | watch: { 20 | isVisible (val) { 21 | this.isActive = val 22 | } 23 | }, 24 | 25 | mounted () { 26 | this.$nextTick(() => { 27 | document.body.appendChild(this.$el) 28 | if (this.isVisible) { 29 | this.active() 30 | } 31 | }) 32 | }, 33 | 34 | beforeDestroy () { 35 | this.$el.remove() 36 | } 37 | } 38 | 39 | export default ModalMixin 40 | -------------------------------------------------------------------------------- /src/comps/components/toast/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Toast from './toast.vue' 3 | 4 | function open (propsData) { 5 | const ToastComponent = Vue.extend(Toast) 6 | return new ToastComponent({ 7 | el: document.createElement('div'), 8 | propsData 9 | }) 10 | } 11 | 12 | export default { 13 | text (opts) { 14 | const defaultOpts = {content: '', mask: false, direction: '', callBack () {}} 15 | const propsOpts = Object.assign(defaultOpts, opts) 16 | return open(propsOpts) 17 | }, 18 | 19 | loading (opts) { 20 | const defaultOpts = {content: '', type: 'default', mask: true, callBack () {}} 21 | const propsOpts = Object.assign(defaultOpts, opts) 22 | return open(propsOpts) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/comps/components/toast/toast.scss: -------------------------------------------------------------------------------- 1 | .xm__toast { 2 | position: fixed; 3 | top: 50%; 4 | left: 50%; 5 | display: flex; 6 | color: #fff; 7 | z-index: 3001; 8 | font-size: $font-size-small; 9 | line-height: 1.2; 10 | @include border-radius; 11 | align-items: center; 12 | justify-content: center; 13 | flex-direction: column; 14 | box-sizing: border-box; 15 | transform: translate3d(-50%, -50%, 0); 16 | background-color: rgba(39, 39, 39, .7); 17 | 18 | 19 | &.xm__toast--text { 20 | padding: 12px; 21 | min-width: 220px; 22 | } 23 | 24 | &.xm__toast--loading { 25 | width: 120px; 26 | min-height: 120px; 27 | padding: 15px; 28 | } 29 | 30 | & .xm__loading { 31 | font-size: 0; 32 | line-height: 0; 33 | z-index: 0; 34 | position: relative; 35 | } 36 | 37 | & .xm__toast--loading .xm__loading { 38 | margin: 10px 0 5px; 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /src/comps/components/toast/toast.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | -------------------------------------------------------------------------------- /src/comps/index.js: -------------------------------------------------------------------------------- 1 | import './styles/index.scss' 2 | 3 | import Tag from './components/tag/index' 4 | import LoadMore from './components/loadmore/index' 5 | import Search from './components/search/index' 6 | import Loading from './components/loading/index' 7 | import Step from './components/step/index' 8 | import Input from './components/input/index' 9 | import Textarea from './components/textarea/index' 10 | import Select from './components/select/index' 11 | import Switch from './components/switch/index' 12 | import Skeleton from './components/skeleton/index' 13 | import Navbar from './components/navbar/index' 14 | import Actionsheet from './components/actionsheet/index' 15 | import Popup from './components/popup/index' 16 | import Lazy from './components/lazy/index' 17 | import KeyBoard from './components/keyboard/index' 18 | 19 | import Button from './components/button/index' 20 | import Tabbar from './components/tabbar/index' 21 | import Radio from './components/radio/index' 22 | import Checkbox from './components/checkbox/index' 23 | import Grid from './components/grid/index' 24 | import Modal from './components/modal/index' 25 | import SpModal from './components/spmodal/index' 26 | import CellGroup from './components/cell/index' 27 | import Flexbox from './components/flexbox/index' 28 | import SeamlessScroll from './components/seamlessscroll/index' 29 | 30 | import GlobalModal from './components/globalmodal/index' 31 | import Toast from './components/toast/index' 32 | 33 | const components = { 34 | Button, 35 | ButtonGroup: Button.group, 36 | Tag, 37 | LoadMore, 38 | Search, 39 | Modal, 40 | SpModal, 41 | Loading, 42 | Step, 43 | Input, 44 | Textarea, 45 | Select, 46 | Switch, 47 | Skeleton, 48 | TabbarItem: Tabbar.item, 49 | Tabbar, 50 | Navbar, 51 | Actionsheet, 52 | Popup, 53 | Lazy, 54 | KeyBoard, 55 | Radio, 56 | RadioGroup: Radio.group, 57 | Checkbox, 58 | CheckboxGroup: Checkbox.group, 59 | Grid, 60 | Grids: Grid.group, 61 | CellItem: CellGroup.item, 62 | CellGroup, 63 | FlexboxItem: Flexbox.item, 64 | Flexbox, 65 | SeamlessScrollItem: SeamlessScroll.item, 66 | SeamlessScroll 67 | } 68 | 69 | const install = function (Vue) { 70 | if (install.installed) return 71 | // components.map(component => Vue.component(component.name, component)) 72 | Object.keys(components).forEach(key => { 73 | Vue.component(components[key].name, components[key]) 74 | }) 75 | 76 | Vue.prototype.$modal = GlobalModal 77 | Vue.prototype.$toast = Toast 78 | } 79 | 80 | if (typeof window !== 'undefined' && window.Vue) { 81 | install(window.Vue) 82 | } 83 | 84 | const API = { 85 | install, 86 | ...components 87 | } 88 | 89 | export default API 90 | -------------------------------------------------------------------------------- /src/comps/styles/animation.scss: -------------------------------------------------------------------------------- 1 | .fade-enter-active { 2 | animation-name: fade-in; 3 | animation-duration: .5s; 4 | } 5 | .fade-leave-active { 6 | animation-name: fade-out; 7 | animation-duration: .5s; 8 | } 9 | 10 | .lazy-enter { 11 | opacity: 0; 12 | } 13 | .lazy-enter-to { 14 | opacity: 1; 15 | } 16 | .lazy-enter-active { 17 | transition: opacity 0.3s 0.2s; 18 | width: 100%; 19 | } 20 | .lazy-leave { 21 | opacity: 1; 22 | } 23 | .lazy-leave-to { 24 | opacity: 0; 25 | } 26 | .lazy-leave-active { 27 | transition: opacity 0.5s; 28 | } 29 | 30 | .slide-up-enter-active, .slide-up-leave-active { 31 | transform: translate(-50%, 0); 32 | } 33 | 34 | .slide-up-enter, .slide-up-leave-to { 35 | transform: translate(-50%, 70%); 36 | } 37 | 38 | .slide-up-leave-active { 39 | transform: translate(-50%, 100%); 40 | } 41 | 42 | @keyframes fade-in { 43 | from { 44 | opacity: 0; 45 | } 46 | 47 | to { 48 | opacity: 1; 49 | } 50 | } 51 | 52 | 53 | 54 | @keyframes fade-out { 55 | from { 56 | opacity: 1; 57 | } 58 | to { 59 | opacity: 0; 60 | } 61 | } 62 | 63 | // loading样式 64 | @keyframes spin { 65 | 0% { 66 | transform: rotate(0deg); 67 | } 68 | 100% { 69 | transform: rotate(360deg); 70 | } 71 | } 72 | 73 | // opacity样式 74 | @keyframes opacity { 75 | 0% {opacity: 1;} 76 | 10% {opacity: 0.9;} 77 | 20% {opacity: 0.8;} 78 | 30% {opacity: 0.7;} 79 | 40% {opacity: 0.6;} 80 | 50% {opacity: 0.5;} 81 | 60% {opacity: 0.6;} 82 | 70% {opacity: 0.7;} 83 | 80% {opacity: 0.8;} 84 | 90% {opacity: 0.9;} 85 | 100% {opacity: 0.95;} 86 | } 87 | 88 | @keyframes bar-loading { 89 | 0% { 90 | width:60% 91 | } 92 | 50% { 93 | width:100% 94 | } 95 | 100% { 96 | width:60% 97 | } 98 | } 99 | 100 | @keyframes ripple { 101 | 0% { 102 | top: 28px; 103 | left: 28px; 104 | width: 0; 105 | height: 0; 106 | opacity: 1; 107 | } 108 | 100% { 109 | top: -1px; 110 | left: -1px; 111 | width: 58px; 112 | height: 58px; 113 | opacity: 0; 114 | } 115 | } -------------------------------------------------------------------------------- /src/comps/styles/common.scss: -------------------------------------------------------------------------------- 1 | 2 | html{ 3 | font-size: 62.5%; 4 | -webkit-tap-highlight-color: transparent; 5 | } 6 | input, button{ 7 | outline: none; 8 | } 9 | 10 | a{ 11 | text-decoration: none; 12 | } 13 | 14 | .xm--overflow--hidden{ 15 | overflow: hidden!important; 16 | } -------------------------------------------------------------------------------- /src/comps/styles/index.scss: -------------------------------------------------------------------------------- 1 | @import "varibles"; 2 | @import "mixin"; 3 | @import "normalize"; 4 | @import "animation"; 5 | @import "common"; 6 | @import "icon"; 7 | 8 | @import "../components/button/button.scss"; 9 | @import "../components/loadmore/loadMore.scss"; 10 | @import "../components/tag/tag.scss"; 11 | @import "../components/search/search.scss"; 12 | @import "../components/globalmodal/modal.scss"; 13 | @import "../components/spmodal/spmodal.scss"; 14 | @import "../components/loading/loading.scss"; 15 | @import "../components/step/step.scss"; 16 | @import "../components/toast/toast.scss"; 17 | @import "../components/cell/cell.scss"; 18 | @import "../components/input/input.scss"; 19 | @import "../components/textarea/textarea.scss"; 20 | @import "../components/select/select.scss"; 21 | @import "../components/switch/switch.scss"; 22 | @import "../components/skeleton/skeleton.scss"; 23 | @import "../components/grid/grid.scss"; 24 | @import "../components/radio/radio.scss"; 25 | @import "../components/checkbox/checkbox.scss"; 26 | @import "../components/tabbar/tabbar.scss"; 27 | @import "../components/navbar/navbar.scss"; 28 | @import "../components/actionsheet/actionsheet.scss"; 29 | @import "../components/flexbox/flexbox.scss"; 30 | @import "../components/seamlessscroll/seamlessscroll.scss"; 31 | @import "../components/popup/popup.scss"; 32 | @import "../components/lazy/lazy.scss"; 33 | @import "../components/keyboard/keyboard.scss"; 34 | -------------------------------------------------------------------------------- /src/comps/styles/mixin.scss: -------------------------------------------------------------------------------- 1 | // border圆角 2 | @mixin border-radius($radius:$border-radius-small){ 3 | -webkit-border-radius: $radius; 4 | border-radius: $radius; 5 | } 6 | 7 | // 宽高 8 | @mixin size($width,$height){ 9 | width: $width; 10 | height: $height; 11 | } 12 | 13 | // 遮罩层 14 | @mixin mask(){ 15 | position: fixed; 16 | top: 0; 17 | bottom: 0; 18 | left: 0; 19 | right: 0; 20 | background-color: rgba(55, 55, 55, 0.6); 21 | height: 100%; 22 | z-index: $zindex-modal-mask; 23 | transition: opacity .2s ease-in; 24 | pointer-events: auto; 25 | 26 | &--hidden { 27 | display: none; 28 | } 29 | } 30 | 31 | // 按下去背景颜色 32 | @mixin tap-color($bgcolor, $opacity:.9) { 33 | 34 | &:active { 35 | background-color: $bgcolor * $opacity; 36 | } 37 | } 38 | 39 | // flex布局 40 | @mixin flex(){ 41 | display: flex; 42 | align-items: center; 43 | 44 | & .xm__flex--item { 45 | flex: 1; 46 | } 47 | 48 | &.xm__flex--vertical { 49 | flex-direction: column; 50 | height: 100%; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | import router from './router' 4 | import xmui from './comps/index' 5 | 6 | Vue.use(xmui) 7 | Vue.config.productionTip = false 8 | /* eslint-disable */ 9 | new Vue({ 10 | el: '#app', 11 | router, 12 | template: '', 13 | components: { App } 14 | }) 15 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | Vue.use(Router) 5 | 6 | export default new Router({ 7 | routes: [ 8 | { 9 | path: '/', 10 | name: 'home', 11 | component: (resolve) => { 12 | require(['@/views/home'], resolve) 13 | } 14 | } 15 | ] 16 | }) 17 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monw3c/xmui/9b389127a94b5838a71bc5f3bb9cfff41a1cbef0/static/.gitkeep -------------------------------------------------------------------------------- /static/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monw3c/xmui/9b389127a94b5838a71bc5f3bb9cfff41a1cbef0/static/logo.jpg -------------------------------------------------------------------------------- /test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // The assertion name is the filename. 3 | // Example usage: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // For more information on custom assertions see: 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | 10 | exports.assertion = function (selector, count) { 11 | this.message = 'Testing if element <' + selector + '> has count: ' + count 12 | this.expected = count 13 | this.pass = function (val) { 14 | return val === this.expected 15 | } 16 | this.value = function (res) { 17 | return res.value 18 | } 19 | this.command = function (cb) { 20 | var self = this 21 | return this.api.execute(function (selectorToCount) { 22 | return document.querySelectorAll(selectorToCount).length 23 | }, [selector], function (res) { 24 | cb.call(self, res) 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | var config = require('../../config') 3 | 4 | // http://nightwatchjs.org/gettingstarted#settings-file 5 | module.exports = { 6 | src_folders: ['test/e2e/specs'], 7 | output_folder: 'test/e2e/reports', 8 | custom_assertions_path: ['test/e2e/custom-assertions'], 9 | 10 | selenium: { 11 | start_process: true, 12 | server_path: require('selenium-server').path, 13 | host: '127.0.0.1', 14 | port: 4444, 15 | cli_args: { 16 | 'webdriver.chrome.driver': require('chromedriver').path 17 | } 18 | }, 19 | 20 | test_settings: { 21 | default: { 22 | selenium_port: 4444, 23 | selenium_host: 'localhost', 24 | silent: true, 25 | globals: { 26 | devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port) 27 | } 28 | }, 29 | 30 | chrome: { 31 | desiredCapabilities: { 32 | browserName: 'chrome', 33 | javascriptEnabled: true, 34 | acceptSslCerts: true 35 | } 36 | }, 37 | 38 | firefox: { 39 | desiredCapabilities: { 40 | browserName: 'firefox', 41 | javascriptEnabled: true, 42 | acceptSslCerts: true 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server using production config 2 | process.env.NODE_ENV = 'testing' 3 | 4 | const webpack = require('webpack') 5 | const DevServer = require('webpack-dev-server') 6 | 7 | const webpackConfig = require('../../build/webpack.prod.conf') 8 | const devConfigPromise = require('../../build/webpack.dev.conf') 9 | 10 | let server 11 | 12 | devConfigPromise.then(devConfig => { 13 | const devServerOptions = devConfig.devServer 14 | const compiler = webpack(webpackConfig) 15 | server = new DevServer(compiler, devServerOptions) 16 | const port = devServerOptions.port 17 | const host = devServerOptions.host 18 | return server.listen(port, host) 19 | }) 20 | .then(() => { 21 | // 2. run the nightwatch test suite against it 22 | // to run in additional browsers: 23 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings" 24 | // 2. add it to the --env flag below 25 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox` 26 | // For more information on Nightwatch's config file, see 27 | // http://nightwatchjs.org/guide#settings-file 28 | let opts = process.argv.slice(2) 29 | if (opts.indexOf('--config') === -1) { 30 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']) 31 | } 32 | if (opts.indexOf('--env') === -1) { 33 | opts = opts.concat(['--env', 'chrome']) 34 | } 35 | 36 | const spawn = require('cross-spawn') 37 | const runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }) 38 | 39 | runner.on('exit', function (code) { 40 | server.close() 41 | process.exit(code) 42 | }) 43 | 44 | runner.on('error', function (err) { 45 | server.close() 46 | throw err 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /test/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // For authoring Nightwatch tests, see 2 | // http://nightwatchjs.org/guide#usage 3 | 4 | module.exports = { 5 | 'default e2e tests': function (browser) { 6 | // automatically uses dev Server port from /config.index.js 7 | // default: http://localhost:8080 8 | // see nightwatch.conf.js 9 | const devServer = browser.globals.devServerURL 10 | 11 | browser 12 | .url(devServer) 13 | .waitForElementVisible('#app', 5000) 14 | .assert.elementPresent('.hello') 15 | .assert.containsText('h1', 'Welcome to Your Vue.js App') 16 | .assert.elementCount('img', 1) 17 | .end() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | Vue.config.productionTip = false 4 | 5 | // require all test files (files that ends with .spec.js) 6 | const testsContext = require.context('./specs', true, /\.spec$/) 7 | testsContext.keys().forEach(testsContext) 8 | 9 | // require all src files except main.js for coverage. 10 | // you can also change this to match only the subset of files that 11 | // you want coverage for. 12 | const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/) 13 | srcContext.keys().forEach(srcContext) 14 | -------------------------------------------------------------------------------- /test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | // This is a karma config file. For more details see 2 | // http://karma-runner.github.io/0.13/config/configuration-file.html 3 | // we are also using it with karma-webpack 4 | // https://github.com/webpack/karma-webpack 5 | 6 | var webpackConfig = require('../../build/webpack.test.conf') 7 | 8 | module.exports = function (config) { 9 | config.set({ 10 | // to run in additional browsers: 11 | // 1. install corresponding karma launcher 12 | // http://karma-runner.github.io/0.13/config/browsers.html 13 | // 2. add it to the `browsers` array below. 14 | browsers: ['PhantomJS'], 15 | frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'], 16 | reporters: ['spec', 'coverage'], 17 | files: ['./index.js'], 18 | preprocessors: { 19 | './index.js': ['webpack', 'sourcemap'] 20 | }, 21 | webpack: webpackConfig, 22 | webpackMiddleware: { 23 | noInfo: true 24 | }, 25 | coverageReporter: { 26 | dir: './coverage', 27 | reporters: [ 28 | { type: 'lcov', subdir: '.' }, 29 | { type: 'text-summary' } 30 | ] 31 | } 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /test/unit/specs/HelloWorld.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import HelloWorld from '@/components/HelloWorld' 3 | 4 | describe('HelloWorld.vue', () => { 5 | it('should render correct contents', () => { 6 | const Constructor = Vue.extend(HelloWorld) 7 | const vm = new Constructor().$mount() 8 | expect(vm.$el.querySelector('.hello h1').textContent) 9 | .to.equal('Welcome to Your Vue.js App') 10 | }) 11 | }) 12 | --------------------------------------------------------------------------------