├── .editorconfig ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── build └── rollup.config.js ├── dist ├── vue-step.esm.js ├── vue-step.min.js └── vue-step.umd.js ├── example └── index.vue ├── package.json ├── screenshot └── demo.png └── src ├── index.js └── vue-step.vue /.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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | package-lock.json 4 | npm-debug.log 5 | yarn-error.log 6 | 7 | # Editor directories and files 8 | .idea 9 | *.suo 10 | *.ntvs* 11 | *.njsproj 12 | *.sln 13 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | docs 2 | build 3 | .editorconfig 4 | .gitignore 5 | package-lock.json 6 | node_modules 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 LiLong 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-step 2 | 3 | > 基于Vue.js的移动端步骤导航组件 Mobile Step Navigation Component Based On Vue.js 4 | 5 | [![NPM](https://nodei.co/npm/vue-step.png)](https://nodei.co/npm/vue-step/) 6 | 7 | ## Installation 8 | 9 | ``` bash 10 | npm i vue-step -S 11 | ``` 12 | 13 | ## API 14 | 15 | | Param | Description | Type | Default | 16 | | --------- | ----------------- | -------- | ------- | 17 | | now-step | The current step, The starting value is 1. | `Number` | - | 18 | | step-list | Name of all steps | `Array` | - | 19 | | active-color | Active status color | `String` | '#1fb11d' | 20 | | style-type | You can set 'style1' or 'style2' | `String` | 'style1' | 21 | | direction | You can set 'horizontal' or 'vertical' | `String` | 'horizontal' | 22 | | @selected | Event issued when an item is selected / clicked | `Event` | - | 23 | 24 | ## Usage 25 | 26 | ``` bash 27 | # example 28 | 33 | 34 | 55 | ``` 56 | 57 | ## Demo Screenshot 58 | 59 | ![Demo Screenshot](./screenshot/demo.png) 60 | 61 | ## License 62 | 63 | MIT 64 | -------------------------------------------------------------------------------- /build/rollup.config.js: -------------------------------------------------------------------------------- 1 | // rollup.config.js 2 | import vue from 'rollup-plugin-vue'; 3 | import buble from 'rollup-plugin-buble'; 4 | import uglify from 'rollup-plugin-uglify-es'; 5 | import minimist from 'minimist'; 6 | 7 | const argv = minimist(process.argv.slice(2)); 8 | 9 | const config = { 10 | input: 'src/index.js', 11 | output: { 12 | name: 'VueStep', 13 | exports: 'named', 14 | }, 15 | plugins: [ 16 | vue({ 17 | css: true, 18 | compileTemplate: true, 19 | }), 20 | buble(), 21 | ], 22 | }; 23 | 24 | // Only minify browser (iife) version 25 | if (argv.format === 'iife') { 26 | config.plugins.push(uglify()); 27 | } 28 | 29 | export default config; 30 | -------------------------------------------------------------------------------- /dist/vue-step.esm.js: -------------------------------------------------------------------------------- 1 | (function(){ if(typeof document !== 'undefined'){ var head=document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .v-step-warp-horizontal[data-v-3500aeb9] { position: relative; padding: 10px 0; z-index: 2; } .v-step-warp-horizontal .v-step-progress-bg[data-v-3500aeb9] { position: absolute; width: 100%; height: 4px; bottom: 22px; background-color: #ddd; } .v-step-warp-horizontal .v-step-progress-value[data-v-3500aeb9] { position: inherit; top: 0; left: 0; height: inherit; } .v-step-list[data-v-3500aeb9] { position: relative; display: -webkit-flex; display: flex; cursor: pointer; user-select: none; } .v-step-list[data-v-3500aeb9], .v-step-item[data-v-3500aeb9] { margin: 0; padding: 0; list-style-type: none; } .v-step-warp-horizontal .v-step-list[data-v-3500aeb9] { justify-content: space-around; text-align: center; } .v-step-item-label[data-v-3500aeb9] { font-size: 12px; color: #666; } .v-step-item-number[data-v-3500aeb9] { width: 18px; height: 18px; line-height: 18px; font-size: 12px; border-radius: 50%; color: #666; background-color: #ddd; } .v-step-warp-horizontal .v-step-item-label[data-v-3500aeb9] { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .v-step-warp-horizontal .v-step-item-number[data-v-3500aeb9] { margin: 5px auto; } .v-step-warp-horizontal.style2 .v-step-progress-bg[data-v-3500aeb9] { height: 2px; bottom: 19px; } .v-step-warp-horizontal.style2 .v-step-item-number[data-v-3500aeb9] { width: 10px; height: 10px; line-height: 10px; } .v-step-warp-vertical[data-v-3500aeb9] { position: relative; padding: 0; z-index: 2; } .v-step-warp-vertical .v-step-progress-bg[data-v-3500aeb9] { position: absolute; width: 4px; height: 100%; top: 0; left: 15px; background-color: #ddd; } .v-step-warp-vertical .v-step-progress-value[data-v-3500aeb9] { position: absolute; top: 0; left: 0; width: inherit; } .v-step-warp-vertical .v-step-list[data-v-3500aeb9] { height: inherit; flex-direction: column; padding-left: 8px; } .v-step-warp-vertical .v-step-item[data-v-3500aeb9] { display: -webkit-flex; display: flex; height: 25%; align-items: center; } .v-step-warp-vertical .v-step-item-number[data-v-3500aeb9] { text-align: center; } .v-step-warp-vertical .v-step-item-label[data-v-3500aeb9] { position: absolute; order: 1; padding-left: 34px; } .v-step-warp-vertical.style2 .v-step-progress-bg[data-v-3500aeb9] { width: 2px; } .v-step-warp-vertical.style2 .v-step-item-number[data-v-3500aeb9] { width: 10px; height: 10px; line-height: 10px; margin-left: 3px; } .v-step-warp-vertical.style2 .v-step-item-label[data-v-3500aeb9] { padding-top: 0; } "; style.type='text/css'; if (style.styleSheet){ style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })(); 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | var component = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{class:[("v-step-warp-" + (_vm.direction)), _vm.styleType]},[_c('div',{staticClass:"v-step-progress-bg"},[_c('div',{staticClass:"v-step-progress-value",style:(_vm.progressStyle)})]),_vm._v(" "),_c('ul',{staticClass:"v-step-list"},_vm._l((_vm.stepList),function(label,index){return _c('li',{key:index,staticClass:"v-step-item",style:(_vm.horizontalItemWidth),on:{"click":function($event){_vm.selectItem(index);}}},[_c('label',{staticClass:"v-step-item-label"},[_vm._v(" "+_vm._s(label)+" ")]),_vm._v(" "),_c('div',{staticClass:"v-step-item-number",style:(_vm.itemNumberStyle(index))},[_vm._v(" "+_vm._s(_vm.showItemNumber(index))+" ")])])}))])},staticRenderFns: [],_scopeId: 'data-v-3500aeb9', 34 | name: 'vue-step', 35 | props: { 36 | nowStep: { 37 | type: Number, 38 | required: true 39 | }, 40 | stepList: { 41 | type: Array, 42 | required: true 43 | }, 44 | activeColor: { 45 | type: String, 46 | default: '#1fb11d' 47 | }, 48 | styleType: { 49 | type: String, 50 | default: 'style1', 51 | validator: function (value) { 52 | return ['style1', 'style2'].indexOf(value) !== -1 53 | } 54 | }, 55 | direction: { 56 | type: String, 57 | default: 'horizontal' 58 | } 59 | }, 60 | computed: { 61 | stepItemWidth: function stepItemWidth () { 62 | return 100 / this.stepList.length 63 | }, 64 | horizontalItemWidth: function horizontalItemWidth () { 65 | return this.direction === 'vertical' 66 | ? '' 67 | : { width: this.stepItemWidth + '%' } 68 | }, 69 | progressStyle: function progressStyle () { 70 | var oStyle = { 71 | 'background-color': this.activeColor 72 | }; 73 | if (this.direction === 'vertical') { 74 | oStyle.height = this.stepItemWidth * this.nowStep + '%'; 75 | } else { 76 | oStyle.width = this.stepItemWidth * this.nowStep + '%'; 77 | } 78 | return oStyle 79 | } 80 | }, 81 | methods: { 82 | itemNumberStyle: function itemNumberStyle (index) { 83 | var style = ''; 84 | if (index < this.nowStep) { 85 | style = { 86 | 'background-color': this.activeColor, 87 | 'color': '#fff' 88 | }; 89 | } 90 | return style 91 | }, 92 | showItemNumber: function showItemNumber (index) { 93 | return this.styleType !== 'style2' ? index + 1 : '' 94 | }, 95 | selectItem: function selectItem (itemIndex) { 96 | this.$emit('selected', this.showItemNumber(itemIndex)); 97 | } 98 | } 99 | } 100 | 101 | // Import vue component 102 | 103 | // install function executed by Vue.use() 104 | function install(Vue) { 105 | if (install.installed) { return; } 106 | install.installed = true; 107 | Vue.component('VueStep', component); 108 | } 109 | 110 | // Create module definition for Vue.use() 111 | var plugin = { 112 | install: install, 113 | }; 114 | 115 | // To auto-install when vue is found 116 | var GlobalVue = null; 117 | if (typeof window !== 'undefined') { 118 | GlobalVue = window.Vue; 119 | } else if (typeof global !== 'undefined') { 120 | GlobalVue = global.Vue; 121 | } 122 | if (GlobalVue) { 123 | GlobalVue.use(plugin); 124 | } 125 | 126 | // It's possible to expose named exports when writing components that can 127 | // also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo'; 128 | // export const RollupDemoDirective = component; 129 | 130 | export default component; 131 | export { install }; 132 | -------------------------------------------------------------------------------- /dist/vue-step.min.js: -------------------------------------------------------------------------------- 1 | var VueStep=function(t){"use strict";function e(t){e.installed||(e.installed=!0,t.component("VueStep",i))}!function(){if("undefined"!=typeof document){var t=document.head||document.getElementsByTagName("head")[0],e=document.createElement("style"),i=" .v-step-warp-horizontal[data-v-3500aeb9] { position: relative; padding: 10px 0; z-index: 2; } .v-step-warp-horizontal .v-step-progress-bg[data-v-3500aeb9] { position: absolute; width: 100%; height: 4px; bottom: 22px; background-color: #ddd; } .v-step-warp-horizontal .v-step-progress-value[data-v-3500aeb9] { position: inherit; top: 0; left: 0; height: inherit; } .v-step-list[data-v-3500aeb9] { position: relative; display: -webkit-flex; display: flex; cursor: pointer; user-select: none; } .v-step-list[data-v-3500aeb9], .v-step-item[data-v-3500aeb9] { margin: 0; padding: 0; list-style-type: none; } .v-step-warp-horizontal .v-step-list[data-v-3500aeb9] { justify-content: space-around; text-align: center; } .v-step-item-label[data-v-3500aeb9] { font-size: 12px; color: #666; } .v-step-item-number[data-v-3500aeb9] { width: 18px; height: 18px; line-height: 18px; font-size: 12px; border-radius: 50%; color: #666; background-color: #ddd; } .v-step-warp-horizontal .v-step-item-label[data-v-3500aeb9] { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .v-step-warp-horizontal .v-step-item-number[data-v-3500aeb9] { margin: 5px auto; } .v-step-warp-horizontal.style2 .v-step-progress-bg[data-v-3500aeb9] { height: 2px; bottom: 19px; } .v-step-warp-horizontal.style2 .v-step-item-number[data-v-3500aeb9] { width: 10px; height: 10px; line-height: 10px; } .v-step-warp-vertical[data-v-3500aeb9] { position: relative; padding: 0; z-index: 2; } .v-step-warp-vertical .v-step-progress-bg[data-v-3500aeb9] { position: absolute; width: 4px; height: 100%; top: 0; left: 15px; background-color: #ddd; } .v-step-warp-vertical .v-step-progress-value[data-v-3500aeb9] { position: absolute; top: 0; left: 0; width: inherit; } .v-step-warp-vertical .v-step-list[data-v-3500aeb9] { height: inherit; flex-direction: column; padding-left: 8px; } .v-step-warp-vertical .v-step-item[data-v-3500aeb9] { display: -webkit-flex; display: flex; height: 25%; align-items: center; } .v-step-warp-vertical .v-step-item-number[data-v-3500aeb9] { text-align: center; } .v-step-warp-vertical .v-step-item-label[data-v-3500aeb9] { position: absolute; order: 1; padding-left: 34px; } .v-step-warp-vertical.style2 .v-step-progress-bg[data-v-3500aeb9] { width: 2px; } .v-step-warp-vertical.style2 .v-step-item-number[data-v-3500aeb9] { width: 10px; height: 10px; line-height: 10px; margin-left: 3px; } .v-step-warp-vertical.style2 .v-step-item-label[data-v-3500aeb9] { padding-top: 0; } ";e.type="text/css",e.styleSheet?e.styleSheet.cssText=i:e.appendChild(document.createTextNode(i)),t.appendChild(e)}}();var i={render:function(){var t=this,e=t.$createElement,i=t._self._c||e;return i("div",{class:["v-step-warp-"+t.direction,t.styleType]},[i("div",{staticClass:"v-step-progress-bg"},[i("div",{staticClass:"v-step-progress-value",style:t.progressStyle})]),t._v(" "),i("ul",{staticClass:"v-step-list"},t._l(t.stepList,function(e,a){return i("li",{key:a,staticClass:"v-step-item",style:t.horizontalItemWidth,on:{click:function(e){t.selectItem(a)}}},[i("label",{staticClass:"v-step-item-label"},[t._v(" "+t._s(e)+" ")]),t._v(" "),i("div",{staticClass:"v-step-item-number",style:t.itemNumberStyle(a)},[t._v(" "+t._s(t.showItemNumber(a))+" ")])])}))])},staticRenderFns:[],_scopeId:"data-v-3500aeb9",name:"vue-step",props:{nowStep:{type:Number,required:!0},stepList:{type:Array,required:!0},activeColor:{type:String,default:"#1fb11d"},styleType:{type:String,default:"style1",validator:function(t){return-1!==["style1","style2"].indexOf(t)}},direction:{type:String,default:"horizontal"}},computed:{stepItemWidth:function(){return 100/this.stepList.length},horizontalItemWidth:function(){return"vertical"===this.direction?"":{width:this.stepItemWidth+"%"}},progressStyle:function(){var t={"background-color":this.activeColor};return"vertical"===this.direction?t.height=this.stepItemWidth*this.nowStep+"%":t.width=this.stepItemWidth*this.nowStep+"%",t}},methods:{itemNumberStyle:function(t){var e="";return t 2 |
3 |

