├── .babelrc ├── .eslintrc.js ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── postcss.config.js ├── src ├── assest │ └── close.png ├── components │ ├── index.less │ ├── mainContent.vue │ └── modal.vue └── index.js ├── webpack.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/preset-env", { 4 | "targets": { 5 | "edge": "17", 6 | "firefox": "60", 7 | "chrome": "67", 8 | "safari": "11.1", 9 | "ie": "10" 10 | }, 11 | "corejs": "2", 12 | "useBuiltIns": "usage" 13 | } 14 | ] 15 | ] 16 | } -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | }, 6 | extends: [ 7 | 'plugin:vue/essential', 8 | 'airbnb-base', 9 | ], 10 | parserOptions: { 11 | ecmaVersion: 12, 12 | sourceType: 'module', 13 | }, 14 | plugins: [ 15 | 'vue', 16 | ], 17 | rules: { 18 | 'linebreak-style': [0, 'error', 'windows'], 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /lib 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # drag-modal-vue 2 | 3 | #### 基于vue,不依赖任何UI库的可拖拽弹窗组件 4 | 5 | #### ![演示动画.gif](https://upload-images.jianshu.io/upload_images/18029972-ad5c878a480fe63f.gif?imageMogr2/auto-orient/strip) 6 | 7 | #### 安装及使用 8 | 9 | ``` 10 | yarn add drag-modal-vue -S 11 | or 12 | npm install drag-modal-vue -S 13 | ``` 14 | ``` 15 | // main.js 16 | import dragModalVue from "drag-modal-vue"; 17 | import "drag-modal-vue/lib/main.css" 18 | Vue.use(dragModalVue); 19 | ... 20 | ``` 21 | 22 | ``` 23 | // page.vue 24 | 32 | ``` 33 | 34 | #### 属性 35 | 36 | | 属性名 | 含义 | 默认值 |类型 37 | | :----:| :----: | :----: |:----: | 38 | | visible(`v-model`)(visible.sync) | 弹窗的显隐 | false | Boolean 39 | | title | 标题 | '' | String 40 | | width | 弹窗宽度 | 500 | Number 41 | | height | 弹窗高度 | 0(auto) | Number 42 | | mask | 是否显示遮罩 | true | Boolean 43 | | maskClosable | 点击遮罩是否允许关闭 | true | Boolean 44 | | zIndex | 内容的`z-index`值 | 10 | Number 45 | | ok | 点击"确认按钮"的回调 | - | Function 46 | | cancel | 点击"取消按钮"的回调 | - | Function 47 | 48 | #### 插槽 49 | 50 | | 插槽名 | 含义 | 默认值 |类型 51 | | :----:| :----: | :----: |:----: | 52 | | footer | 弹窗页脚 | 确认取消按钮(建议使用自己UI库按钮) | slot 53 | | close | 自定义右上角关闭按钮 | "X"号图片 | slot 54 | 55 | #### 代码贡献 56 | [ZSJ1314](https://github.com/ZSJ1314)、[sorryljt](https://github.com/sorryljt) 57 | 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "drag-modal-vue", 3 | "version": "1.2.1", 4 | "sideEffects": [ 5 | "*.less", 6 | "*.css" 7 | ], 8 | "description": "a drag layer in Vue", 9 | "main": "./lib/main.js", 10 | "scripts": { 11 | "build": "webpack" 12 | }, 13 | "keywords": [ 14 | "vue可拖拽的弹层", 15 | "drag-modal-vue", 16 | "可拖拽弹层" 17 | ], 18 | "author": "sorryljt", 19 | "license": "MIT", 20 | "devDependencies": { 21 | "@babel/core": "^7.11.6", 22 | "@babel/preset-env": "^7.11.5", 23 | "autoprefixer": "9.8.6", 24 | "babel-loader": "^8.1.0", 25 | "clean-webpack-plugin": "^3.0.0", 26 | "css-loader": "^4.3.0", 27 | "eslint": "^7.11.0", 28 | "eslint-config-airbnb-base": "^14.2.0", 29 | "eslint-loader": "^4.0.2", 30 | "eslint-plugin-import": "^2.22.1", 31 | "eslint-plugin-vue": "^7.0.1", 32 | "less": "^3.12.2", 33 | "less-loader": "^7.0.1", 34 | "mini-css-extract-plugin": "^0.12.0", 35 | "optimize-css-assets-webpack-plugin": "^5.0.4", 36 | "postcss-loader": "^4.0.3", 37 | "url-loader": "^4.1.0", 38 | "vue-loader": "^15.9.3", 39 | "vue-template-compiler": "^2.6.12", 40 | "webpack": "^4.44.2", 41 | "webpack-cli": "^3.3.12" 42 | }, 43 | "dependencies": { 44 | "@babel/polyfill": "^7.11.5", 45 | "core-js": "2", 46 | "vue": "^2.6.12" 47 | }, 48 | "browserslist": [ 49 | "defaults", 50 | "not ie <= 8", 51 | "last 2 versions", 52 | "> 1%", 53 | "iOS >= 7", 54 | "Android >= 4.0" 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('autoprefixer') 4 | ] 5 | } -------------------------------------------------------------------------------- /src/assest/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sorryljt/drag-modal-vue/7e7617644a43266c995aa753e0a2f936bf8641e3/src/assest/close.png -------------------------------------------------------------------------------- /src/components/index.less: -------------------------------------------------------------------------------- 1 | .drag-modal-vue-modal { 2 | position: absolute; 3 | top: 50%; 4 | left: 50%; 5 | transform: translate(-50%, -50%); 6 | background: #fff; 7 | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); 8 | border: 0; 9 | border-radius: 4px; 10 | .drag-modal-vue-header { 11 | background-color: white; 12 | color: #333; 13 | padding: 10px 15px; 14 | display: flex; 15 | justify-content: space-between; 16 | align-items: center; 17 | background: #f3f3f3; 18 | border-top-left-radius: 4px; 19 | border-top-right-radius: 4px; 20 | &:hover { 21 | cursor: move; 22 | } 23 | } 24 | .drag-modal-vue-title { 25 | font-size: 16px; 26 | color: #333; 27 | } 28 | .drag-modal-vue-main { 29 | padding: 10px 15px 0 15px; 30 | } 31 | .drag-modal-vue-footer { 32 | padding: 10px 15px; 33 | text-align: right; 34 | } 35 | } 36 | .drag-modal-vue-modal-warp { 37 | position: fixed; 38 | left: 0; 39 | right: 0; 40 | top: 0; 41 | bottom: 0; 42 | z-index: 10; 43 | .drag-modal-vue-modal-btn { 44 | margin-left: 10px; 45 | line-height: 1.499; 46 | position: relative; 47 | display: inline-block; 48 | font-weight: 400; 49 | white-space: nowrap; 50 | text-align: center; 51 | background-image: none; 52 | border: 1px solid transparent; 53 | box-shadow: 0 2px 0 rgba(0, 0, 0, 0.015); 54 | cursor: pointer; 55 | transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); 56 | -webkit-user-select: none; 57 | -moz-user-select: none; 58 | -ms-user-select: none; 59 | user-select: none; 60 | touch-action: manipulation; 61 | height: 32px; 62 | padding: 0 15px; 63 | font-size: 14px; 64 | border-radius: 4px; 65 | color: rgba(0, 0, 0, 0.65); 66 | background-color: #fff; 67 | border-color: #d9d9d9; 68 | &:hover { 69 | text-decoration: none; 70 | background: #fff; 71 | color: #40a9ff; 72 | border-color: #40a9ff; 73 | } 74 | &:active { 75 | color: #096dd9; 76 | outline: 0; 77 | box-shadow: none; 78 | text-decoration: none; 79 | background: #fff; 80 | border-color: #096dd9; 81 | } 82 | &:focus { 83 | color: #096dd9; 84 | text-decoration: none; 85 | background: #fff; 86 | outline: 0; 87 | border-color: #096dd9; 88 | } 89 | } 90 | .drag-modal-vue-close { 91 | width: 18px; 92 | &:hover { 93 | cursor: pointer; 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /src/components/mainContent.vue: -------------------------------------------------------------------------------- 1 | 19 | 112 | 114 | -------------------------------------------------------------------------------- /src/components/modal.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 122 | 124 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import dragModalVue from './components/modal.vue'; 2 | 3 | // 在使用组件时,我们提供了Vue.use()的方式,如果使用Vue.use 4 | // 就会调用本身的 install 方法,同时传一个 Vue 这个类的参数,所以一定要像下面这样写 5 | 6 | const DragModalVueComponent = { 7 | install(Vue) { 8 | Vue.component('dragModalVue', dragModalVue); 9 | }, 10 | }; 11 | 12 | export default DragModalVueComponent; 13 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path") 2 | const VueLoaderPlugin = require('vue-loader/lib/plugin') 3 | const MiniCssExtractPlugin = require('mini-css-extract-plugin') 4 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); 5 | const {CleanWebpackPlugin} = require('clean-webpack-plugin') 6 | module.exports = { 7 | mode: 'production', 8 | entry: "./src/index.js", 9 | resolve: { 10 | extensions: ['.js', '.vue'] 11 | }, 12 | externals: ['vue', 'vue-loader', 'vue-template-compiler'], 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.vue?$/, 17 | loader: 'vue-loader' 18 | }, 19 | { 20 | test: /\.js$/, 21 | exclude: /node_modules/, 22 | use: ['babel-loader', 'eslint-loader'], 23 | }, 24 | { 25 | test: /\.less$/, 26 | use: [ 27 | MiniCssExtractPlugin.loader, 28 | { 29 | loader: 'css-loader', 30 | options: { 31 | importLoaders: 2, 32 | } 33 | }, 34 | 'less-loader', 35 | 'postcss-loader' 36 | ] 37 | }, 38 | { 39 | test: /\.(jpg|png|gif)$/, 40 | use: { 41 | loader: 'url-loader', 42 | options: { 43 | name: '[name]_[hash].[ext]', 44 | outputPath: 'images/', 45 | limit: 5000 46 | } 47 | } 48 | } 49 | ] 50 | }, 51 | plugins: [ 52 | new VueLoaderPlugin(), 53 | new MiniCssExtractPlugin({ 54 | filename: '[name].css', 55 | chunkFilename: '[name].chunk.css' 56 | }), 57 | new CleanWebpackPlugin() 58 | ], 59 | optimization: { 60 | minimizer: [new OptimizeCSSAssetsPlugin({})], 61 | }, 62 | output: { 63 | path: path.resolve(__dirname, 'lib'), 64 | filename: '[name].js', 65 | libraryTarget: 'umd' 66 | } 67 | } --------------------------------------------------------------------------------