├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── create-relaease.yml ├── .gitignore ├── CHANGELOG_CN.md ├── LICENSE ├── README.md ├── babel.config.js ├── build └── webpack.config.js ├── example ├── App.vue ├── assets │ └── icon │ │ ├── iconfont.css │ │ ├── iconfont.eot │ │ ├── iconfont.js │ │ ├── iconfont.svg │ │ ├── iconfont.ttf │ │ └── iconfont.woff ├── index.html └── main.js ├── lib └── ly-tab.common.js ├── package.json ├── src ├── index.js ├── tab-bar.vue ├── tab-item.vue ├── tabs.vue └── utils │ └── requestAnimationFrame.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = tab 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | insert_final_newline = false 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | lib 3 | node_modules 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true, 6 | es2021: true 7 | }, 8 | extends: [ 9 | 'eslint:recommended', 10 | 'plugin:vue/recommended', 11 | 'plugin:prettier/recommended' 12 | ], 13 | // 规则覆盖 14 | rules: { 15 | 'prettier/prettier': [ 16 | 'warn', 17 | { 18 | singleQuote: true, // 使用单引号 19 | useTabs: true, // 使用tab代替空格缩进 20 | // tabWidth: 2, 21 | trailingComma: 'none' // 尾部的逗号 22 | }, 23 | { 24 | usePrettierrc: false // 不使用.prettierrc配置文件 25 | } 26 | ], 27 | 'implicit-arrow-linebreak': ['warn', 'beside'], 28 | 'vue/require-default-prop': 0 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /.github/workflows/create-relaease.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - 'v*' # Push events to matching tags starts with 'v', i.e. v1.0, v20.15.10 5 | 6 | name: Create Release 7 | 8 | jobs: 9 | build: 10 | name: Create Release 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v3 15 | - name: Create Release for Tag 16 | id: release_tag 17 | uses: yyx990803/release-tag@master # https://github.com/yyx990803/release-tag 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | with: 21 | tag_name: ${{ github.ref }} 22 | body: | 23 | 更新内容请参见 [CHANGELOG](https://github.com/ScoutYin/ly-tab/blob/master/CHANGELOG_CN.md)。 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | # lock file 4 | yarn.lock -------------------------------------------------------------------------------- /CHANGELOG_CN.md: -------------------------------------------------------------------------------- 1 | ### 3.0.1 (2022-04-29) 2 | 3 | Fix: 4 | 5 | - 移除 babel-loader 生产依赖 6 | 7 | ### 3.0.0 (2022-04-29) 8 | 9 | Features: 10 | 11 | - LyTabs、LyTabItem、LyTabBar 组件 12 | 13 | ### 2.1.3 (2022-04-16) 14 | 15 | Fixed: 16 | 17 | - core 修复`ly-tabbar`组件销毁生命周期钩子名拼写错误(`destoryed` -> `destroyed`) 18 | 19 | ### 2.1.2 (2018-11-17) 20 | 21 | Fixed: 22 | 23 | - core 修复组件内部非点击修改selectId外部不更新的问题 24 | - core 修复lineWidth设置不生效的问题 25 | 26 | ### 2.1.1 (2018-9-22) 27 | 28 | Features: 29 | 30 | - core:支持ssr 31 | 32 | Fixed: 33 | 34 | - core:修复当默认选中item不在可视区时,tabbar未做位置调整使选中的item显示在可视区的bug 35 | 36 | ### 2.1.0 (2018-8-14) 37 | 38 | Features: 39 | 40 | - core:点击item时可触发ly-tab的change事件 41 | - core:可指定labelKey作为item数据中文字的字段名,不指定默认为label 42 | - style:优化组件样式 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 ScoutYin 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 | # Ly-Tab 3.x版本(非Vue3) 2 | 3 | 请注意,这个版本依然是 **Vue2** 版本。如果你想使用 **Vue3** 版本,请[点击这里](https://github.com/ScoutYin/fun-tab)。 4 | 5 | 当前的3.x版本和之前2.x版本存在使用方法及API上的不兼容,使用者如需升级,请参照3.x版本。**强烈建议**使用3.x版本,2.x版本将不再进行更新维护。 6 | 7 | ## 基本效果展示 8 | 9 | ![v3 0 0](https://user-images.githubusercontent.com/32835712/166098427-fef7c973-00aa-4a3a-82a5-41ce74dbe62f.gif) 10 | 11 | ## 安装 12 | 13 | ```shell 14 | yarn add ly-tab 15 | # or 16 | npm i ly-tab 17 | ``` 18 | ## 使用 19 | 20 | ### 全局注册 21 | 22 | ```js 23 | import LyTab from 'ly-tab'; 24 | 25 | Vue.use(LyTab); 26 | ``` 27 | 28 | ### 局部注册 29 | 30 | ```js 31 | import { LyTabs, LyTabBar, LyTabItem } from 'ly-tab'; 32 | 33 | export default { 34 | components: { 35 | LyTabs, 36 | LyTabBar, 37 | LyTabItem 38 | } 39 | // ... 40 | } 41 | ``` 42 | 43 | ## LyTabs 44 | 45 | ### 简单示例 46 | 47 | ```javascript 48 | 49 | 50 | 51 | 52 | ``` 53 | 54 | ```javascript 55 | export default { 56 | data() { 57 | return { 58 | value: '1' 59 | } 60 | } 61 | } 62 | ``` 63 | 64 | ### 属性 65 | 66 | | 属性 | 说明 | 类型 | 默认值 | 67 | | ---- | -----|---|----| 68 | | value | 当前激活的 `tab` 的 name 属性值 | `string \| number` | '' | 69 | | lineWidth | 当前激活 `tab` 下划线的宽度,单位 `px` | `number` | 30 | 70 | | lineHeight | 当前激活 `tab` 下划线的高度,单位 `px` | `number` | 3 | 71 | | activeColor | 激活状态下 `tab` 文案及下划线的颜色 | `string` | #1677ff | 72 | | additionalX | 近似等于超出边界时最大可拖动距离,单位 `px` | `number` | 50 | 73 | | reBoundExponent | 惯性回弹指数,值越大,惯性回弹距离越长 | `number` | 10 | 74 | | inertialDuration | 惯性滑动过程的持续时间,值越小,感知上阻力越大,可近似认为惯性滑动过程速度减为零所需的时间(ms) | `number` | 1000 | 75 | | reBoundingDuration | 回弹过程动画duration,单位 `ms` | `number` | 360 | 76 | 77 | ### 事件 78 | 79 | | 事件名 | 说明 | 回调参数 | 80 | | ----- | ---- | ----- | 81 | | change | 切换激活 tab 项的回调 | `name: string \| number` | 82 | 83 | ### 方法 84 | 85 | | 方法名 | 说明 | 参数 | 返回值 | 86 | | ----- | ---- | ---- | ---- | 87 | | resize | 外层元素大小或组件布局、尺寸变化时,可以调用此方法来进行重绘 | - | - | 88 | 89 | ### 插槽 90 | 91 | | 名称 | 说明 | 92 | | --- | ---- | 93 | | default | 默认插槽,放置 `LyTabItem` 组件 | 94 | 95 | ## LyTabItem 96 | 97 | ### 属性 98 | 99 | | 属性 | 说明 | 类型 | 默认值 | 100 | | ---- | -----|---|----| 101 | | title | 选项卡显示文字 | `string` | - | 102 | | name | 选项卡标识符 | `string \| number` | 选项卡索引 | 103 | | badge | 右上角徽标内容 | `string \| number` | - | 104 | 105 | ### 插槽 106 | 107 | | 名称 | 说明 | 108 | | --- | ---- | 109 | | default | 选项卡文字内容插槽,优先级高于传入的 `title` 属性 | 110 | | icon | 选项卡图标 | 111 | 112 | ## LyTabBar 113 | 114 | ### 简单示例 115 | 116 | ```javascript 117 | 118 | 119 | 120 | 121 | ``` 122 | 123 | ```javascript 124 | export default { 125 | data() { 126 | return { 127 | value: '1' 128 | } 129 | } 130 | } 131 | ``` 132 | 133 | ### 属性 134 | 135 | | 属性 | 说明 | 类型 | 默认值 | 136 | | ---- | -----|---|----| 137 | | value | 当前激活的 `tab` 的 name 属性值 | `string \| number` | '' | 138 | | activeColor | 激活状态下 `tab` 文案及icon的颜色 | `string` | #1677ff | 139 | 140 | ### 事件 141 | 142 | | 事件名 | 说明 | 回调参数 | 143 | | ----- | ---- | ----- | 144 | | change | 切换激活 tab 项的回调 | `name: string \| number` | 145 | 146 | ### 插槽 147 | 148 | | 名称 | 说明 | 149 | | --- | ---- | 150 | | default | 默认插槽,放置 `LyTabItem` 组件 | 151 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@babel/preset-env'], 3 | only: ['./src'] 4 | }; 5 | -------------------------------------------------------------------------------- /build/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge'); 2 | const path = require('path'); 3 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 5 | 6 | const rootDir = process.cwd(); 7 | 8 | const devServerConfig = { 9 | port: 8081, 10 | historyApiFallback: true, 11 | static: { 12 | publicPath: '/' 13 | }, 14 | client: { 15 | // 重连次数 16 | reconnect: 10 17 | }, 18 | onListening() { 19 | console.log(); 20 | console.log( 21 | `You application is running here http://localhost:${devServerConfig.port}` 22 | ); 23 | } 24 | }; 25 | 26 | const commonConfig = { 27 | module: { 28 | rules: [ 29 | { 30 | test: /\.js$/, 31 | exclude: /node_modules/, 32 | use: 'babel-loader' 33 | }, 34 | { 35 | test: /\.vue$/, 36 | use: 'vue-loader' 37 | }, 38 | { 39 | test: /\.css/, 40 | use: ['vue-style-loader', 'css-loader'] 41 | } 42 | ] 43 | }, 44 | optimization: { 45 | minimize: false 46 | } 47 | }; 48 | 49 | const devConfig = { 50 | mode: 'development', 51 | entry: path.resolve(rootDir, 'example/main.js'), 52 | output: { 53 | path: path.resolve(rootDir, 'dist'), 54 | filename: '[name].bundle.js' 55 | }, 56 | devServer: devServerConfig, 57 | stats: 'errors-only', 58 | 59 | resolve: { 60 | extensions: ['.vue', '.js', '...'], 61 | alias: { 62 | vue$: 'vue/dist/vue.esm.js', 63 | 'ly-tab': path.resolve(rootDir, 'src/index.js') 64 | } 65 | }, 66 | 67 | plugins: [ 68 | new VueLoaderPlugin(), 69 | new HtmlWebpackPlugin({ 70 | filename: 'index.html', 71 | inject: 'body', 72 | template: 'example/index.html' 73 | }) 74 | ] 75 | }; 76 | 77 | const prodConfig = { 78 | mode: 'production', 79 | entry: path.resolve(rootDir, 'src/index.js'), 80 | output: { 81 | path: path.resolve(rootDir, 'lib'), 82 | filename: 'ly-tab.common.js', 83 | library: { 84 | type: 'commonjs' 85 | } 86 | }, 87 | resolve: { 88 | extensions: ['.vue', '.js', '...'] 89 | }, 90 | plugins: [new VueLoaderPlugin()] 91 | }; 92 | 93 | module.exports = (env, args) => { 94 | if (args.mode === 'production') { 95 | return merge(commonConfig, prodConfig); 96 | } else { 97 | return merge(commonConfig, devConfig); 98 | } 99 | }; 100 | -------------------------------------------------------------------------------- /example/App.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 94 | 95 | 116 | -------------------------------------------------------------------------------- /example/assets/icon/iconfont.css: -------------------------------------------------------------------------------- 1 | 2 | @font-face {font-family: "ly-icon"; 3 | src: url('iconfont.eot?t=1533392363195'); /* IE9*/ 4 | src: url('iconfont.eot?t=1533392363195#iefix') format('embedded-opentype'), /* IE6-IE8 */ 5 | url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'), 6 | url('iconfont.ttf?t=1533392363195') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ 7 | url('iconfont.svg?t=1533392363195#ly-icon') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .ly-icon { 11 | font-family:"ly-icon" !important; 12 | font-size:16px; 13 | font-style:normal; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .ly-icon-sousuo:before { content: "\e6a8"; } 19 | 20 | .ly-icon-wode:before { content: "\e67b"; } 21 | 22 | .ly-icon-icon--:before { content: "\e746"; } 23 | 24 | .ly-icon-home:before { content: "\e7c6"; } 25 | 26 | -------------------------------------------------------------------------------- /example/assets/icon/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScoutYin/ly-tab/b472b0756f584526f3105864d0ab01ed8a493092/example/assets/icon/iconfont.eot -------------------------------------------------------------------------------- /example/assets/icon/iconfont.js: -------------------------------------------------------------------------------- 1 | (function(window){var svgSprite='';var script=function(){var scripts=document.getElementsByTagName("script");return scripts[scripts.length-1]}();var shouldInjectCss=script.getAttribute("data-injectcss");var ready=function(fn){if(document.addEventListener){if(~["complete","loaded","interactive"].indexOf(document.readyState)){setTimeout(fn,0)}else{var loadFn=function(){document.removeEventListener("DOMContentLoaded",loadFn,false);fn()};document.addEventListener("DOMContentLoaded",loadFn,false)}}else if(document.attachEvent){IEContentLoaded(window,fn)}function IEContentLoaded(w,fn){var d=w.document,done=false,init=function(){if(!done){done=true;fn()}};var polling=function(){try{d.documentElement.doScroll("left")}catch(e){setTimeout(polling,50);return}init()};polling();d.onreadystatechange=function(){if(d.readyState=="complete"){d.onreadystatechange=null;init()}}}};var before=function(el,target){target.parentNode.insertBefore(el,target)};var prepend=function(el,target){if(target.firstChild){before(el,target.firstChild)}else{target.appendChild(el)}};function appendSvg(){var div,svg;div=document.createElement("div");div.innerHTML=svgSprite;svgSprite=null;svg=div.getElementsByTagName("svg")[0];if(svg){svg.setAttribute("aria-hidden","true");svg.style.position="absolute";svg.style.width=0;svg.style.height=0;svg.style.overflow="hidden";prepend(svg,document.body)}}if(shouldInjectCss&&!window.__iconfont__svg__cssinject__){window.__iconfont__svg__cssinject__=true;try{document.write("")}catch(e){console&&console.log(e)}}ready(appendSvg)})(window) -------------------------------------------------------------------------------- /example/assets/icon/iconfont.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Created by iconfont 9 | 10 | 11 | 12 | 13 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/assets/icon/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScoutYin/ly-tab/b472b0756f584526f3105864d0ab01ed8a493092/example/assets/icon/iconfont.ttf -------------------------------------------------------------------------------- /example/assets/icon/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScoutYin/ly-tab/b472b0756f584526f3105864d0ab01ed8a493092/example/assets/icon/iconfont.woff -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ly-tab使用demo 7 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /example/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue'; 4 | import App from './App'; 5 | 6 | Vue.config.productionTip = false; 7 | 8 | /* eslint-disable no-new */ 9 | new Vue({ 10 | el: '#app', 11 | components: { App }, 12 | template: '' 13 | }); 14 | -------------------------------------------------------------------------------- /lib/ly-tab.common.js: -------------------------------------------------------------------------------- 1 | /******/ (function() { // webpackBootstrap 2 | /******/ var __webpack_modules__ = ({ 3 | 4 | /***/ 696: 5 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 6 | 7 | "use strict"; 8 | __webpack_require__.r(__webpack_exports__); 9 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(81); 10 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__); 11 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(645); 12 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__); 13 | // Imports 14 | 15 | 16 | var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default())); 17 | // Module 18 | ___CSS_LOADER_EXPORT___.push([module.id, "\n.ly-tab-bar-wrap {\n\tdisplay: flex;\n\tflex-wrap: nowrap;\n\talign-items: stretch;\n\tmin-height: 50px;\n\tbackground: #fff;\n}\n.ly-tab-bar .ly-tab-item {\n\tflex: 1 1;\n\tfont-size: 12px;\n}\n.ly-tab-bar .ly-tab-item__badge {\n\ttop: 2px;\n\tright: 0;\n}\n", ""]); 19 | // Exports 20 | /* harmony default export */ __webpack_exports__["default"] = (___CSS_LOADER_EXPORT___); 21 | 22 | 23 | /***/ }), 24 | 25 | /***/ 918: 26 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 27 | 28 | "use strict"; 29 | __webpack_require__.r(__webpack_exports__); 30 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(81); 31 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__); 32 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(645); 33 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__); 34 | // Imports 35 | 36 | 37 | var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default())); 38 | // Module 39 | ___CSS_LOADER_EXPORT___.push([module.id, "\n.ly-tab-item {\n\tdisplay: flex;\n\tflex-direction: column;\n\tjustify-content: center;\n\talign-items: center;\n}\n.ly-tab-item__wrap {\n\tposition: relative;\n}\n.ly-tab-item__badge {\n\tposition: absolute;\n\ttop: 4px;\n\tright: -10px;\n\tpadding: 1px 4px;\n\tmin-width: 8px;\n\tfont-size: 9px;\n\tline-height: 12px;\n\tcolor: #fff;\n\tbackground: #ff411c;\n\twhite-space: nowrap;\n\tborder-radius: 100px;\n\ttransform: translate(50%, -50%);\n\ttext-align: center;\n}\n", ""]); 40 | // Exports 41 | /* harmony default export */ __webpack_exports__["default"] = (___CSS_LOADER_EXPORT___); 42 | 43 | 44 | /***/ }), 45 | 46 | /***/ 374: 47 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 48 | 49 | "use strict"; 50 | __webpack_require__.r(__webpack_exports__); 51 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(81); 52 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__); 53 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(645); 54 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__); 55 | // Imports 56 | 57 | 58 | var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default())); 59 | // Module 60 | ___CSS_LOADER_EXPORT___.push([module.id, "\n.ly-tabs {\n\toverflow: hidden;\n\tposition: relative;\n\twidth: 100%;\n\tborder-bottom: 1px solid #eee;\n\tbackground: #fff;\n}\n.ly-tabs__tab-list {\n\tposition: relative;\n\tdisplay: flex;\n\tflex-wrap: nowrap;\n\tmin-width: 100%;\n\twidth: min-content;\n}\n.ly-tabs__active-line {\n\tposition: absolute;\n\tbottom: 3px;\n\tleft: 0;\n\twidth: 30px;\n\theight: 3px;\n\tborder-radius: 4px;\n}\n.ly-tabs .ly-tab-item {\n\tpadding: 10px 12px;\n\tflex: 1 1 auto;\n\tfont-size: 14px;\n\ttext-align: center;\n\twhite-space: nowrap;\n}\n", ""]); 61 | // Exports 62 | /* harmony default export */ __webpack_exports__["default"] = (___CSS_LOADER_EXPORT___); 63 | 64 | 65 | /***/ }), 66 | 67 | /***/ 645: 68 | /***/ (function(module) { 69 | 70 | "use strict"; 71 | 72 | 73 | /* 74 | MIT License http://www.opensource.org/licenses/mit-license.php 75 | Author Tobias Koppers @sokra 76 | */ 77 | module.exports = function (cssWithMappingToString) { 78 | var list = []; // return the list of modules as css string 79 | 80 | list.toString = function toString() { 81 | return this.map(function (item) { 82 | var content = ""; 83 | var needLayer = typeof item[5] !== "undefined"; 84 | 85 | if (item[4]) { 86 | content += "@supports (".concat(item[4], ") {"); 87 | } 88 | 89 | if (item[2]) { 90 | content += "@media ".concat(item[2], " {"); 91 | } 92 | 93 | if (needLayer) { 94 | content += "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {"); 95 | } 96 | 97 | content += cssWithMappingToString(item); 98 | 99 | if (needLayer) { 100 | content += "}"; 101 | } 102 | 103 | if (item[2]) { 104 | content += "}"; 105 | } 106 | 107 | if (item[4]) { 108 | content += "}"; 109 | } 110 | 111 | return content; 112 | }).join(""); 113 | }; // import a list of modules into the list 114 | 115 | 116 | list.i = function i(modules, media, dedupe, supports, layer) { 117 | if (typeof modules === "string") { 118 | modules = [[null, modules, undefined]]; 119 | } 120 | 121 | var alreadyImportedModules = {}; 122 | 123 | if (dedupe) { 124 | for (var k = 0; k < this.length; k++) { 125 | var id = this[k][0]; 126 | 127 | if (id != null) { 128 | alreadyImportedModules[id] = true; 129 | } 130 | } 131 | } 132 | 133 | for (var _k = 0; _k < modules.length; _k++) { 134 | var item = [].concat(modules[_k]); 135 | 136 | if (dedupe && alreadyImportedModules[item[0]]) { 137 | continue; 138 | } 139 | 140 | if (typeof layer !== "undefined") { 141 | if (typeof item[5] === "undefined") { 142 | item[5] = layer; 143 | } else { 144 | item[1] = "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {").concat(item[1], "}"); 145 | item[5] = layer; 146 | } 147 | } 148 | 149 | if (media) { 150 | if (!item[2]) { 151 | item[2] = media; 152 | } else { 153 | item[1] = "@media ".concat(item[2], " {").concat(item[1], "}"); 154 | item[2] = media; 155 | } 156 | } 157 | 158 | if (supports) { 159 | if (!item[4]) { 160 | item[4] = "".concat(supports); 161 | } else { 162 | item[1] = "@supports (".concat(item[4], ") {").concat(item[1], "}"); 163 | item[4] = supports; 164 | } 165 | } 166 | 167 | list.push(item); 168 | } 169 | }; 170 | 171 | return list; 172 | }; 173 | 174 | /***/ }), 175 | 176 | /***/ 81: 177 | /***/ (function(module) { 178 | 179 | "use strict"; 180 | 181 | 182 | module.exports = function (i) { 183 | return i[1]; 184 | }; 185 | 186 | /***/ }), 187 | 188 | /***/ 923: 189 | /***/ (function(module, __unused_webpack_exports, __webpack_require__) { 190 | 191 | // style-loader: Adds some css to the DOM by adding a 62 | -------------------------------------------------------------------------------- /src/tab-item.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 44 | 45 | 71 | -------------------------------------------------------------------------------- /src/tabs.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 395 | 396 | 430 | -------------------------------------------------------------------------------- /src/utils/requestAnimationFrame.js: -------------------------------------------------------------------------------- 1 | export function windowInit() { 2 | var lastTime = 0; 3 | var vendors = ['webkit', 'moz']; 4 | for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 5 | window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; 6 | window.cancelAnimationFrame = 7 | window[vendors[x] + 'CancelAnimationFrame'] || // name has changed in Webkit 8 | window[vendors[x] + 'CancelRequestAnimationFrame']; 9 | } 10 | 11 | if (!window.requestAnimationFrame) { 12 | window.requestAnimationFrame = function (callback) { 13 | var currTime = new Date().getTime(); 14 | var timeToCall = Math.max(0, 16.7 - (currTime - lastTime)); 15 | var interval = currTime - lastTime; 16 | var id = window.setTimeout(function () { 17 | callback(interval); 18 | }, timeToCall); 19 | lastTime = currTime + timeToCall; 20 | return id; 21 | }; 22 | } 23 | if (!window.cancelAnimationFrame) { 24 | window.cancelAnimationFrame = function (id) { 25 | clearTimeout(id); 26 | }; 27 | } 28 | } 29 | --------------------------------------------------------------------------------