9 | * ```
10 | */
11 | var index = {
12 | id: 'clickoutside',
13 |
14 | bind: function bind() {
15 | var _this = this;
16 |
17 | this.handler = function (e) {
18 | if (_this.vm && !_this.el.contains(e.target)) {
19 | _this.vm.$eval(_this.expression);
20 | }
21 | };
22 | document.addEventListener(this.arg || 'click', this.handler);
23 | },
24 | unbind: function unbind() {
25 | document.removeEventListener(this.arg || 'click', this.handler);
26 | },
27 | install: function install(Vue) {
28 | Vue.directive('clickoutside', {
29 | bind: this.bind,
30 | unbind: this.unbind
31 | });
32 | }
33 | };
34 |
35 | module.exports = index;
--------------------------------------------------------------------------------
/dist/clickoutside.js:
--------------------------------------------------------------------------------
1 | (function (global, factory) {
2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3 | typeof define === 'function' && define.amd ? define(factory) :
4 | (global.VueClickOutside = factory());
5 | }(this, function () { 'use strict';
6 |
7 | /**
8 | * v-clickoutside
9 | * @desc 点击元素外面才会触发的事件
10 | * @example
11 | * ```vue
12 | *
13 | * ```
14 | */
15 | var index = {
16 | id: 'clickoutside',
17 |
18 | bind: function bind() {
19 | var _this = this;
20 |
21 | this.handler = function (e) {
22 | if (_this.vm && !_this.el.contains(e.target)) {
23 | _this.vm.$eval(_this.expression);
24 | }
25 | };
26 | document.addEventListener(this.arg || 'click', this.handler);
27 | },
28 | unbind: function unbind() {
29 | document.removeEventListener(this.arg || 'click', this.handler);
30 | },
31 | install: function install(Vue) {
32 | Vue.directive('clickoutside', {
33 | bind: this.bind,
34 | unbind: this.unbind
35 | });
36 | }
37 | };
38 |
39 | return index;
40 |
41 | }));
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
DEMO
6 |
7 |
12 |
13 |
14 | 点击黑框外面会隐藏 dropdown 元素
15 |
16 |
17 |
dropdown
18 |
19 |
20 |
21 |
22 |
23 |
35 |
--------------------------------------------------------------------------------
/examples/vue2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
DEMO
6 |
7 |
12 |
13 |
14 |
点击黑框外面会隐藏 dropdown 元素
15 |
16 |
17 |
dropdown
18 |
19 | {{ show }}
20 |
21 |
22 |
23 |
24 |
25 |
47 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Fri Apr 08 2016 14:38:26 GMT+0800 (CST)
3 |
4 | module.exports = function(config) {
5 | config.set({
6 |
7 | // base path that will be used to resolve all patterns (eg. files, exclude)
8 | basePath: '',
9 |
10 |
11 | // frameworks to use
12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
13 | frameworks: ['jasmine'],
14 |
15 |
16 | // list of files / patterns to load in the browser
17 | files: [
18 | 'tests/**/*.js'
19 | ],
20 |
21 |
22 | // list of files to exclude
23 | exclude: [
24 | ],
25 |
26 |
27 | // preprocess matching files before serving them to the browser
28 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
29 | preprocessors: {
30 | 'tests/**/*.js': ['rollup']
31 | },
32 |
33 | rollupPreprocessor: {
34 | rollup: {
35 | plugins: [
36 | require('rollup-plugin-babel')({
37 | exclude: 'node_modules/**',
38 | presets: [
39 | require('babel-preset-es2015-rollup')
40 | ]
41 | }),
42 | require('rollup-plugin-node-resolve')(),
43 | require('rollup-plugin-commonjs')(),
44 | require('rollup-plugin-env')({})
45 | ]
46 | }
47 | },
48 |
49 |
50 | // test results reporter to use
51 | // possible values: 'dots', 'progress'
52 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
53 | reporters: ['progress'],
54 |
55 |
56 | // web server port
57 | port: 9876,
58 |
59 |
60 | // enable / disable colors in the output (reporters and logs)
61 | colors: true,
62 |
63 |
64 | // level of logging
65 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
66 | logLevel: config.LOG_INFO,
67 |
68 |
69 | // enable / disable watching file and executing tests whenever any file changes
70 | autoWatch: true,
71 |
72 |
73 | // start these browsers
74 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
75 | browsers: ['PhantomJS'],
76 |
77 |
78 | // Continuous Integration mode
79 | // if true, Karma captures browsers, runs the tests and exits
80 | singleRun: true,
81 |
82 | // Concurrency level
83 | // how many browser should be started simultaneous
84 | concurrency: Infinity
85 | })
86 | }
87 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-clickoutside",
3 | "version": "0.2.0",
4 | "description": "A Vue directive about listener a click outside an element.",
5 | "main": "dist/clickoutside.common.js",
6 | "files": [
7 | "src",
8 | "dist"
9 | ],
10 | "scripts": {
11 | "test": "npm run dist && karma start",
12 | "dist": "rm -rf dist && rollup -c",
13 | "publish": "npm run dist"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/element-component/vue-clickoutside.git"
18 | },
19 | "keywords": [
20 | "vue",
21 | "click",
22 | "outside",
23 | "directive"
24 | ],
25 | "author": "qingwei.li
",
26 | "license": "MIT",
27 | "bugs": {
28 | "url": "https://github.com/element-component/vue-clickoutside/issues"
29 | },
30 | "homepage": "https://github.com/element-component/vue-clickoutside#readme",
31 | "devDependencies": {
32 | "babel-preset-es2015-rollup": "^1.1.1",
33 | "karma": "^0.13.22",
34 | "karma-chrome-launcher": "^0.2.3",
35 | "karma-jasmine": "^0.3.8",
36 | "karma-phantomjs-launcher": "^1.0.0",
37 | "karma-rollup-preprocessor": "^2.0.1",
38 | "rollup": "^0.34.1",
39 | "rollup-plugin-babel": "^2.6.1",
40 | "vue": "^1.0.21"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # vue-clickoutside
2 | > make a click outside event.
3 |
4 | Similar [vue-clickaway](https://github.com/simplesmiler/vue-clickaway), but more simpler. :P
5 |
6 |
7 | # Installation
8 | ```shell
9 | npm i vue-clickoutside -D
10 | ```
11 |
12 | # Demo
13 | 
14 |
15 | # Quick Start
16 | ```javascript
17 | import Vue from 'vue'
18 | import VueClickoutside from 'vue-clickoutside'
19 |
20 | Vue.use(VueClickoutside)
21 |
22 | // or custom directive id
23 | Vue.directive('v-clickoutside', VueClickoutside)
24 | ```
25 |
26 | ```html
27 |
28 |
29 |
dropdown
30 |
31 | ```
32 |
33 | # Development
34 | If you using NPM 3.x, these will not be automatically installed.
35 |
36 | - jasmine-core *
37 | - phantomjs-prebuilt ^1.9
38 |
39 | # License
40 | [MIT](https://opensource.org/licenses/MIT)
41 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | entry: 'src/index.js',
3 | moduleName: 'VueClickOutside',
4 | plugins: [
5 | require('rollup-plugin-babel')()
6 | ],
7 | targets: [
8 | { dest: "dist/clickoutside.js", format: "umd" },
9 | { dest: "dist/clickoutside.common.js", format: "cjs" }
10 | ]
11 | };
12 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * v-clickoutside
3 | * @desc 点击元素外面才会触发的事件
4 | * @example
5 | * ```vue
6 | *
7 | * ```
8 | */
9 | export default {
10 | id: 'clickoutside',
11 |
12 | bind() {
13 | this.handler = (e) => {
14 | if (this.vm && !this.el.contains(e.target)) {
15 | this.vm.$eval(this.expression);
16 | }
17 | };
18 | document.addEventListener(this.arg || 'click', this.handler);
19 | },
20 |
21 | unbind() {
22 | document.removeEventListener(this.arg || 'click', this.handler);
23 | },
24 |
25 | install(Vue) {
26 | Vue.directive('clickoutside', {
27 | bind: this.bind,
28 | unbind: this.unbind
29 | });
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/tests/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueClickoutside from './../build/index.js'
3 |
4 | describe('check methods', () => {
5 | it('as a plugin', next => {
6 | expect(VueClickoutside.install).toBeDefined()
7 | next()
8 | })
9 |
10 | it('as a directive', next => {
11 | expect(VueClickoutside.bind).toBeDefined()
12 | expect(VueClickoutside.unbind).toBeDefined()
13 | next()
14 | })
15 | })
16 |
17 | describe('directive is work', () => {
18 | let vm
19 |
20 | afterEach(next => {
21 | vm.$destroy()
22 | next()
23 | })
24 |
25 | it('as a plugin', next => {
26 | vm = new Vue({
27 | el: 'body',
28 | replace: false,
29 | template: `outside
30 | `,
31 | directives: {
32 | 'clickoutside': VueClickoutside
33 | },
34 | methods: {
35 | handleClick() {
36 | console.log('23333')
37 | }
38 | }
39 | })
40 |
41 | spyOn(vm, 'handleClick')
42 | document.querySelector('.outside').click()
43 | document.querySelector('.button').click()
44 | expect(vm.handleClick.calls.count()).toEqual(1)
45 | next()
46 | })
47 |
48 | it('as a directive', next => {
49 | Vue.use(VueClickoutside)
50 |
51 | vm = new Vue({
52 | el: 'body',
53 | replace: false,
54 | template: `outside
55 | `,
56 | methods: {
57 | handleClick() {
58 | console.log('23333')
59 | }
60 | }
61 | })
62 |
63 | spyOn(vm, 'handleClick')
64 | document.querySelector('.outside').click()
65 | document.querySelector('.button').click()
66 | expect(vm.handleClick.calls.count()).toEqual(1)
67 | next()
68 | })
69 |
70 | it('namespaces', next => {
71 | Vue.use(VueClickoutside)
72 |
73 | vm = new Vue({
74 | el: 'body',
75 | replace: false,
76 | template: `outside1
77 |
78 | outside2
79 |
80 | outside3
81 | `,
82 | methods: {
83 | handleClick1() {
84 | console.log('23333')
85 | },
86 | handleClick2() {
87 | console.log('6666')
88 | },
89 | handleClick3() {
90 | console.log('99999')
91 | }
92 | }
93 | })
94 | spyOn(vm, 'handleClick1')
95 | spyOn(vm, 'handleClick2')
96 | spyOn(vm, 'handleClick3')
97 |
98 | document.querySelector('.outside1').click()
99 | document.querySelector('.button1').click()
100 | document.querySelector('.outside3').click()
101 | document.querySelector('.outside1').click()
102 | document.querySelector('.button2').click()
103 |
104 | expect(vm.handleClick1.calls.count()).toEqual(4)
105 | expect(vm.handleClick2.calls.count()).toEqual(4)
106 | expect(vm.handleClick3.calls.count()).toEqual(5)
107 | next()
108 | })
109 | })
110 |
--------------------------------------------------------------------------------