提交 c1808467 编写于 作者: richard_1015's avatar richard_1015

Merge remote-tracking branch 'origin/v2'

{ {
"name": "@nutui/nutui", "name": "@nutui/nutui",
"version": "2.1.9", "version": "2.2.0",
"description": "一套轻量级移动端Vue组件库", "description": "一套轻量级移动端Vue组件库",
"typings": "dist/types/index.d.ts", "typings": "dist/types/index.d.ts",
"main": "dist/nutui.js", "main": "dist/nutui.js",
"files": [ "files": [
"dist", "dist",
"README.md", "README.md",
"package.json", "package.json",
"LICENSE", "LICENSE",
"CHANGELOG.md" "CHANGELOG.md"
],
"scripts": {
"dev": "npm run dev:new",
"dev:new": "cross-env NODE_ENV=development DOC_TYPE=true webpack-dev-server -d --open --config build/webpack.dev.conf.js",
"dev:carefree": "cross-env NODE_ENV=carefree carefree_env=dev webpack -w --colors --progress --config build/webpack.demo.dev.conf.js",
"dev:demo": "cross-env NODE_ENV=development webpack-dev-server -d --open --config build/webpack.demo.dev.conf.js",
"dev:doc": "cross-env NODE_ENV=development DOC_TYPE=true webpack-dev-server -d --open -w --progress --config build/webpack.doc.dev.conf.js",
"build:demo": "cross-env NODE_ENV=production webpack --hide-modules --progress --config build/webpack.demo.build.conf.js",
"build:doc": "cross-env NODE_ENV=production DOC_TYPE=true webpack --hide-modules --progress --config build/webpack.doc.build.conf.js",
"build:site": "npm run build:demo && npm run build:doc",
"build:prod": "cross-env NODE_ENV=production webpack --hide-modules --progress --config build/webpack.prod.conf.js && node scripts/createIndexScss.js",
"build:prodmin": "cross-env NODE_ENV=production webpack --hide-modules --progress --config build/webpack.prod.mini.conf.js",
"build:disp": "cross-env NODE_ENV=production PROD_TYPE=disp webpack --hide-modules --progress --config build/webpack.prod.disperse.conf.js",
"build": "npm run build:prod && npm run build:prodmin && npm run build:disp",
"clear": "node scripts/clearCache.js",
"eslint": "eslint src/packages/**/*.{js,vue}",
"add": "node scripts/createCptTpl.js",
"test": "cross-env NODE_ENV=test nyc --reporter=lcov --reporter=text mocha-webpack --webpack-config build/webpack.test.conf.js --require test/setup.js src/packages/*/__test__/**.spec.js",
"coveralls": "cat ./coverage/lcov.info | coveralls",
"test:watch": "npm run test --watch"
},
"repository": {
"type": "git",
"url": "https://github.com/jdf2e/nutui.git"
},
"keywords": [
"nutui",
"nutui2",
"vue",
"webpack",
"vue component",
"jdc",
"jdcfe"
],
"author": "jdcfe",
"license": "MIT",
"dependencies": {
"@babel/polyfill": "7.0.0",
"@babel/runtime": "7.1.2",
"cache-loader": "^4.1.0",
"happypack": "^5.0.1",
"intersection-observer": "^0.5.1",
"os": "^0.1.1",
"progress-bar-webpack-plugin": "^1.12.1",
"webpack-build-notifier": "^1.1.1"
},
"peerDependencies": {
"vue": "^2.6.10"
},
"devDependencies": {
"@babel/cli": "7.1.2",
"@babel/core": "7.1.2",
"@babel/plugin-syntax-dynamic-import": "7.0.0",
"@babel/plugin-transform-runtime": "7.1.0",
"@babel/preset-env": "7.1.0",
"@nutui/carefree": "^0.4.0",
"@tweenjs/tween.js": "17.2.0",
"@vue/test-utils": "1.0.0-beta.25",
"autoprefixer": "9.1.3",
"babel-eslint": "8.2.6",
"babel-helper-vue-jsx-merge-props": "2.0.3",
"babel-jest": "23.4.2",
"babel-loader": "8.0.4",
"babel-plugin-add-module-exports": "0.2.1",
"babel-plugin-dynamic-import-node": "2.0.0",
"babel-plugin-syntax-jsx": "6.18.0",
"babel-plugin-transform-es2015-modules-commonjs": "6.26.2",
"babel-preset-env": "1.7.0",
"babel-preset-stage-2": "6.24.1",
"chalk": "^2.4.2",
"chokidar": "^2.0.4",
"clipboard": "2.0.1",
"copy": "0.3.2",
"copy-webpack-plugin": "4.5.4",
"coveralls": "^3.0.2",
"cross-env": "^5.2.0",
"css-loader": "1.0.0",
"eslint": "4.19.1",
"eslint-loader": "2.1.1",
"eslint-plugin-vue": "4.7.1",
"expect": "23.6.0",
"file-loader": "1.1.11",
"folder-hash": "^2.1.2",
"friendly-errors-webpack-plugin": "1.7.0",
"google-code-prettify": "1.0.5",
"has": "1.0.3",
"highlight.js": "^9.13.1",
"html-webpack-plugin": "3.2.0",
"inquirer": "6.2.0",
"istanbul-instrumenter-loader": "3.0.1",
"jest": "23.5.0",
"jest-serializer-vue": "2.0.2",
"jsdom": "13.0.0",
"jsdom-global": "3.0.2",
"marked": "^0.6.1",
"mini-css-extract-plugin": "0.4.1",
"mocha": "5.2.0",
"mocha-webpack": "2.0.0-beta.0",
"moment": "2.22.2",
"node-filelist": "^1.0.0",
"node-notifier": "5.2.1",
"node-sass": "4.9.3",
"npm-run-all": "^4.1.5",
"nyc": "10.0.0",
"offline-plugin": "^5.0.6",
"optimize-css-assets-webpack-plugin": "5.0.0",
"ora": "3.0.0",
"path": "^0.12.7",
"portfinder": "1.0.17",
"postcss-import": "12.0.0",
"postcss-loader": "3.0.0",
"postcss-url": "8.0.0",
"qrcode": "1.3.2",
"raw-loader": "0.5.1",
"rimraf": "2.6.2",
"sass-loader": "7.1.0",
"sass-resources-loader": "1.3.3",
"semver": "5.5.1",
"shelljs": "^0.8.3",
"style-loader": "0.22.1",
"svg-sprite-loader": "3.9.2",
"three": "^0.99.0",
"uglifyjs-webpack-plugin": "1.3.0",
"url-loader": "1.1.1",
"vue": "^2.6.10",
"vue-i18n": "8.1.0",
"vue-jest": "2.6.0",
"vue-lazyload": "1.3.3",
"vue-loader": "15.4.0",
"vue-router": "^3.0.2",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.10",
"vueg": "1.3.4",
"webpack": "4.25.0",
"webpack-bundle-analyzer": "^3.3.2",
"webpack-cli": "3.1.0",
"webpack-dev-server": "3.1.11",
"webpack-merge": "4.1.4",
"webpack-node-externals": "1.7.2"
},
"browserslist": [
"> 3%",
"Android >= 4",
"iOS >= 8"
],
"nyc": {
"include": [
"src/packages/**/*.vue"
], ],
"instrument": false, "scripts": {
"sourceMap": false "dev": "npm run dev:new",
} "dev:new": "cross-env NODE_ENV=development DOC_TYPE=true webpack-dev-server -d --open --config build/webpack.dev.conf.js",
} "dev:carefree": "cross-env NODE_ENV=carefree carefree_env=dev webpack -w --colors --progress --config build/webpack.demo.dev.conf.js",
"dev:demo": "cross-env NODE_ENV=development webpack-dev-server -d --open --config build/webpack.demo.dev.conf.js",
"dev:doc": "cross-env NODE_ENV=development DOC_TYPE=true webpack-dev-server -d --open -w --progress --config build/webpack.doc.dev.conf.js",
"build:demo": "cross-env NODE_ENV=production webpack --hide-modules --progress --config build/webpack.demo.build.conf.js",
"build:doc": "cross-env NODE_ENV=production DOC_TYPE=true webpack --hide-modules --progress --config build/webpack.doc.build.conf.js",
"build:site": "npm run build:demo && npm run build:doc",
"build:prod": "cross-env NODE_ENV=production webpack --hide-modules --progress --config build/webpack.prod.conf.js && node scripts/createIndexScss.js",
"build:prodmin": "cross-env NODE_ENV=production webpack --hide-modules --progress --config build/webpack.prod.mini.conf.js",
"build:disp": "cross-env NODE_ENV=production PROD_TYPE=disp webpack --hide-modules --progress --config build/webpack.prod.disperse.conf.js",
"build": "npm run build:prod && npm run build:prodmin && npm run build:disp",
"clear": "node scripts/clearCache.js",
"eslint": "eslint src/packages/**/*.{js,vue}",
"add": "node scripts/createCptTpl.js",
"test": "cross-env NODE_ENV=test nyc --reporter=lcov --reporter=text mocha-webpack --webpack-config build/webpack.test.conf.js --require test/setup.js src/packages/*/__test__/**.spec.js",
"coveralls": "cat ./coverage/lcov.info | coveralls",
"test:watch": "npm run test --watch"
},
"repository": {
"type": "git",
"url": "https://github.com/jdf2e/nutui.git"
},
"keywords": [
"nutui",
"nutui2",
"vue",
"webpack",
"vue component",
"jdc",
"jdcfe"
],
"author": "jdcfe",
"license": "MIT",
"dependencies": {
"@babel/polyfill": "7.0.0",
"@babel/runtime": "7.1.2",
"cache-loader": "^4.1.0",
"happypack": "^5.0.1",
"intersection-observer": "^0.5.1",
"os": "^0.1.1",
"progress-bar-webpack-plugin": "^1.12.1",
"webpack-build-notifier": "^1.1.1"
},
"peerDependencies": {
"vue": "^2.6.10"
},
"devDependencies": {
"@babel/cli": "7.1.2",
"@babel/core": "7.1.2",
"@babel/plugin-syntax-dynamic-import": "7.0.0",
"@babel/plugin-transform-runtime": "7.1.0",
"@babel/preset-env": "7.1.0",
"@nutui/carefree": "^0.4.0",
"@tweenjs/tween.js": "17.2.0",
"@vue/test-utils": "1.0.0-beta.25",
"autoprefixer": "9.1.3",
"babel-eslint": "8.2.6",
"babel-helper-vue-jsx-merge-props": "2.0.3",
"babel-jest": "23.4.2",
"babel-loader": "8.0.4",
"babel-plugin-add-module-exports": "0.2.1",
"babel-plugin-dynamic-import-node": "2.0.0",
"babel-plugin-syntax-jsx": "6.18.0",
"babel-plugin-transform-es2015-modules-commonjs": "6.26.2",
"babel-preset-env": "1.7.0",
"babel-preset-stage-2": "6.24.1",
"chalk": "^2.4.2",
"chokidar": "^2.0.4",
"clipboard": "2.0.1",
"copy": "0.3.2",
"copy-webpack-plugin": "4.5.4",
"coveralls": "^3.0.2",
"cross-env": "^5.2.0",
"css-loader": "1.0.0",
"eslint": "4.19.1",
"eslint-loader": "2.1.1",
"eslint-plugin-vue": "4.7.1",
"expect": "23.6.0",
"file-loader": "1.1.11",
"folder-hash": "^2.1.2",
"friendly-errors-webpack-plugin": "1.7.0",
"google-code-prettify": "1.0.5",
"has": "1.0.3",
"highlight.js": "^9.13.1",
"html-webpack-plugin": "3.2.0",
"inquirer": "6.2.0",
"istanbul-instrumenter-loader": "3.0.1",
"jest": "23.5.0",
"jest-serializer-vue": "2.0.2",
"jsdom": "13.0.0",
"jsdom-global": "3.0.2",
"marked": "^0.6.1",
"mini-css-extract-plugin": "0.4.1",
"mocha": "5.2.0",
"mocha-webpack": "2.0.0-beta.0",
"moment": "2.22.2",
"node-filelist": "^1.0.0",
"node-notifier": "5.2.1",
"node-sass": "4.9.3",
"npm-run-all": "^4.1.5",
"nyc": "10.0.0",
"offline-plugin": "^5.0.6",
"optimize-css-assets-webpack-plugin": "5.0.0",
"ora": "3.0.0",
"path": "^0.12.7",
"portfinder": "1.0.17",
"postcss-import": "12.0.0",
"postcss-loader": "3.0.0",
"postcss-url": "8.0.0",
"qrcode": "1.3.2",
"raw-loader": "0.5.1",
"rimraf": "2.6.2",
"sass-loader": "7.1.0",
"sass-resources-loader": "1.3.3",
"semver": "5.5.1",
"shelljs": "^0.8.3",
"style-loader": "0.22.1",
"svg-sprite-loader": "3.9.2",
"three": "^0.99.0",
"uglifyjs-webpack-plugin": "1.3.0",
"url-loader": "1.1.1",
"vue": "^2.6.10",
"vue-i18n": "8.1.0",
"vue-jest": "2.6.0",
"vue-lazyload": "1.3.3",
"vue-loader": "15.4.0",
"vue-router": "^3.0.2",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.10",
"vueg": "1.3.4",
"webpack": "4.25.0",
"webpack-bundle-analyzer": "^3.3.2",
"webpack-cli": "3.1.0",
"webpack-dev-server": "3.1.11",
"webpack-merge": "4.1.4",
"webpack-node-externals": "1.7.2"
},
"browserslist": [
"> 3%",
"Android >= 4",
"iOS >= 8"
],
"nyc": {
"include": [
"src/packages/**/*.vue"
],
"instrument": false,
"sourceMap": false
}
}
\ No newline at end of file
此差异已折叠。
import { version } from "../package.json"; import {version} from '../package.json';
import { packages as pkgList } from "./config.json"; import {packages as pkgList} from './config.json';
import { locale } from "./locales"; import {locale} from './locales';
import Cell from "./packages/cell/index.js"; import Cell from './packages/cell/index.js';
import "./packages/cell/cell.scss"; import './packages/cell/cell.scss';
import Dialog from "./packages/dialog/index.js"; import Dialog from './packages/dialog/index.js';
import "./packages/dialog/dialog.scss"; import './packages/dialog/dialog.scss';
import Icon from "./packages/icon/index.js"; import Icon from './packages/icon/index.js';
import "./packages/icon/icon.scss"; import './packages/icon/icon.scss';
import Toast from "./packages/toast/index.js"; import Toast from './packages/toast/index.js';
import "./packages/toast/toast.scss"; import './packages/toast/toast.scss';
import ActionSheet from "./packages/actionsheet/index.js"; import ActionSheet from './packages/actionsheet/index.js';
import "./packages/actionsheet/actionsheet.scss"; import './packages/actionsheet/actionsheet.scss';
import Tab from "./packages/tab/index.js"; import Tab from './packages/tab/index.js';
import "./packages/tab/tab.scss"; import './packages/tab/tab.scss';
import TabPanel from "./packages/tabpanel/index.js"; import TabPanel from './packages/tabpanel/index.js';
import "./packages/tabpanel/tabpanel.scss"; import './packages/tabpanel/tabpanel.scss';
import TabBar from "./packages/tabbar/index.js"; import TabBar from './packages/tabbar/index.js';
import "./packages/tabbar/tabbar.scss"; import './packages/tabbar/tabbar.scss';
import Calendar from "./packages/calendar/index.js"; import Calendar from './packages/calendar/index.js';
import "./packages/calendar/calendar.scss"; import './packages/calendar/calendar.scss';
import DatePicker from "./packages/datepicker/index.js"; import DatePicker from './packages/datepicker/index.js';
import "./packages/datepicker/datepicker.scss"; import './packages/datepicker/datepicker.scss';
import NavBar from "./packages/navbar/index.js"; import NavBar from './packages/navbar/index.js';
import "./packages/navbar/navbar.scss"; import './packages/navbar/navbar.scss';
import NoticeBar from "./packages/noticebar/index.js"; import NoticeBar from './packages/noticebar/index.js';
import "./packages/noticebar/noticebar.scss"; import './packages/noticebar/noticebar.scss';
import Switch from "./packages/switch/index.js"; import Switch from './packages/switch/index.js';
import "./packages/switch/switch.scss"; import './packages/switch/switch.scss';
import Slider from "./packages/slider/index.js"; import Slider from './packages/slider/index.js';
import "./packages/slider/slider.scss"; import './packages/slider/slider.scss';
import Range from "./packages/range/index.js"; import Range from './packages/range/index.js';
import "./packages/range/range.scss"; import './packages/range/range.scss';
import Picker from "./packages/picker/index.js"; import Picker from './packages/picker/index.js';
import "./packages/picker/picker.scss"; import './packages/picker/picker.scss';
import Progress from "./packages/progress/index.js"; import Progress from './packages/progress/index.js';
import "./packages/progress/progress.scss"; import './packages/progress/progress.scss';
import Price from "./packages/price/index.js"; import Price from './packages/price/index.js';
import "./packages/price/price.scss"; import './packages/price/price.scss';
import Flex from "./packages/flex/index.js"; import Flex from './packages/flex/index.js';
import "./packages/flex/flex.scss"; import './packages/flex/flex.scss';
import Col from "./packages/col/index.js"; import Col from './packages/col/index.js';
import "./packages/col/col.scss"; import './packages/col/col.scss';
import Row from "./packages/row/index.js"; import Row from './packages/row/index.js';
import "./packages/row/row.scss"; import './packages/row/row.scss';
import Steps from "./packages/steps/index.js"; import Steps from './packages/steps/index.js';
import "./packages/steps/steps.scss"; import './packages/steps/steps.scss';
import Button from "./packages/button/index.js"; import Button from './packages/button/index.js';
import "./packages/button/button.scss"; import './packages/button/button.scss';
import Badge from "./packages/badge/index.js"; import Badge from './packages/badge/index.js';
import "./packages/badge/badge.scss"; import './packages/badge/badge.scss';
import Rate from "./packages/rate/index.js"; import Rate from './packages/rate/index.js';
import "./packages/rate/rate.scss"; import './packages/rate/rate.scss';
import Swiper from "./packages/swiper/index.js"; import Swiper from './packages/swiper/index.js';
import "./packages/swiper/swiper.scss"; import './packages/swiper/swiper.scss';
import Menu from "./packages/menu/index.js"; import Menu from './packages/menu/index.js';
import "./packages/menu/menu.scss"; import './packages/menu/menu.scss';
import Stepper from "./packages/stepper/index.js"; import Stepper from './packages/stepper/index.js';
import "./packages/stepper/stepper.scss"; import './packages/stepper/stepper.scss';
import ButtonGroup from "./packages/buttongroup/index.js"; import ButtonGroup from './packages/buttongroup/index.js';
import "./packages/buttongroup/buttongroup.scss"; import './packages/buttongroup/buttongroup.scss';
import SearchBar from "./packages/searchbar/index.js"; import SearchBar from './packages/searchbar/index.js';
import "./packages/searchbar/searchbar.scss"; import './packages/searchbar/searchbar.scss';
import ImagePicker from "./packages/imagepicker/index.js"; import ImagePicker from './packages/imagepicker/index.js';
import "./packages/imagepicker/imagepicker.scss"; import './packages/imagepicker/imagepicker.scss';
import Radio from "./packages/radio/index.js"; import Radio from './packages/radio/index.js';
import "./packages/radio/radio.scss"; import './packages/radio/radio.scss';
import RadioGroup from "./packages/radiogroup/index.js"; import RadioGroup from './packages/radiogroup/index.js';
import "./packages/radiogroup/radiogroup.scss"; import './packages/radiogroup/radiogroup.scss';
import CheckBox from "./packages/checkbox/index.js"; import CheckBox from './packages/checkbox/index.js';
import "./packages/checkbox/checkbox.scss"; import './packages/checkbox/checkbox.scss';
import CheckBoxGroup from "./packages/checkboxgroup/index.js"; import CheckBoxGroup from './packages/checkboxgroup/index.js';
import "./packages/checkboxgroup/checkboxgroup.scss"; import './packages/checkboxgroup/checkboxgroup.scss';
import ShortPassword from "./packages/shortpassword/index.js"; import ShortPassword from './packages/shortpassword/index.js';
import "./packages/shortpassword/shortpassword.scss"; import './packages/shortpassword/shortpassword.scss';
import Skeleton from "./packages/skeleton/index.js"; import Skeleton from './packages/skeleton/index.js';
import "./packages/skeleton/skeleton.scss"; import './packages/skeleton/skeleton.scss';
import Scroller from "./packages/scroller/index.js"; import Scroller from './packages/scroller/index.js';
import "./packages/scroller/scroller.scss"; import './packages/scroller/scroller.scss';
import BackTop from "./packages/backtop/index.js"; import BackTop from './packages/backtop/index.js';
import "./packages/backtop/backtop.scss"; import './packages/backtop/backtop.scss';
import CountDown from "./packages/countdown/index.js"; import CountDown from './packages/countdown/index.js';
import "./packages/countdown/countdown.scss"; import './packages/countdown/countdown.scss';
import InfiniteLoading from "./packages/infiniteloading/index.js"; import InfiniteLoading from './packages/infiniteloading/index.js';
import "./packages/infiniteloading/infiniteloading.scss"; import './packages/infiniteloading/infiniteloading.scss';
import Uploader from "./packages/uploader/index.js"; import Uploader from './packages/uploader/index.js';
import "./packages/uploader/uploader.scss"; import './packages/uploader/uploader.scss';
import TextInput from "./packages/textinput/index.js"; import TextInput from './packages/textinput/index.js';
import "./packages/textinput/textinput.scss"; import './packages/textinput/textinput.scss';
import Avatar from "./packages/avatar/index.js"; import Avatar from './packages/avatar/index.js';
import "./packages/avatar/avatar.scss"; import './packages/avatar/avatar.scss';
import Lazyload from "./packages/lazyload/index.js"; import Lazyload from './packages/lazyload/index.js';
import "./packages/textbox/textbox.scss"; import './packages/textbox/textbox.scss';
import TextBox from "./packages/textbox/index.js"; import TextBox from './packages/textbox/index.js';
import Elevator from "./packages/elevator/index.js"; import Elevator from './packages/elevator/index.js';
import "./packages/elevator/elevator.scss"; import './packages/elevator/elevator.scss';
import Popup from "./packages/popup/index.js"; import Popup from './packages/popup/index.js';
import LeftSlip from './packages/leftslip/index.js';
import './packages/leftslip/leftslip.scss';
import TabSelect from "./packages/tabselect/index.js";
import "./packages/tabselect/tabselect.scss";
import './packages/popup/popup.scss';
const packages = { const packages = {
Cell, Cell,
Dialog, Dialog,
Icon, Icon,
Toast, Toast,
ActionSheet, ActionSheet,
Tab, Tab,
TabPanel, TabPanel,
TabBar, TabBar,
Calendar, Calendar,
DatePicker, DatePicker,
NavBar, NavBar,
NoticeBar, NoticeBar,
Switch, Switch,
Slider, Slider,
Range, Range,
Picker, Picker,
Progress, Progress,
Price, Price,
Flex, Flex,
Col, Col,
Row, Row,
Steps, Steps,
Button, Button,
Badge, Badge,
Rate, Rate,
Swiper, Swiper,
Menu, Menu,
Stepper, Stepper,
ButtonGroup, ButtonGroup,
SearchBar, SearchBar,
ImagePicker, ImagePicker,
Radio, Radio,
RadioGroup, RadioGroup,
CheckBox, CheckBox,
CheckBoxGroup, CheckBoxGroup,
ShortPassword, ShortPassword,
Skeleton, Skeleton,
Scroller, Scroller,
BackTop, BackTop,
CountDown, CountDown,
InfiniteLoading, InfiniteLoading,
Uploader, Uploader,
TextInput, TextInput,
TextBox, TextBox,
Avatar, Avatar,
Elevator, Elevator,
Popup Popup,
LeftSlip,
TabSelect: TabSelect
}; };
const components = {}; const components = {};
...@@ -150,80 +158,79 @@ const methods = {}; ...@@ -150,80 +158,79 @@ const methods = {};
const filters = {}; const filters = {};
const directives = {}; const directives = {};
pkgList.map(item => { pkgList.map(item => {
const pkg = packages[item.name]; const pkg = packages[item.name];
if (!pkg) return; if (!pkg) return;
if (item.type == "component") { if (item.type == 'component') {
if (pkg.name) { if (pkg.name) {
components[pkg.name] = pkg; components[pkg.name] = pkg;
} else { } else {
for (let n in pkg) { for (let n in pkg) {
components[n] = pkg[n]; components[n] = pkg[n];
} }
}
} else if (item.type == 'method') {
methods[item.name] = pkg;
} else if (item.type == 'filter') {
filters[item.name] = pkg;
} else if (item.type == 'directive') {
directives[item.name] = pkg;
} }
} else if (item.type == "method") {
methods[item.name] = pkg;
} else if (item.type == "filter") {
filters[item.name] = pkg;
} else if (item.type == "directive") {
directives[item.name] = pkg;
}
}); });
const install = function(Vue, opts = {}) { const install = function(Vue, opts = {}) {
if (install.installed) return; if (install.installed) return;
if (opts.locale) { if (opts.locale) {
Vue.config.lang = opts.locale; Vue.config.lang = opts.locale;
} }
if (opts.lang) locale(Vue.config.lang, opts.lang); if (opts.lang) locale(Vue.config.lang, opts.lang);
for (let cptName in methods) { for (let cptName in methods) {
if (Array.isArray(methods[cptName])) { if (Array.isArray(methods[cptName])) {
Vue.prototype["$" + cptName.toLowerCase()] = methods[cptName][0]; Vue.prototype['$' + cptName.toLowerCase()] = methods[cptName][0];
Vue.component(methods[cptName][1].name, methods[cptName][1]); Vue.component(methods[cptName][1].name, methods[cptName][1]);
} else { } else {
Vue.prototype["$" + cptName.toLowerCase()] = methods[cptName]; Vue.prototype['$' + cptName.toLowerCase()] = methods[cptName];
}
} }
}
for (let cptName in components) { for (let cptName in components) {
if (components[cptName] && components[cptName].name) { if (components[cptName] && components[cptName].name) {
Vue.component(components[cptName].name, components[cptName]); Vue.component(components[cptName].name, components[cptName]);
}
} }
}
for (let cptName in filters) { for (let cptName in filters) {
if (filters[cptName] && filters[cptName].name) { if (filters[cptName] && filters[cptName].name) {
Vue.filter(cptName, filters[cptName]); Vue.filter(cptName, filters[cptName]);
}
} }
}
for (let cptName in directives) { for (let cptName in directives) {
if (directives[cptName] && directives[cptName].name) { if (directives[cptName] && directives[cptName].name) {
Vue.directive(directives[cptName].name, directives[cptName]); Vue.directive(directives[cptName].name, directives[cptName]);
}
} }
}
Vue.use(Lazyload, { Vue.use(Lazyload, {
lazyComponent: true, lazyComponent: true,
loading: loading: '//img12.360buyimg.com/imagetools/jfs/t1/73967/28/14561/916/5dc142e4E0666555b/bf33454553c6035e.png'
"//img12.360buyimg.com/imagetools/jfs/t1/73967/28/14561/916/5dc142e4E0666555b/bf33454553c6035e.png" });
});
}; };
if (typeof window !== "undefined" && window.Vue) { if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue); install(window.Vue);
} }
export default { export default {
version, version,
locale, locale,
install, install,
Lazyload, Lazyload,
...components, ...components,
...filters, ...filters,
...directives, ...directives,
...methods ...methods
}; };
\ No newline at end of file
...@@ -6,7 +6,9 @@ import Vue from 'vue'; ...@@ -6,7 +6,9 @@ import Vue from 'vue';
describe('Calendar.vue', () => { describe('Calendar.vue', () => {
const wrapper = shallowMount(Calendar, { const wrapper = shallowMount(Calendar, {
propsData: { propsData: {
defaultValue: '2020-01-12' defaultValue: '2022-01-12',
startDate: '2020-02-01',
endDate:'2028-04-11'
} }
}); });
...@@ -19,7 +21,7 @@ describe('Calendar.vue', () => { ...@@ -19,7 +21,7 @@ describe('Calendar.vue', () => {
it('设置默认日期', () => { it('设置默认日期', () => {
return Vue.nextTick().then(function () { return Vue.nextTick().then(function () {
expect(wrapper.findAll('.nut-calendar-month-title').at(0).text()).toBe('2020年01月'); expect(wrapper.findAll('.nut-calendar-month-title').at(0).text()).toBe('2022年01月');
expect(wrapper.findAll('.nut-calendar-month-item').at(0).find('.nut-calendar-month-day-active').text()).toBe('12'); expect(wrapper.findAll('.nut-calendar-month-item').at(0).find('.nut-calendar-month-day-active').text()).toBe('12');
}) })
}); });
...@@ -27,7 +29,7 @@ describe('Calendar.vue', () => { ...@@ -27,7 +29,7 @@ describe('Calendar.vue', () => {
it('选择日期', () => { it('选择日期', () => {
wrapper.findAll('.nut-calendar-month-item').at(0).findAll('.nut-calendar-month-day').at(10).trigger('click'); wrapper.findAll('.nut-calendar-month-item').at(0).findAll('.nut-calendar-month-day').at(10).trigger('click');
return Vue.nextTick().then(function () { return Vue.nextTick().then(function () {
expect(wrapper.findAll('.nut-calendar-month-item').at(0).findAll('.nut-calendar-month-day-active').at(0).text()).toBe('12'); expect(wrapper.findAll('.nut-calendar-month-item').at(0).findAll('.nut-calendar-month-day-active').at(0).text()).toBe('5');
}) })
}); });
...@@ -36,9 +38,9 @@ describe('Calendar.vue', () => { ...@@ -36,9 +38,9 @@ describe('Calendar.vue', () => {
const wrapper = shallowMount(Calendar, { const wrapper = shallowMount(Calendar, {
propsData: { propsData: {
type: 'range', type: 'range',
defaultValue: ['2020-02-22', '2020-02-25'], defaultValue: ['2022-02-22', '2022-02-25'],
startDate: '2020-02-01', startDate: '2022-02-01',
endDate:'2020-04-11' endDate:'2022-04-11'
} }
}); });
...@@ -55,7 +57,7 @@ describe('Calendar.vue', () => { ...@@ -55,7 +57,7 @@ describe('Calendar.vue', () => {
}); });
it('设置默认日期', () => { it('设置默认日期', () => {
return Vue.nextTick().then(function () { return Vue.nextTick().then(function () {
expect(wrapper.findAll('.nut-calendar-month-title').at(0).text()).toBe('2020年02月'); expect(wrapper.findAll('.nut-calendar-month-title').at(0).text()).toBe('2022年02月');
expect(wrapper.findAll('.nut-calendar-month-item').at(0).findAll('.nut-calendar-month-day-active').at(0).text()).toBe('22 开始'); expect(wrapper.findAll('.nut-calendar-month-item').at(0).findAll('.nut-calendar-month-day-active').at(0).text()).toBe('22 开始');
expect(wrapper.findAll('.nut-calendar-month-item').at(0).findAll('.nut-calendar-month-day-active').at(1).text()).toBe('25 结束'); expect(wrapper.findAll('.nut-calendar-month-item').at(0).findAll('.nut-calendar-month-day-active').at(1).text()).toBe('25 结束');
}) })
...@@ -65,8 +67,8 @@ describe('Calendar.vue', () => { ...@@ -65,8 +67,8 @@ describe('Calendar.vue', () => {
wrapper.findAll('.nut-calendar-month-item').at(1).findAll('.nut-calendar-month-day').at(14).trigger('click'); wrapper.findAll('.nut-calendar-month-item').at(1).findAll('.nut-calendar-month-day').at(14).trigger('click');
wrapper.findAll('.nut-calendar-month-item').at(1).findAll('.nut-calendar-month-day').at(16).trigger('click'); wrapper.findAll('.nut-calendar-month-item').at(1).findAll('.nut-calendar-month-day').at(16).trigger('click');
return Vue.nextTick().then(function () { return Vue.nextTick().then(function () {
expect(wrapper.findAll('.nut-calendar-month-item').at(1).findAll('.nut-calendar-month-day-active').at(0).text()).toBe('15 开始'); expect(wrapper.findAll('.nut-calendar-month-item').at(1).findAll('.nut-calendar-month-day-active').at(0).text()).toBe('13 开始');
expect(wrapper.findAll('.nut-calendar-month-item').at(1).findAll('.nut-calendar-month-day-active').at(1).text()).toBe('17 结束'); expect(wrapper.findAll('.nut-calendar-month-item').at(1).findAll('.nut-calendar-month-day-active').at(1).text()).toBe('15 结束');
}) })
}); });
......
<template> <template>
<div :class="['nut-checkboxgroup',{'vertical':vertical},customClass]" > <div :class="['nut-checkboxgroup', { vertical: vertical }, customClass]">
<div class="checkbox-item" v-for="(item,index) in checkBoxData" :key="item[keys.id]"> <div
<nut-checkbox class="checkbox-item"
:name="name||item[keys.name]" v-for="(item, index) in initData"
:disabled=" disabled || item[keys.disabled]" :key="item[keys.id]"
:label="item[keys.label]" >
:animation="animation" <nut-checkbox
:size="item.size ? item.size : size" :name="name || item[keys.name]"
:disabled="disabled || item[keys.disabled]"
:id="item[keys.id]" :label="item[keys.label]"
:checked.sync="item.checked" :animation="animation"
:size="item.size ? item.size : size"
:id="item[keys.id]"
v-model="checkboxValues[index]" :checked.sync="item.checked"
@change="changeEvt(arguments,item)" v-model="checkboxValues[index]"
@change="changeEvt(arguments, item)"
>{{ item[keys.label] || item[keys.value] || item}} >{{ item[keys.label] || item[keys.value] || item }}
</nut-checkbox> </nut-checkbox>
</div>
</div> </div>
</div>
</template> </template>
<script> <script>
import nutcheckbox from "../checkbox/checkbox.vue"; import nutcheckbox from "../checkbox/checkbox.vue";
import "../checkbox/checkbox.scss"; import "../checkbox/checkbox.scss";
export default { export default {
name:'nut-checkboxgroup', name: "nut-checkboxgroup",
props: { props: {
name: String, name: String,
checkBoxData:{ checkBoxData: {
type:Array, type: Array,
required:true, required: true
},
},
value: { value: {
type: Array, type: Array,
required: true required: true
},
keys: {
type: Object,
default() {
return {
id: 'id',
name: 'name',
class: 'class',
label: 'label',
value: 'value',
disabled: 'disabled'
};
}
},
customClass:{
type: String,
default: ''
},
label:{
type: [String, Number, Boolean],
default: ''
},
size: {
type: [String, Number],
default: 'base'
},
disabled: {
type: Boolean,
default: false
},
animation: {
type: Boolean,
default: true
},
vertical:{
type: Boolean,
default: false
}
}, },
data() { keys: {
type: Object,
default() {
return { return {
ignoreChange: false, id: "id",
checkboxValues: [], name: "name",
initialValue: [] class: "class",
label: "label",
value: "value",
disabled: "disabled"
}; };
}
},
customClass: {
type: String,
default: ""
}, },
components: { label: {
[nutcheckbox.name]: nutcheckbox type: [String, Number, Boolean],
default: ""
}, },
watch:{ size: {
value(){ type: [String, Number],
this.init(); default: "base"
},
disabled: {
type: Boolean,
default: false
},
animation: {
type: Boolean,
default: true
},
vertical: {
type: Boolean,
default: false
}
},
data() {
return {
ignoreChange: false,
initData: [],
checkboxValues: [],
initialValue: []
};
},
components: {
[nutcheckbox.name]: nutcheckbox
},
watch: {
value() {
this.init();
}
},
mounted() {
this.init();
},
methods: {
init() {
this.initialValue = this.value;
this.checkBoxData.map(item => {
if (typeof item === "object") {
item.checked = this.isOptionCheckedByDefault(item);
} }
});
}, },
mounted(){ isObject(obj) {
this.init() return obj !== null && typeof obj === "object";
}, },
methods: { looseIndexOf(arr, val) {
init(){ for (let i = 0; i < arr.length; i++) {
this.initialValue = this.value; if (this.looseEqual(arr[i], val)) {
this.checkBoxData.map(item=>{ return i;
if(typeof item ==="object"){ }
item.checked = this.isOptionCheckedByDefault(item) }
}
})
},
isObject(obj) {
return obj !== null && typeof obj === 'object';
},
looseIndexOf(arr, val) {
for (let i = 0; i < arr.length; i++) {
if (this.looseEqual(arr[i], val)) {
return i;
}
}
return -1;
},
isOptionCheckedByDefault(item) {
return this.looseIndexOf(this.initialValue, item[this.keys.value] || item) > -1;
},
looseEqual(a, b) {
return a == b || (
this.isObject(a) && this.isObject(b) ? JSON.stringify(a) === JSON.stringify(b) : false
);
},
changeEvt(args,item) {
if (this.ignoreChange) {
return;
}
const checked = args[0]; return -1;
const label = args[1]; },
const e = args[2]; isOptionCheckedByDefault(item) {
return (
this.looseIndexOf(this.initialValue, item[this.keys.value] || item) > -1
);
},
looseEqual(a, b) {
return (
a == b ||
(this.isObject(a) && this.isObject(b)
? JSON.stringify(a) === JSON.stringify(b)
: false)
);
},
changeEvt(args, item) {
if (this.ignoreChange) {
return;
}
let value = []; const checked = args[0];
const itemValue = item[this.keys.value] || item; const label = args[1];
const i = this.looseIndexOf(this.value, itemValue); const e = args[2];
if (checked && i < 0) { let value = [];
value = this.value.concat(itemValue); const itemValue = item[this.keys.value] || item;
} const i = this.looseIndexOf(this.value, itemValue);
if (!checked && i > -1) { if (checked && i < 0) {
value = this.value.slice(0, i).concat(this.value.slice(i + 1)); value = this.value.concat(itemValue);
} }
this.$emit('input', value); if (!checked && i > -1) {
this.$emit('change', value,label, e); value = this.value.slice(0, i).concat(this.value.slice(i + 1));
}
this.$emit("input", value);
}, this.$emit("change", value, label, e);
toggleAll(checked) { },
if (checked === false) { toggleAll(checked) {
this.$emit("input", []); if (checked === false) {
return; this.$emit("input", []);
} return;
if(checked === true){ }
this.checkBoxData.map(item => { if (checked === true) {
item.checked = true; this.checkBoxData.map(item => {
}); item.checked = true;
} });
if (!checked) { }
this.checkBoxData.map(item => { if (!checked) {
item.checked = !item.checked; this.checkBoxData.map(item => {
}); item.checked = !item.checked;
} });
}
let value = [], let value = [],
label = []; label = [];
let resData = this.checkBoxData.filter(item => { let resData = this.checkBoxData.filter(item => {
if (item.checked) { if (item.checked) {
value.push(item.value); value.push(item.value);
label.push(item.label); label.push(item.label);
}
return item.checked;
});
this.$emit("input",value);
this.$emit("change", value, label, null);
} }
return item.checked;
});
this.$emit("input", value);
this.$emit("change", value, label, null);
} }
} }
</script> };
\ No newline at end of file </script>
.nut-elevator{ .nut-elevator{
position: fixed;
top:40px;
width: 100%;
}
.nut-main{
overflow: scroll; overflow: scroll;
background:#FFF; background:#FFF;
&::-webkit-scrollbar{
display:none;
}
} }
.nut-elevator-ul{ .nut-elevator-ul{
width: 100%; width: 100%;
......
<template> <template>
<div class="nut-elevator" id="nut-elevator" :style="{height:wrapHeight+'px'}"> <div class="nut-elevator" :style="{height:wrapHeight+'px'}">
<ul class="nut-elevator-ul" <div class="nut-main" :style="{height:wrapHeight+'px'}">
id="nut-elevator-ul" <ul class="nut-elevator-ul"
> id="nut-elevator-ul"
<li >
v-for="item in dataArray" <li
v-bind:key="item.title" v-for="item in dataArray"
class="nut-list-title" v-bind:key="item.title"
> class="nut-list-title"
<h3 class="nut-list-h" :id="item.title">{{item.title}}</h3> >
<ul class="nut-people-list"> <h3 class="nut-list-h" :id="item.title">{{item.title}}</h3>
<li v-for="(list,idx) in item.list" <ul class="nut-people-list">
v-bind:key="idx" <li v-for="(list,idx) in item.list"
class="nut-list-name" v-bind:key="idx"
:id="list.id?list.id:'list'+item.title+idx" class="nut-list-name"
@click="clickList(list,item)" :id="list.id?list.id:'list'+item.title+idx"
>{{list.name}}</li> @click="clickList(list,item)"
>{{list.name}}</li>
</ul>
</li>
</ul> </ul>
</li> <ul class="nut-elevator-nav" id="nut-elevator-nav"
</ul> @touchmove="onPointerMove($event)"
<ul class="nut-elevator-nav" id="nut-elevator-nav" @touchstart="onPointerMove($event)"
@touchmove="onPointerMove($event)" @touchend="onPointerEnd($event)"
@touchstart="onPointerMove($event)" >
@touchend="onPointerEnd($event)" <li v-for="(item,index) in dataArray"
> v-bind:key="index"
<li v-for="(item,index) in dataArray" :id="'nav'+index"
v-bind:key="index" class="nut-nav-list"
:id="'nav'+index" :style="{height:navListHeight+'px'}"
class="nut-nav-list" @click="clickNav(item.title,index)"
:class="{'nut-nav-curr':item.title==currTitle}" >{{item.title}}</li>
:style="{height:navListHeight+'px'}" </ul>
@click="clickNav(item.title,index)" <template v-if="showIndicator">
>{{item.title}}</li> <div class="nut-big-box" v-show="currBox">
</ul> {{currTitle}}
<template v-if="showIndicator"> </div>
<div class="nut-big-box" v-show="currBox"> </template>
{{currTitle}}
</div> </div>
</template> </div>
</div>
</template> </template>
<script> <script>
export default { export default {
...@@ -107,6 +108,7 @@ export default { ...@@ -107,6 +108,7 @@ export default {
}, },
clickNav(title,index){ clickNav(title,index){
this.currBox =true; this.currBox =true;
this.currTitle = title;
setTimeout(()=>{ setTimeout(()=>{
this.currBox =false; this.currBox =false;
},this.hiddenTime); },this.hiddenTime);
...@@ -118,6 +120,7 @@ export default { ...@@ -118,6 +120,7 @@ export default {
moveFun(title,index){ moveFun(title,index){
let titleBox = document.getElementById(title); let titleBox = document.getElementById(title);
titleBox.scrollIntoView(); titleBox.scrollIntoView();
}, },
onPointerEnd(e){ onPointerEnd(e){
let fontSize = this.getFontSize(); let fontSize = this.getFontSize();
......
...@@ -136,6 +136,19 @@ export default { ...@@ -136,6 +136,19 @@ export default {
} }
}, },
activated() {
if(this.keepAlive){
this.keepAlive = false;
this.scrollListener();
}
},
deactivated() {
this.keepAlive = true;
window.removeEventListener('scroll', this.handleScroll, false);
window.removeEventListener('resize', this.handleScroll, false);
},
destroyed() { destroyed() {
window.removeEventListener('scroll', this.handleScroll, false); window.removeEventListener('scroll', this.handleScroll, false);
window.removeEventListener('resize', this.handleScroll, false); window.removeEventListener('resize', this.handleScroll, false);
......
import { shallowMount } from '@vue/test-utils'
import LeftSlip from "../leftslip.vue"
import Vue from 'vue';
describe('LeftSlip.vue', () => {
const wrapper = shallowMount(LeftSlip, {});
it('一键删除设置', () => {
wrapper.setProps({
onlyDel: true,
});
return Vue.nextTick().then(function() {
expect(wrapper.find('.delbtn').isVisible()).toBe(true);
})
})
});
\ No newline at end of file
<template>
<div>
<h4>基本用法</h4>
<div>
<nut-leftslip>
<div slot="slip-main" class="slip-main">向左滑动我</div>
<div slot="slipbtns" class="slipbtns"
><a href="javascript:;" @click="delSlipItem">删除</a><a href="javascript:;" class="favorite">收藏</a></div
>
</nut-leftslip>
</div>
<p>单个按钮</p>
<div>
<nut-leftslip>
<div slot="slip-main" class="slip-main">单一按钮</div>
<div slot="slipbtns" class="slipbtns"><a href="javascript:;">删除</a></div>
</nut-leftslip>
<nut-leftslip onlyDel @oneDelete="oneDel" ref="leftslip1">
<div slot="slip-main" class="slip-main">向左滑滑滑~一键删除</div>
</nut-leftslip>
</div>
<p>多个按钮</p>
<div>
<nut-leftslip>
<div slot="slip-main" class="slip-main">向左滑动,多个按钮有超出限制哦~</div>
<div slot="slipbtns" class="slipbtns"
><a href="javascript:;">删除</a>
<a href="javascript:;" class="favorite">收藏</a>
<a href="javascript:;" class="favorite org1"><nut-icon type="trolley" size="20px" color="#fff"></nut-icon></a>
<a href="javascript:;" class="favorite org2"><nut-icon type="cross" size="15px" color="#fff"></nut-icon></a>
<a href="javascript:;" class="favorite org3">确认</a>
<a href="javascript:;" class="favorite org1">加购物车</a>
<a href="javascript:;" class="favorite">收藏2</a>
<a href="javascript:;" class="favorite">收藏3</a>
</div>
</nut-leftslip>
</div>
<p>列表</p>
<div>
<nut-leftslip v-for="(item, index) in list" :key="item.id" ref="leftslip">
<div slot="slip-main" class="slip-main">
<div class="addr">
<p class="name-mobile">{{ item.tel }}</p>
<p class="full-addr">{{ item.addr }}</p>
</div>
<a class="addr-edit" href="javascript:void(0)"></a>
</div>
<div slot="slipbtns" class="slipbtns"
><a href="javascript:;" @click="delItem(index)">删除</a><a href="javascript:;" class="favorite">收藏</a></div
>
</nut-leftslip>
</div>
</div>
</template>
<script>
export default {
components: {},
data() {
return {
list: [
{id: 'add1', addr: '北京市大兴区亦庄经济开发中心京东大厦B座1', tel: '159****8888'},
{id: 'add2', addr: '北京市大兴区亦庄经济开发中心京东大厦B座2', tel: '159****8888'},
{id: 'add3', addr: '北京市大兴区亦庄经济开发中心京东大厦B座3', tel: '159****8888'},
{id: 'add4', addr: '北京市大兴区亦庄经济开发中心京东大厦B座4', tel: '159****8888'},
{id: 'add5', addr: '北京市大兴区亦庄经济开发中心京东大厦B座5', tel: '159****8888'},
{id: 'add6', addr: '北京市大兴区亦庄经济开发中心京东大厦B座6', tel: '159****8888'},
{id: 'add7', addr: '北京市大兴区亦庄经济开发中心京东大厦B座7', tel: '159****8888'},
{id: 'add8', addr: '北京市大兴区亦庄经济开发中心京东大厦B座8', tel: '159****8888'}
]
};
},
methods: {
delSlipItem(e) {
console.log(e.target);
},
delItem(index) {
this.list.splice(index, 1);
},
onlyDelBtnClick(par) {
// console.log(par);
par.remove();
},
oneDel(par) {
par.remove();
}
}
};
</script>
<style lang="scss" scoped>
.slip-main {
&:after {
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 200%;
height: 0;
box-sizing: border-box;
transform: scale(0.5);
transform-origin: left bottom;
border-bottom: 1px solid #ececee;
}
.addr-wrap {
display: flex;
position: relative;
width: 100%;
}
.addr {
flex: 1;
}
.addr-edit {
display: flex;
width: 36px;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAXCAYAAAGXLeQ2AAAAAXNSR0IArs4c6QAAAdFJREFUSA2tVTFuAjEQtNF1KBIvoEEiD+CkVHRX0CaPgG9Aly9ADwVFaO8LkeABeUVOAWqys7k5+Xw+zkixdF7v7ux4vWuDMe5Yr9c3jOPxeOvRMZlMuDRGEEtDCKTFBP9ms9HpBwYOECmZGJ7IcjqdDEghe9baAx21nWhsyMvlQnqVSFpBrpUnqTloBBCOKndFlZMkZHt5nrs2c71eVbdyyrFEf9W8pTKfz3WFc+GTsULB3Lxqa1QGfkgMRCSY/EFGFIi7aL0FGAwAsK2aVWP9Xdr0ZLFYoCofkuJrG0j8Z/nSNn/QLodfoqTfwjwIIRqHBZDGUACrAszdg7pAELWCfWArOASErcFc3o2qk+45Gt38t0420nC39dcK5qX3ndTxSKTlh0Sm591uh0tcPXKCKAGUprxZGKQsYxHv8mX3goDlCHWd76LErHCX9JYOh0MznU5Nv99nfLT0SPUdpWlqE8lUr/9sNosmIzBE6j7QRt8ZeE92kTL2IfIYUl51bBBFXhSF2e/3TEhr6h6/cniLKHL5+VTC0WhkBoPg74hH+6dGkWdZFgzuMj703LrIfD/+Nc8wdj1RPzCkk4OcKEsqyud2u40vZoi5tAlXIcsXqL8z/jqozhCfMwAAAABJRU5ErkJggg==)
no-repeat center center;
background-size: 23px 23px;
}
.name-mobile {
font-size: 15px;
color: #333;
}
.full-addr {
font-size: 14px;
color: #666;
margin-top: 10px;
line-height: 22px;
// height: 40px;
}
}
.slipbtns {
a {
&.favorite {
background: #ccc;
}
&.org1 {
background: #ff9800;
}
&.org2 {
background: #ffc107;
}
&.org3 {
background: #ff5722;
}
}
}
</style>
# LeftSlip 左滑删除
列表元素向左滑出现删除等按钮
## 基本用法
```html
<div>
<nut-leftslip>
<div slot="slip-main" class="slip-main">向左滑动我</div>
<div slot="slipbtns" class="slipbtns"><a href="javascript:;">删除</a><a href="javascript:;" class="favorite">收藏</a></div>
</nut-leftslip>
</div>
```
### 单个按钮
```html
<div>
<nut-leftslip>
<div slot="slip-main" class="slip-main">单一按钮</div>
<div slot="slipbtns" class="slipbtns"><a href="javascript:;">删除</a></div>
</nut-leftslip>
</div>
```
### 单个按钮左滑一键删除
```html
<nut-leftslip onlyDel @oneDelete="oneDel">
<div slot="slip-main" class="slip-main">向左滑滑滑~一键删除</div>
</nut-leftslip>
```
```javascript
export default {
oneDel(par) {
par.remove();
}
};
```
### 多个按钮
```html
<div>
<nut-leftslip>
<div slot="slip-main" class="slip-main">向左滑动,多个按钮有超出限制哦~</div>
<div slot="slipbtns" class="slipbtns"
><a href="javascript:;">删除</a>
<a href="javascript:;" class="favorite">收藏</a>
<a href="javascript:;" class="favorite org1"><nut-icon type="trolley" size="20px" color="#fff"></nut-icon></a>
<a href="javascript:;" class="favorite org2"><nut-icon type="cross" size="15px" color="#fff"></nut-icon></a>
<a href="javascript:;" class="favorite org3">确认</a>
<a href="javascript:;" class="favorite org1">加购物车</a>
<a href="javascript:;" class="favorite">收藏2</a>
<a href="javascript:;" class="favorite">收藏3</a>
</div>
</nut-leftslip>
</div>
```
### 列表
```html
<div>
<nut-leftslip v-for="(item, index) in list" :key="item.id" ref="leftslip">
<div slot="slip-main" class="slip-main">
<div class="addr">
<p class="name-mobile">159****8888</p>
<p class="full-addr">北京市大兴区亦庄经济开发中心京东大厦B座1</p>
</div>
<a class="addr-edit" href="javascript:void(0)"></a>
</div>
<div slot="slipbtns" class="slipbtns"
><a href="javascript:;" @click="delItem(index)">删除</a><a href="javascript:;" class="favorite">收藏</a></div
>
</nut-leftslip>
</div>
```
```javascript
export default {
components: {},
data() {
return {
list: [
{id: 'add1', addr: '北京市大兴区亦庄经济开发中心京东大厦B座1', tel: '159****8888'},
{id: 'add2', addr: '北京市大兴区亦庄经济开发中心京东大厦B座2', tel: '159****8888'},
{id: 'add3', addr: '北京市大兴区亦庄经济开发中心京东大厦B座3', tel: '159****8888'},
{id: 'add4', addr: '北京市大兴区亦庄经济开发中心京东大厦B座4', tel: '159****8888'},
{id: 'add5', addr: '北京市大兴区亦庄经济开发中心京东大厦B座5', tel: '159****8888'},
{id: 'add6', addr: '北京市大兴区亦庄经济开发中心京东大厦B座6', tel: '159****8888'},
{id: 'add7', addr: '北京市大兴区亦庄经济开发中心京东大厦B座7', tel: '159****8888'},
{id: 'add8', addr: '北京市大兴区亦庄经济开发中心京东大厦B座8', tel: '159****8888'}
]
};
},
methods: {
delItem(index) {
this.list.splice(index, 1);
}
}
};
```
## Prop
| 字段 | 说明 | 类型 | 默认值 |
| -------------- | ---------------------------------------------- | ------- | ------ |
| slot:slip-main | 列表主内容自定义区域 | html | - |
| slot:slipbtns | 左滑按钮自定义区域 | html | - |
| onlyDel | 显示只有一个删除按钮的列表样式(支持一键删除) | Boolean | false |
## Event
| 字段 | 说明 | 回调参数 |
| --------- | -------------------------- | -------- |
| oneDelete | 单一删除按钮模式下删除事件 | 无 |
import LeftSlip from "./leftslip.vue";
import "./leftslip.scss";
LeftSlip.install = function(Vue) {
Vue.component(LeftSlip.name, LeftSlip);
};
export default LeftSlip;
.nut-leftslip {
position: relative;
overflow: hidden;
&:first-child .nut-slip-main {
border-top: 1px solid #d8d8d8;
}
.slip-main {
padding: 10px;
position: relative;
overflow: hidden;
display: flex;
border-bottom: 1px solid #d8d8d8;
background: #fff;
}
.nut-leftslip-item {
transition: all 0.6s ease;
}
.delbtn {
position: absolute;
right: -52px;
top: 0;
min-width: 40px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
// transform: translateX(100%);
background: #ff4949;
color: #fff;
padding: 0 5px;
font-size: 14px;
span {
// width: 40px;
display: flex;
position: absolute;
right: 0;
width: 50px;
align-items: center;
justify-content: center;
height: 100%;
}
}
.slipbtns {
position: absolute;
right: 0;
top: 0;
// width: 80px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
transform: translateX(100%);
a {
display: flex;
width: 40px;
background: #ff4949;
color: #fff;
height: 100%;
padding: 0 5px;
font-size: 14px;
align-items: center;
justify-content: center;
text-align: center;
}
}
}
\ No newline at end of file
<template>
<div class="nut-leftslip">
<div class="nut-leftslip-item" ref="slipItem" :style="deleteSlider">
<div @touchstart="touchStart($event)" @touchmove="touchMove($event)" @touchend="touchEnd($event)">
<slot name="slip-main"></slot>
</div>
<div v-if="onlyDel" class="delbtn" ref="delBtn"
><div :style="delBtnStyle" class="trans"></div><span @click.prevent="onlyDelClick($event)">删除</span></div
>
<div v-else>
<!-- <a @click.prevent="onlyDelClick($event)">删除</a> -->
<slot name="slipbtns"></slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'nut-leftslip',
props: {
onlyDel: {
type: Boolean,
default: false
}
},
data() {
return {
startX: 0,
startY: 0,
moveX: 0,
moveY: 0,
left: 0,
buttonWidth: 0,
disX: 0, //移动距离
deleteSlider: '', //滑动时的效果,使用v-bind:style="deleteSlider"
delBtnStyle: '' //单个删除键拖拽删除效果
};
},
mounted() {
this.$nextTick(() => {
if (this.onlyDel) {
return;
}
for (var slot of this.$slots.slipbtns) {
this.buttonWidth = this.buttonWidth + slot.elm.offsetWidth;
}
});
window.addEventListener('scroll', this.handleScroll, true);
},
beforeDestroy() {
// 移除监听
window.removeEventListener('scroll', this.handleScroll, true);
},
methods: {
handleScroll() {
if (this.disX) {
this.restSlide();
}
},
handleClick() {
this.restSlide();
},
onlyDelClick() {
//一键删除模式点击删除
this.$emit('oneDelete', this.$refs.slipItem);
this.restSlide();
},
touchStart(e) {
this.restSlide();
e = e || event;
//等于1时表示此时有只有一只手指在触摸屏幕
if (e.touches.length == 1) {
this.startX = e.touches[0].clientX;
this.startY = e.touches[0].clientY;
}
},
touchMove(e) {
e = e || event;
//获取当前滑动对象
let parentElement = e.currentTarget.parentElement;
//获取删除按钮的宽度,此宽度为滑块左滑的最大距离
let itemWd = this.$refs.slipItem.offsetWidth;
let wd = this.onlyDel ? 40 : this.buttonWidth;
if (e.touches.length == 1) {
// 滑动时距离浏览器左侧实时距离
this.moveY = e.touches[0].clientY;
this.moveX = e.touches[0].clientX;
if (Math.abs(this.moveY - this.startY) < 40) {
//起始位置减去 实时的滑动的距离,得到手指实时偏移距离
this.disX = this.startX - this.moveX;
// console.log(this.disX);
if (this.onlyDel) {
//单一删除,左滑一键删除
if (this.disX < 0 || this.disX == 0) {
this.deleteSlider = 'transform:translateX(0px)';
}
this.deleteSlider = 'transform:translateX(-' + this.disX + 'px)';
this.delBtnStyle = 'width:' + this.disX + 'px';
parentElement.dataset.type = 1;//设置滑动展开隐藏标志位,左滑展开为1,右滑或复位为0
} else {
// 如果是向右滑动或者不滑动,不改变滑块的位置
if (this.disX < wd / 4 || this.disX == 0) {
this.deleteSlider = 'transform:translateX(0px)';
parentElement.dataset.type = 0;
} else if (this.disX > wd / 4) {
parentElement.dataset.type = 1;
this.deleteSlider = 'transform:translateX(-' + this.disX + 'px)';
// 最大也只能等于删除按钮宽度
if (this.disX * 1.5 >= wd) {
// parentElement.dataset.type = 1;
if (wd >= itemWd) {
this.deleteSlider = 'transform:translateX(-' + (itemWd - 40) + 'px)';
} else {
this.deleteSlider = 'transform:translateX(-' + wd + 'px)';
}
}
}
}
}
}
},
touchEnd(e) {
e = e || event;
let parentElement = e.currentTarget.parentElement;
let itemWd = this.$refs.slipItem.offsetWidth;
let wd = this.onlyDel ? 40 : this.buttonWidth;
if (e.changedTouches.length == 1) {
let endY = e.changedTouches[0].clientY;
if (Math.abs(this.startY - endY) < 40) {
let endX = e.changedTouches[0].clientX;
this.disX = this.startX - endX;
// console.log('touchEndthis.disX:', this.disX);
if (this.onlyDel) {
//单一按钮,左滑一键删除
if (this.disX < 0 || this.disX == 0) {
this.deleteSlider = 'transform:translateX(0px)';
parentElement.dataset.type = 0;
} else if (this.disX < itemWd - 20) {
parentElement.dataset.type = 1;
this.deleteSlider = 'transform:translateX(-50px);';
this.delBtnStyle = ' width:0px;';
} else {
this.deleteSlider = 'transform:translateX(-' + itemWd + 'px);';
this.delBtnStyle = ' width:' + itemWd + 'px;';
parentElement.dataset.type = 1;
this.onlyDelClick();
}
} else {
//如果距离小于删除按钮的四分之一,强行回到起点
if (this.disX < wd / 4) {
parentElement.dataset.type = 0;
this.deleteSlider = 'transform:translateX(0px)';
} else {
//大于一半 滑动到最大值
parentElement.dataset.type = 1;
if (wd >= itemWd) {
//按钮数不可超出整行宽度
this.deleteSlider = 'transform:translateX(-' + (itemWd - 40) + 'px)';
} else {
this.deleteSlider = 'transform:translateX(-' + wd + 'px)';
}
}
}
// console.log('touchEnd:dataset', parentElement.dataset.type);
}
}
},
restSlide() {
let listItems = document.querySelectorAll('.nut-leftslip-item');
// 复位
for (let i = 0; i < listItems.length; i++) {
listItems[i].style = 'transform:translateX(0' + 'px)';
listItems[i].dataset.type = 0;//是否展开标志位默认0,左滑展开为1,右滑隐藏为0
}
if(this.onlyDel){
let delBtns = document.querySelectorAll('.delbtn .trans');
for (let j = 0; j < delBtns.length; j++) {
delBtns[j].style = '';
}
}
}
}
};
</script>
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
height: 36px;
line-height: 36px; line-height: 36px;
color: $title-color; color: $title-color;
font-size: $font-size-base; font-size: $font-size-base;
......
...@@ -58,6 +58,49 @@ ...@@ -58,6 +58,49 @@
v-model="showRight" v-model="showRight"
:style="{ width: '20%', height: '100%' }" :style="{ width: '20%', height: '100%' }"
></nut-popup> ></nut-popup>
<h2 class="title">关闭图标</h2>
<nut-cell
isLink
title="关闭图标"
:showIcon="true"
@click.native="showIcon = true">
</nut-cell>
<nut-popup
position="bottom"
closeable
v-model="showIcon"
:style="{ height: '20%' }"
></nut-popup>
<nut-cell
isLink
title="图标位置"
:showIcon="true"
@click.native="showIconPosition = true">
</nut-cell>
<nut-popup
position="bottom"
closeable
close-icon-position="top-left"
v-model="showIconPosition"
:style="{ height: '20%' }"
></nut-popup>
<nut-cell
isLink
title="自定义图标"
:showIcon="true"
@click.native="showCloseIcon = true">
</nut-cell>
<nut-popup
position="bottom"
closeable
close-icon="tick"
v-model="showCloseIcon"
:style="{ height: '20%' }"
></nut-popup>
<h2 class="title">圆角弹框</h2> <h2 class="title">圆角弹框</h2>
<nut-cell <nut-cell
...@@ -85,7 +128,10 @@ export default { ...@@ -85,7 +128,10 @@ export default {
showBottom: false, showBottom: false,
showLeft: false, showLeft: false,
showRight: false, showRight: false,
showRound: false showIcon: false,
showRound: false,
showIconPosition: false,
showCloseIcon: false
}; };
}, },
methods: { methods: {
......
...@@ -35,12 +35,20 @@ export default { ...@@ -35,12 +35,20 @@ export default {
<nut-popup v-model="show" position="top" :style="{ height: '20%' }" /> <nut-popup v-model="show" position="top" :style="{ height: '20%' }" />
``` ```
## 关闭图标
设置closeable属性后,会在弹出层的右上角显示关闭图标,并且可以通过close-icon属性自定义图标,使用close-icon-position属性可以自定义图标位置
```html
<nut-popup position="bottom" closeable close-icon="tick" v-model="showCloseIcon" :style="{ height: '20%' }" close-icon-position="top-left"></nut-popup>
```
## 圆角弹窗 ## 圆角弹窗
设置 round 属性后,弹窗会根据弹出位置添加不同的圆角样式 设置 round 属性后,弹窗会根据弹出位置添加不同的圆角样式
```html ```html
<van-popup v-model="show" round position="bottom" :style="{ height: '20%' }" /> <nut-popup v-model="show" round position="bottom" :style="{ height: '20%' }" />
``` ```
## API ## API
...@@ -53,3 +61,7 @@ export default { ...@@ -53,3 +61,7 @@ export default {
| duration | 动画时长,单位秒 | Number | - | | duration | 动画时长,单位秒 | Number | - |
| round | 是否显示圆角 | boolean | - | | round | 是否显示圆角 | boolean | - |
| transition | 动画类名,等价于 transtion 的 name 属性 | string | - | | transition | 动画类名,等价于 transtion 的 name 属性 | string | - |
| closeable | 是否显示关闭图标 | Boolean | false |
| close-icon | 关闭图标名称 | string | cross |
| close-icon-position | 关闭图标位置,可选值为top-left bottom-left bottom-right | string | top-right |
import Popup from "./popup.vue"; import Popup from "./popup.vue";
import "./popup.scss";
Popup.install = function(Vue) { Popup.install = function(Vue) {
Vue.component(Popup.name, Popup); Vue.component(Popup.name, Popup);
......
<template> <template>
<transition name="popup-fade"> <transition name="popup-fade">
<div v-show="show" class="bg nut-mask" @click="onClick"></div> <div v-show="show" class="bg nut-mask" ></div>
</transition> </transition>
</template> </template>
<script> <script>
...@@ -8,24 +8,15 @@ export default { ...@@ -8,24 +8,15 @@ export default {
name: "nut-popup-mask", name: "nut-popup-mask",
props: { props: {
show: { type: Boolean, default: true } show: { type: Boolean, default: true }
}, },
data() {
return {};
},
methods: {
onClick() {
this.$emit("input", false);
}
}
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.popup-fade-enter-active { .popup-fade-enter-active {
animation: 0.3s van-fade-in; animation: 0.3s nut-fade-in;
} }
.popup-fade-leave-active { .popup-fade-leave-active {
animation: 0.3s van-fade-out; animation: 0.3s nut-fade-out;
} }
.bg { .bg {
position: fixed; position: fixed;
...@@ -37,7 +28,7 @@ export default { ...@@ -37,7 +28,7 @@ export default {
z-index: 99; z-index: 99;
} }
@keyframes van-fade-in { @keyframes nut-fade-in {
from { from {
opacity: 0; opacity: 0;
} }
...@@ -47,7 +38,7 @@ export default { ...@@ -47,7 +38,7 @@ export default {
} }
} }
@keyframes van-fade-out { @keyframes nut-fade-out {
from { from {
opacity: 1; opacity: 1;
} }
......
$popup-close-icon-margin: 16px;
.popup-fade-enter-active {
animation: 0.3s nut-fade-in;
}
.popup-fade-leave-active {
animation: 0.3s nut-fade-out;
}
.popup-slide {
&-top-enter,
&-top-leave-active {
transform: translate(0, -100%);
}
&-right-enter,
&-right-leave-active {
transform: translate(100%, 0);
}
&-bottom-enter,
&-bottom-leave-active {
transform: translate(0, 100%);
}
&-left-enter,
&-left-leave-active {
transform: translate(-100%, 0);
}
}
.popup-center {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.popup-bottom {
bottom: 0;
left: 0;
width: 100%;
&.round {
border-radius: 25px 25px 0 0;
}
}
.popup-right {
top: 0;
right: 0;
&.round {
border-radius: 25px 0 0 25px;
}
}
.popup-left {
top: 0;
left: 0;
&.round {
border-radius: 0 25px 25px 0;
}
}
.popup-top {
top: 0;
left: 0;
width: 100%;
&.round {
border-radius: 0 0 25px 25px;
}
}
.popup-box {
position: fixed;
max-height: 100%;
overflow-y: auto;
background-color: #fff;
transition: transform 0.3s;
-webkit-overflow-scrolling: touch;
z-index: 2028;
}
@keyframes nut-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes nut-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.nutui-popup{
&__close-icon{
position: absolute;
z-index: 1;
color: #969799;
font-size: 18px;
cursor: pointer;
&:active {
opacity: .7;
}
&--top-left {
top: $popup-close-icon-margin;
left: $popup-close-icon-margin;
}
&--top-right {
top: $popup-close-icon-margin;
right: $popup-close-icon-margin;
}
&--bottom-left {
bottom: $popup-close-icon-margin;
left: $popup-close-icon-margin;
}
&--bottom-right {
right: $popup-close-icon-margin;
bottom: $popup-close-icon-margin;
}
}
}
\ No newline at end of file
...@@ -6,7 +6,9 @@ ...@@ -6,7 +6,9 @@
class="popup-box" class="popup-box"
:class="[`popup-${position}`, { round }]" :class="[`popup-${position}`, { round }]"
> >
<slot></slot> <slot></slot>
<nut-icon v-if='closeable' @click.native='$emit("input", false)' :type="closeIcon" size="12px" class="nutui-popup__close-icon" :class="'nutui-popup__close-icon--'+closeIconPosition">
</nut-icon>
</div> </div>
</transition> </transition>
</template> </template>
...@@ -28,6 +30,18 @@ export default { ...@@ -28,6 +30,18 @@ export default {
type: Boolean, type: Boolean,
default: true default: true
}, },
closeable:{
type: Boolean,
default: false
},
closeIconPosition: {
type: String,
default: 'top-right'
},
closeIcon:{
type: String,
default: 'cross'
},
round: Boolean round: Boolean
}, },
created() { created() {
...@@ -99,98 +113,3 @@ export default { ...@@ -99,98 +113,3 @@ export default {
} }
}; };
</script> </script>
<style lang="scss" scoped>
.popup-fade-enter-active {
animation: 0.2s van-fade-in;
}
.popup-fade-leave-active {
animation: 0.2s van-fade-out;
}
.popup-slide {
&-top-enter,
&-top-leave-active {
transform: translate(0, -100%);
}
&-right-enter,
&-right-leave-active {
transform: translate(100%, 0);
}
&-bottom-enter,
&-bottom-leave-active {
transform: translate(0, 100%);
}
&-left-enter,
&-left-leave-active {
transform: translate(-100%, 0);
}
}
.popup-center {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.popup-bottom {
bottom: 0;
left: 0;
width: 100%;
&.round {
border-radius: 25px 25px 0 0;
}
}
.popup-right {
top: 0;
right: 0;
&.round {
border-radius: 25px 0 0 25px;
}
}
.popup-left {
top: 0;
left: 0;
&.round {
border-radius: 0 25px 25px 0;
}
}
.popup-top {
top: 0;
left: 0;
width: 100%;
&.round {
border-radius: 0 0 25px 25px;
}
}
.popup-box {
position: fixed;
max-height: 100%;
overflow-y: auto;
background-color: #fff;
transition: transform 0.2s;
-webkit-overflow-scrolling: touch;
z-index: 2028;
}
@keyframes van-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes van-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
</style>
...@@ -6,8 +6,9 @@ ...@@ -6,8 +6,9 @@
>此 Demo 在 PC 端浏览器与移动端浏览器体验差异较大,建议在 Android 或 iOS 设备上体验。</nut-noticebar> >此 Demo 在 PC 端浏览器与移动端浏览器体验差异较大,建议在 Android 或 iOS 设备上体验。</nut-noticebar>
<h4>横向滑动</h4> <h4>横向滑动</h4>
<p>支持惯性和吸边回弹,支持滑动到底跳转链接。</p> <p>支持惯性和吸边回弹,支持滑动到底跳转链接。</p>
<p><nut-button type="light" shape="circle" small @click="scrollToPosHor()">返回第一个</nut-button></p>
<div class="hor-panel"> <div class="hor-panel">
<nut-scroller @jump="jump()"> <nut-scroller @jump="jump()" @scrollToCbk="scrollToCbkHor" :scrollTo="scrollToHor">
<div slot="list" class="nut-hor-list-item" v-for="(item, index) of listData" :key="index"> <div slot="list" class="nut-hor-list-item" v-for="(item, index) of listData" :key="index">
<dl class="nut-scroller-item-info"> <dl class="nut-scroller-item-info">
<dt>防水升级版 蓝 迷你小音</dt> <dt>防水升级版 蓝 迷你小音</dt>
...@@ -26,19 +27,21 @@ ...@@ -26,19 +27,21 @@
<dd>2018-02-25</dd> <dd>2018-02-25</dd>
</dl> </dl>
</div> </div>
<slot slot="more" ><div class="nut-hor-jump-more">查看更多</div></slot>
</nut-scroller> </nut-scroller>
</div> </div>
<h4>纵向滑动</h4> <h4>纵向滑动</h4>
<p>支持下拉刷新、上拉加载更多。</p> <p>支持下拉刷新、上拉加载更多。</p>
<p><nut-button type="light" shape="circle" small @click="scrollToPos()">返回列表顶部</nut-button></p>
<div class="vert-panel"> <div class="vert-panel">
<nut-scroller <nut-scroller
:is-un-more="isUnMore1" :is-un-more="isUnMore1"
:is-loading="isLoading1" :is-loading="isLoading1"
:type="'vertical'" :type="'vertical'"
:propsTime="0" :propsTime="0"
:scrollTo="scrollTo"
@loadMore="loadMoreVert" @loadMore="loadMoreVert"
@pulldown="pulldown" @pulldown="pulldown"
@scrollToCbk="scrollToCbk"
> >
<div slot="list" class="nut-vert-list-panel"> <div slot="list" class="nut-vert-list-panel">
<div class="nut-vert-list-item" v-for="(item, index) of listData1" :key="index"> <div class="nut-vert-list-item" v-for="(item, index) of listData1" :key="index">
...@@ -90,6 +93,8 @@ export default { ...@@ -90,6 +93,8 @@ export default {
isLoading2: false, isLoading2: false,
page2: 2, page2: 2,
timers: null, timers: null,
scrollTo: 1,
scrollToHor: 1
}; };
}, },
...@@ -98,6 +103,23 @@ export default { ...@@ -98,6 +103,23 @@ export default {
location.href = 'http://www.jd.com'; location.href = 'http://www.jd.com';
}, },
scrollToCbk() {
this.scrollTo = 1;
},
scrollToCbkHor() {
this.scrollToHor = 1;
},
scrollToPosHor() {
this.scrollToHor = 0;
},
scrollToPos() {
this.scrollTo = 0;
},
loadMoreVert() { loadMoreVert() {
this.isLoading1 = true; this.isLoading1 = true;
if (this.page1 > this.maxPages) { if (this.page1 > this.maxPages) {
......
...@@ -174,6 +174,7 @@ export default { ...@@ -174,6 +174,7 @@ export default {
| pulldownTxt | 下拉展示文案 | String | '下拉刷新' | pulldownTxt | 下拉展示文案 | String | '下拉刷新'
| loadMoreTxt | 上拉展示文案 | String | '上拉加载' | loadMoreTxt | 上拉展示文案 | String | '上拉加载'
| unloadMoreTxt | 没有更多数据展示文案 | String | '没有更多了' | unloadMoreTxt | 没有更多数据展示文案 | String | '没有更多了'
| scrollTo | 滚动到指定位置,只能设置复数,需要配合scrollToCbk使用 | Number | 1
## Event ## Event
...@@ -181,4 +182,5 @@ export default { ...@@ -181,4 +182,5 @@ export default {
|----- | ----- | ----- |----- | ----- | -----
| pulldown | 下拉刷新回调 | - | pulldown | 下拉刷新回调 | -
| loadMore | 上拉加载回调 | - | loadMore | 上拉加载回调 | -
| jump | 查看更多跳转回调 | - | jump | 查看更多跳转回调 | -
\ No newline at end of file | scrollToCbk | 滚动到指定位置之后,scrollTo参数设置成默认值 | -
\ No newline at end of file
...@@ -16,6 +16,18 @@ export default { ...@@ -16,6 +16,18 @@ export default {
stretch: { stretch: {
type: Number, type: Number,
default: 40 default: 40
},
scrollTo: {
type: Number,
default: 1
}
},
watch: {
'scrollTo': function(val) {
if (typeof val === 'number' && !isNaN(val) && val <= 0 ) {
this.setTransform(val, null, 500);
this.$emit('scrollToCbk');
}
} }
}, },
data() { data() {
......
...@@ -10,15 +10,22 @@ ...@@ -10,15 +10,22 @@
:load-more-txt="loadMoreTxt" :load-more-txt="loadMoreTxt"
:unload-more-txt="unloadMoreTxt" :unload-more-txt="unloadMoreTxt"
:props-time="propsTime" :props-time="propsTime"
:scroll-to="scrollTo"
@loadMore="loadMore" @loadMore="loadMore"
@pulldown="pulldown" @pulldown="pulldown"
@scrollToCbk="scrollToCbk"
> >
<slot name="list" slot="list"></slot> <slot name="list" slot="list"></slot>
</nut-vert-scroll> </nut-vert-scroll>
</template> </template>
<template v-else-if="type === 'horizontal'"> <template v-else-if="type === 'horizontal'">
<nut-hor-scroll :stretch="stretch" @jump="jump"> <nut-hor-scroll
:stretch="stretch"
:scroll-to="scrollTo"
@jump="jump"
@scrollToCbk="scrollToCbk"
>
<slot name="list" slot="list"></slot> <slot name="list" slot="list"></slot>
<slot name="more" slot="more"></slot> <slot name="more" slot="more"></slot>
<slot name="arrow" slot="arrow"></slot> <slot name="arrow" slot="arrow"></slot>
...@@ -67,6 +74,10 @@ export default { ...@@ -67,6 +74,10 @@ export default {
propsTime: { propsTime: {
type:Number, type:Number,
default: 0 default: 0
},
scrollTo: {
type: Number,
default: 1
} }
}, },
data() { data() {
...@@ -87,6 +98,10 @@ export default { ...@@ -87,6 +98,10 @@ export default {
pulldown() { pulldown() {
this.$emit('pulldown'); this.$emit('pulldown');
},
scrollToCbk() {
this.$emit('scrollToCbk');
} }
} }
} }
......
...@@ -59,6 +59,10 @@ export default { ...@@ -59,6 +59,10 @@ export default {
propsTime: { propsTime: {
type:Number, type:Number,
default: 0 default: 0
},
scrollTo: {
type: Number,
default: 1
} }
}, },
watch: { watch: {
...@@ -72,6 +76,12 @@ export default { ...@@ -72,6 +76,12 @@ export default {
}, },
'isUnMore': function() { 'isUnMore': function() {
this.isShow(); this.isShow();
},
'scrollTo': function(val) {
if (typeof val === 'number' && !isNaN(val) && val <= 0 ) {
this.setTransform(val, null, 500);
this.$emit('scrollToCbk');
}
} }
}, },
data() { data() {
......
import { shallowMount, mount } from "@vue/test-utils";
import TabSelect from "../tabselect.vue";
import Vue from "vue";
describe("TabSelect.vue", () => {
const wrapper = mount(TabSelect);
it("mainTitle标题", () => {
wrapper.setProps({ mainTitle: "配送" });
return Vue.nextTick().then(function() {
expect(
wrapper
.findAll(".nut-tabselect-main-title")
.at(0)
.text()
).toBe("配送");
});
});
it("subTitle标题", () => {
wrapper.setProps({ subTitle: "送达时间" });
return Vue.nextTick().then(function() {
setTimeout(() => {
expect(
wrapper
.findAll(".nut-tabselect-sub-title")
.at(0)
.text()
).toBe("送达时间");
}, 200);
});
});
it("是否支持多选", () => {
wrapper.setProps({ multiple: true });
return Vue.nextTick().then(function() {
setTimeout(() => {
wrapper
.findAll(".nut-tab-panel-list")
.at(1)
.trigger("click");
wrapper
.findAll(".nut-tab-panel-list")
.at(2)
.trigger("click");
expect(
wrapper
.findAll(".nut-tab-panel-list")
.at(1)
.is(".nut-tab-panel-list-active")
).toBe(true);
expect(
wrapper
.findAll(".nut-tab-panel-list")
.at(2)
.is(".nut-tab-panel-list-active")
).toBe(true);
}, 200);
});
});
it("是否支持单选", () => {
wrapper.setProps({ multiple: false });
return Vue.nextTick().then(function() {
setTimeout(() => {
wrapper
.findAll(".nut-tab-panel-list")
.at(1)
.trigger("click");
wrapper
.findAll(".nut-tab-panel-list")
.at(2)
.trigger("click");
expect(
wrapper
.findAll(".nut-tab-panel-list")
.at(1)
.is(".nut-tab-panel-list-active")
).toBe(false);
expect(
wrapper
.findAll(".nut-tab-panel-list")
.at(2)
.is(".nut-tab-panel-list-active")
).toBe(true);
}, 200);
});
});
it("设置max", () => {
wrapper.setProps({ max: 2, multiple: true });
return Vue.nextTick().then(function() {
setTimeout(() => {
wrapper
.findAll(".nut-tab-panel-list")
.at(1)
.trigger("click");
wrapper
.findAll(".nut-tab-panel-list")
.at(2)
.trigger("click");
wrapper
.findAll(".nut-tab-panel-list")
.at(3)
.trigger("click");
expect(
wrapper
.findAll(".nut-tab-panel-list")
.at(1)
.is(".nut-tab-panel-list-active")
).toBe(true);
expect(
wrapper
.findAll(".nut-tab-panel-list")
.at(2)
.is(".nut-tab-panel-list-active")
).toBe(true);
expect(
wrapper
.findAll(".nut-tab-panel-list")
.at(3)
.is(".nut-tab-panel-list-active")
).toBe(false);
}, 200);
});
});
});
<template>
<div>
<nut-cell
isLink
title="展示单选弹出层"
:showIcon="true"
@click.native="show = true"
>
</nut-cell>
<nut-tabselect
:mainTitle="mainTitle"
:subTitle="subTitle"
:defaultContent="defaultContent"
:tabList="tabList"
:show="show"
@close="show = false"
@choose="choose"
:multiple="false"
></nut-tabselect>
<nut-cell
isLink
title="展示多选弹出层"
:showIcon="true"
@click.native="showMore = true"
>
</nut-cell>
<nut-tabselect
:mainTitle="mainTitle"
:subTitle="subTitle"
:defaultContent="defaultContent"
:tabList="tabList"
:show="showMore"
@close="showMore = false"
@choose="choose"
:multiple="true"
:max="3"
></nut-tabselect>
</div>
</template>
<script>
export default {
components: {},
data() {
return {
mainTitle: "配送",
subTitle: "送达时间",
defaultContent: [
"9:00——10:00",
"10:00——11:00",
"11:00——12:00",
"12:00——13:00",
"13:00——15:00",
"15:00——17:00",
"17:00——19:00"
],
tabList: [
{
tabTitle: "京东快递",
children: [
{
tabTitle: "1月13日 (星期一)",
content: [
"11:00——12:00",
"12:00——13:00",
"13:00——15:00",
"15:00——17:00",
"17:00——19:00"
]
},
{
tabTitle: "1月14日 (星期二)"
},
{
tabTitle: "1月15日 (星期三)"
},
{
tabTitle: "1月16日 (星期四)"
},
{
tabTitle: "1月17日 (星期五)"
},
{
tabTitle: "1月18日 (星期六)"
},
{
tabTitle: "1月19日 (星期天)"
}
]
},
{
tabTitle: "上门自提",
children: [
{
tabTitle: "2月13日 (星期一)",
content: ["13:00——15:00", "15:00——17:00", "17:00——19:00"]
},
{
tabTitle: "2月14日 (星期二)"
},
{
tabTitle: "2月15日 (星期三)"
},
{
tabTitle: "2月16日 (星期四)"
},
{
tabTitle: "2月17日 (星期五)"
},
{
tabTitle: "2月18日 (星期六)"
},
{
tabTitle: "2月19日 (星期天)"
}
]
}
],
show: false,
showMore: false
};
},
methods: {
choose(title, item) {
console.log(title, item);
}
}
};
</script>
<style lang="scss" scoped></style>
# TabSelect 分类选择
## 基本用法
```html
<nut-tabselect
:mainTitle="mainTitle"
:subTitle="subTitle"
:defaultContent="defaultContent"
:tabList="tabList"
:show="show"
@close="show = false"
@choose="choose"
:multiple="false"
></nut-tabselect>
```
## 基本用法(多选模式)
```html
<nut-tabselect
:mainTitle="mainTitle"
:subTitle="subTitle"
:defaultContent="defaultContent"
:tabList="tabList"
:show="show"
@close="show = false"
@choose="choose"
:multiple="true"
:max="3"
></nut-tabselect>
```
```javascript
export default {
components: {},
data() {
return {
mainTitle: "配送",
subTitle: "送达时间",
defaultContent: [
"9:00——10:00",
"10:00——11:00",
"11:00——12:00",
"12:00——13:00",
"13:00——15:00",
"15:00——17:00",
"17:00——19:00"
],
tabList: [
{
tabTitle: "京东快递", // 一级tab标题
children: [
// 一级tab内容
{
tabTitle: "1月13日 (星期一)", // 二级tab标题
content: [
// 二级tab内容,不传默认使用defaultContent字段
"11:00——12:00",
"12:00——13:00",
"13:00——15:00",
"15:00——17:00",
"17:00——19:00"
]
},
{
tabTitle: "1月14日 (星期二)"
},
{
tabTitle: "1月15日 (星期三)"
},
{
tabTitle: "1月16日 (星期四)"
},
{
tabTitle: "1月17日 (星期五)"
},
{
tabTitle: "1月18日 (星期六)"
},
{
tabTitle: "1月19日 (星期天)"
}
]
},
{
tabTitle: "上门自提",
children: [
{
tabTitle: "2月13日 (星期一)",
content: ["13:00——15:00", "15:00——17:00", "17:00——19:00"]
},
{
tabTitle: "2月14日 (星期二)"
},
{
tabTitle: "2月15日 (星期三)"
},
{
tabTitle: "2月16日 (星期四)"
},
{
tabTitle: "2月17日 (星期五)"
},
{
tabTitle: "2月18日 (星期六)"
},
{
tabTitle: "2月19日 (星期天)"
}
]
}
],
show: false
};
},
methods: {
choose(title, item) {
console.log(title, item);
}
}
};
```
### Prop
| 字段 | 说明 | 类型 | 默认值 |
| -------------- | --------------------------- | ------- | -------- |
| mainTitle | 一级 tab 标题 | String | '' |
| subTitle | 二级 tab 标题 | String | '' |
| defaultContent | 二级 tab 下内容完全一致时传 | Array | null |
| multiple | 是否允许多选 | Boolean | false |
| tabList | 整体数据 | Array | null |
| show | 是否显示 | Boolean | false |
| max | 多选时最多可选个数 | Number | Infinity |
### Event
| 事件名称 | 说明 | 回调参数 |
| -------- | -------------------- | -------------------------------------- |
| choose | 切换页签或选中某一项 | 点击的一级 tab ,二级 tab ,选中项内容 |
| close | 组件隐藏时 | -- |
import TabSelect from './tabselect.vue';
import './tabselect.scss';
TabSelect.install = function(Vue) {
Vue.component(TabSelect.name, TabSelect);
};
export default TabSelect
\ No newline at end of file
.nut-tabselect {
.nut-tab {
background: none;
border: none;
padding: 0;
}
.nav-bar {
display: none;
}
.nut-tab-item {
padding: 0;
}
.nut-tab-link {
font-size: 14px;
}
.nut-tab-title {
border: none;
height: auto;
line-height: auto;
padding-left: 18px;
.nut-title-nav-list {
flex: none;
padding: 0 13px;
height: 30px;
line-height: 30px;
border: 1px solid #333;
border-radius: 15px;
margin-right: 15px;
a {
color: #333;
}
}
.nut-tab-active {
border-color: #e2231a;
background: #fcedeb;
a {
color: #e2231a;
}
}
}
.nut-tab-inner {
.nut-tab-title-leftnav {
min-width: 158px;
}
.nut-title-nav {
height: 40px;
line-height: 40px;
background: #f4f4f4;
padding-left: 18px;
}
.nut-tab-active {
background: #fff;
}
.nut-tab-link {
line-height: inherit;
font-size: 14px;
}
.nut-tab-item {
padding: 0 10px 0 17px;
}
.nut-tab-panel {
max-height: 280px;
overflow-y: auto;
}
}
.nut-tab-title-leftnav {
border: none;
max-height: 280px;
overflow-y: auto;
.nut-title-nav {
border: none;
}
}
.nut-tabselect-main-title {
margin: 12px 0 8px 18px;
font-size: 18px;
line-height: 25px;
color: #000;
font-weight: bold;
}
.nut-tabselect-sub-title {
margin: 22px 0 11px 18px;
line-height: 20px;
color: #666;
font-size: 14px;
}
.nut-tab-panel li {
height: 29px;
line-height: 29px;
color: #333;
border: 1px solid #999999;
padding-left: 15px;
margin-bottom: 10px;
border-radius: 2px;
cursor: pointer;
&.nut-tab-panel-list-active {
color: #e2231a;
border: 1px solid #e2231a;
background: #fcedeb;
}
}
.popup-bottom.round {
border-radius: 12px 12px 0px 0px;
}
.nut-tabselect-btn {
display: flex;
background: #fff;
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 12px 18px;
a {
flex: 1;
height: 30px;
line-height: 30px;
background: linear-gradient(
135deg,
rgba(242, 20, 12, 1) 0%,
rgba(242, 39, 12, 1) 70%,
rgba(242, 77, 12, 1) 100%
);
border-radius: 15px;
color: #fff;
text-align: center;
}
}
}
<template>
<div class="nut-tabselect">
<nut-popup
round
closeable
v-model="isShow"
position="bottom"
:style="{ height: '457px' }"
>
<div class="nut-tabselect-main-title" v-html="mainTitle"></div>
<nut-tab @tab-switch="tabSwitchOuter">
<nut-tab-panel
v-for="(value, idx) in tabList"
v-bind:key="value.tabTitle"
:tabTitle="value.tabTitle"
>
<div class="nut-tabselect-sub-title" v-html="subTitle"></div>
<nut-tab
@tab-switch="tabSwitchInner"
positionNav="left"
class="nut-tab-inner"
>
<nut-tab-panel
v-for="(item, index) in value.children"
v-bind:key="item.tabTitle"
:tabTitle="item.tabTitle"
>
<ul>
<template v-if="item.content">
<li
v-for="(sitem, sIndex) in item.content"
v-bind:key="sitem"
@click="choose(idx, index, sIndex, item, sitem)"
class="nut-tab-panel-list"
:class="{
'nut-tab-panel-list-active': isActive(idx, index, sIndex)
}"
>
{{ sitem }}
</li>
</template>
<template v-else-if="defaultContent">
<li
v-for="(sitem, sIndex) in defaultContent"
v-bind:key="sitem"
@click="choose(idx, index, sIndex, item, sitem)"
class="nut-tab-panel-list"
:class="{
'nut-tab-panel-list-active': isActive(idx, index, sIndex)
}"
>
{{ sitem }}
</li>
</template>
</ul>
</nut-tab-panel>
</nut-tab>
</nut-tab-panel>
</nut-tab>
<div class="nut-tabselect-btn">
<a href="javascript:;" @click="isShow = false">确定</a>
</div>
</nut-popup>
</div>
</template>
<script>
import nuttab from "../tab/tab.vue";
import "../tab/tab.scss";
import nutpop from "../popup/popup.vue";
import "../popup/popup.scss";
export default {
name: "nut-tabselect",
props: {
mainTitle: {
type: String,
default: ""
},
subTitle: {
type: String,
default: ""
},
defaultContent: {
type: Array,
default: () => []
},
tabList: {
type: Array,
default: () => []
},
show: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: false
},
max: {
type: Number,
default: Infinity
}
},
data() {
return {
isShow: false,
level0: 0,
level1: new Set([0]),
level2: new Set(["0-0"]),
allChoose: new Set([this.getText(0, 0, 0)])
};
},
components: {
[nuttab.name]: nuttab,
[nutpop.name]: nutpop
},
watch: {
show(val) {
this.isShow = val;
},
isShow(val) {
if (!val) {
this.$emit("close");
}
}
},
mounted() {
this.emit();
},
methods: {
emit() {
this.$emit(
"choose",
(this.tabList[this.level0] && this.tabList[this.level0].tabTitle) || "",
[...this.allChoose]
);
},
getText(idx, index, sIndex) {
const tab =
(this.tabList[idx] && this.tabList[idx].children[index]) || {};
const subTit = tab.tabTitle;
const content =
(tab.content && tab.content[sIndex]) || this.defaultContent[sIndex];
return subTit + " " + content;
},
tabSwitchOuter: function(index, event) {
this.level0 = index;
this.level1 = new Set([0]);
this.level2 = new Set(["0-0"]);
this.allChoose = new Set([this.getText(index, 0, 0)]);
this.emit();
},
tabSwitchInner: function(index, event) {
if (!this.multiple) {
this.level1 = new Set([index]);
} else {
this.level1.add(index);
}
},
unChoose(index, sIndex) {
this.level2.delete(index + "-" + sIndex);
this.level2 = new Set(this.level2);
},
choose(idx, index, sIndex) {
if (this.multiple && this.isActive(idx, index, sIndex)) {
this.unChoose(index, sIndex);
this.allChoose.delete(this.getText(idx, index, sIndex));
this.emit();
return;
}
if (!this.multiple) {
this.level2 = new Set([index + "-" + sIndex]);
this.allChoose = new Set([this.getText(index, 0, 0)]);
} else {
if (this.max !== Infinity && this.max === this.level2.size) {
return;
}
this.level2 = new Set([...this.level2.add(index + "-" + sIndex)]);
this.allChoose.add(this.getText(idx, index, sIndex));
}
this.emit();
},
isActive(idx, index, sIndex) {
if (
idx === this.level0 &&
this.level1.has(index) &&
this.level2.has(index + "-" + sIndex)
) {
return true;
}
return false;
}
}
};
</script>
...@@ -88,5 +88,5 @@ export default { ...@@ -88,5 +88,5 @@ export default {
| value | 当前input值,可使用 v-model 双向绑定数据 | String | '' | value | 当前input值,可使用 v-model 双向绑定数据 | String | ''
| label | 文本框前面的标签 | String | '' | label | 文本框前面的标签 | String | ''
| disabled | 是否禁用 | Boolean | false | disabled | 是否禁用 | Boolean | false
| clearBtn | 是否需要情况按钮 | Boolean | true | clearBtn | 是否需要清空按钮 | Boolean | true
| hasBorder | 是否需要边框 | Boolean | true | hasBorder | 是否需要边框 | Boolean | true
\ No newline at end of file
...@@ -64,3 +64,7 @@ export declare class Avatar extends UIComponent {} ...@@ -64,3 +64,7 @@ export declare class Avatar extends UIComponent {}
export declare class Infiniteloading extends UIComponent {} export declare class Infiniteloading extends UIComponent {}
export declare class Lazyload extends UIComponent {} export declare class Lazyload extends UIComponent {}
export declare class Elevator extends UIComponent {} export declare class Elevator extends UIComponent {}
export declare class SlipesideBotdeslip extends UIComponent {}
export declare class TabSelect extends UIComponent {}
export declare class Popup extends UIComponent {}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册