Horizontal

4 |

style1:

5 | 9 |

style2:

10 | 15 | 16 |

Vertical

17 |

style1:

18 | 24 |

style2:

25 | 32 | 33 |

With @selected event

34 |

Event issued when an item is selected / clicked

35 | 40 |
41 | 42 | 43 | 64 | 65 | 78 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-step", 3 | "version": "1.3.0", 4 | "description": "Mobile Step Navigation Component Based On Vue.js", 5 | "author": "justli ", 6 | "license": "MIT", 7 | "private": false, 8 | "main": "dist/vue-step.umd.js", 9 | "module": "dist/vue-step.esm.js", 10 | "unpkg": "dist/vue-step.min.js", 11 | "browser": { 12 | "./sfc": "src/vue-step.vue" 13 | }, 14 | "scripts": { 15 | "example": "vue serve ./example/index.vue --open", 16 | "build": "npm run build:unpkg & npm run build:es & npm run build:umd", 17 | "build:umd": "rollup --config build/rollup.config.js --format umd --file dist/vue-step.umd.js", 18 | "build:es": "rollup --config build/rollup.config.js --format es --file dist/vue-step.esm.js", 19 | "build:unpkg": "rollup --config build/rollup.config.js --format iife --file dist/vue-step.min.js" 20 | }, 21 | "dependencies": {}, 22 | "devDependencies": { 23 | "minimist": "^1.2.0", 24 | "rollup": "^0.57.1", 25 | "rollup-plugin-buble": "^0.19.2", 26 | "rollup-plugin-uglify-es": "0.0.1", 27 | "rollup-plugin-vue": "^3.0.0", 28 | "vue": "^2.5.16", 29 | "vue-template-compiler": "^2.5.16" 30 | }, 31 | "keywords": [ 32 | "步骤条", 33 | "步骤导航", 34 | "移动端", 35 | "vue component", 36 | "Mobile Step Navigation", 37 | "Vue" 38 | ], 39 | "homepage": "https://github.com/luffyli/vue-step", 40 | "bugs": { 41 | "url": "https://github.com/luffyli/vue-step/issues" 42 | }, 43 | "repository": { 44 | "type": "git", 45 | "url": "git+https://github.com/luffyli/vue-step.git" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /screenshot/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luffyli/vue-step/6070bfcc32103f1a7a67c62414ba777c330c335e/screenshot/demo.png -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // Import vue component 2 | import component from './vue-step.vue'; 3 | 4 | // install function executed by Vue.use() 5 | export function install(Vue) { 6 | if (install.installed) return; 7 | install.installed = true; 8 | Vue.component('VueStep', component); 9 | } 10 | 11 | // Create module definition for Vue.use() 12 | const plugin = { 13 | install, 14 | }; 15 | 16 | // To auto-install when vue is found 17 | let GlobalVue = null; 18 | if (typeof window !== 'undefined') { 19 | GlobalVue = window.Vue; 20 | } else if (typeof global !== 'undefined') { 21 | GlobalVue = global.Vue; 22 | } 23 | if (GlobalVue) { 24 | GlobalVue.use(plugin); 25 | } 26 | 27 | // To allow use as module (npm/webpack/etc.) export component 28 | export default component; 29 | 30 | // It's possible to expose named exports when writing components that can 31 | // also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo'; 32 | // export const RollupDemoDirective = component; -------------------------------------------------------------------------------- /src/vue-step.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 101 | 102 | 221 | --------------------------------------------------------------------------------