Vue 0基础学习路线-对比React(4)—— 图解深度详述Vue自定义指令及详述注册指令、指令使用和最为重要的指令生命周期(钩子函数)及详细案例(附详细案例代码解析过程及版本迭代过程)

1. 自定义指令重点提炼

自定义指令

  • 官网:v-focus
  • 拖拽:v-drag
  • Vue.directive()
  • 生命周期(钩子函数)
    • bind
    • update
    • componentUpdated
    • unbind
    • el
    • binding

2. Vue重要概念简述

组件:在应用开发当中能够复用的一些结构、逻辑、样式等内容、即应用(app)的组织结构。

指令:用一种特殊标签属性来对当前渲染的组件(标签)进行功能扩展,影响当前标签在渲染过程中的一些行为。指令是用在标签上面的,但用起来比较特殊,采用v-的形式作为前缀的,这样的一套属性,有着特殊的作用,vue在解析过程中,它会去影响当前指令所在的标签,影响它的结构、渲染行为、表现等。


我们还可以通过 Vue 提供的方法来自定义指令

3. 注册指令

注册组件的概念一样

vue 提供了两种指令注册方式

  • 全局指令:在应用任何位置都可以使用
  • 局部指令:注册在哪个组件,仅限该组件内部使用

4. 全局指令

Vue.directive('指令名称', {指令配置});

通过directive方法注册指令,重点在于指令配置,它实际提供了一套配置,我们为该配置传入不同的配置参数,它就可以自动生成我们想要的东西了,从而影响整个应用的一些行为。

它也有点类似组件, 这里的配置称为指令生命周期(钩子函数)

当一个指令作用于页面当中某个元素或组件的时候,在该组件渲染过程当中,解析这个组件过程当中,发现有指令,就会解析到指令上面来,接接着进入指令生命周期,执行这些钩子函数。

我们引入一个官网的例子,实现元素的焦点行为 => 在页面当中有一个input输入框,这个输入框可以通过某种简便地方式,给其设置焦点。往下看 =>

4.1 example01

实现设置焦点的例子。

4.1.1 example01-1

原生js是通过dom获取元素设置一个focus方法即可,但在vue当中尽量不要操作dom

我们使用autofocus属性(autofocus 属性规定当页面加载时input元素应该自动获得焦点。

如果使用该属性,则input 元素会获得焦点。),但是它的弊端是后期我们不能自定义控制焦点。

而我们的需求是 => 一刷新页面后,焦点不要自动在input输入框上,而是点击按钮后,焦点才会在上面。因此通过属性绑定方式,是无法实现该种需求的,因此还是需要操作dom的。

如何获取input呢?

=> 使用原生js

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <input type="text" autofocus />
    <button @click="setFocus">设置焦点</button>

</div>

<script src="./js/vue.js"></script>
<script>

    let app = new Vue({
        el: '#app',
        methods: {
            setFocus() {
                let input = document.querySelector('input');
                console.log(input);
                input.focus();
            }
        }
    });

</script>

</body>
</html>

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.57
Branch: branch02

commit description:a0.57(example01-1——原生js获取焦点)

tag:a0.57

注意:vue不是不允许操作dom,还是建议尽量不使用dom操作,能避免就避免。如果dom操作与数据有关,数据变化会影响dom结构的话,尽量用数据驱动视图变化,但是并不代表所有的东西都可以用数据来驱动,可能用数据驱动会很繁琐,所以有时也需要用dom

4.1.2 example01-2

以上用原生获取dom会比较麻烦,vue提供更为简便的方式操作dom

=> 我们使用ref来获取。

ref:vue提供的一种用于获取标签(组件)实例对象的简便方式。

vue对象下的$refs对象属性在解析过程中会把当前html模板当中的所有标有ref的元素对应的实例对象(如原生dom对象)全部存在它下面。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
<!--  ref的值随便取,其实就相当于id   -->
    <input ref="input1" type="text" autofocus />
    <button @click="setFocus">设置焦点</button>

</div>

<script src="./js/vue.js"></script>
<script>

    let app = new Vue({
        el: '#app',
        methods: {
            setFocus() {
                console.log(this.$refs)
                this.$refs.input1.focus();
            }
        }
    });

</script>

</body>
</html>

$refs该对象的key就是我们在标签中设置的ref的值。

image-20200622164209903

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.58
Branch: branch02

commit description:a0.58(example01-2——vue简便快捷方式获取焦点)

tag:a0.58

其实越偏底层,自己去写自定义组件的时候,封装一些UI组件的时候,经常会用到它。

除了这种方法,还有其他方式实现 => 自定义指令

4.2 自定义指令实例

参看指令生命周期与官网例子下的example02

5. 局部指令

new Vue({
  el: '#app',
  directives: {
    '指令名称': {指令配置}
  }
});

在使用指令的时候(指令定义的时候不需要使用 v-),需要使用 v-指令名称 的方式来调用

6. 指令生命周期(钩子函数)

和组件生命周期(钩子函数)一样的,当一个指令作用于页面当中一个元素(组件)的时候,那么在该组件渲染的过程当中,在解析这个组件(渲染的这个标签)的过程中,它会解析到这个指令(vue指令)上面来,它会执行后面传入的钩子函数。一共有5个钩子函数,bindinsertedupdatecomponentUpdatedunbind

指令的运行方式很简单,它提供了一组指令生命周期钩子函数,我们只需要在不同的生命周期钩子函数中进行逻辑处理就可以了。

在不同的生命周期,都可以接收一些参数,具体参见传入参数

6.1 bind

bind : 只调用一次(和组件初始化一样),指令第一次绑定到元素时(解析的一瞬间)调用。在这里可以进行一次性的初始化设置。

解析过程中第一次,有点类似document.createElement()。虽然创建了,但是在dom树当中是不存在的。就相当于这个组件已经被变成对象了,就相当于它被构建出来了,但是在页面dom树中是不存在的。

这个时候比如进行获取它的父节点,获取子节点的时候可能会出一些问题。

6.2 inserted

inserted : 被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中),与bind两者之间有一个很大的区别。

当前的组件被插入dom元素的时候调用,代表当前的元素已经被添加到dom树当中,比如调用appendChildinsertBefore行为,此时就可以操作dom树了。

比如进行获取它的父节点、获取子节点、获取宽高等操作。

但是是不是一定可以获取到呢?

比如宽高,那不一定,得看具体的行为,比如这个元素要是隐藏的呢!这样的话,宽高一样获取不到,但是它已经表示在dom结构当中是可以的了。

6.3 update

update : 所在组件更新的时候调用

6.4 componentUpdated

componentUpdated : 所在组件更新完成后调用

6.5 unbind

unbind : 只调用一次,指令与元素解绑时调用

6.6 传入参数

不同的生命周期钩子函数在调用的时候同时会接收到传入的一些不同的参数

  • el : 指令所绑定的元素,可以用来直接操作 DOM
  • binding : 一个对象,包含以下属性:
    • name : 指令名,不包括 v- 前缀
    • value : 指令的绑定值(作为表达式解析后的结果)
    • expression : 指令绑定的表达式(字符串)
    • arg : 传给指令的参数,可选
    • modifiers : 传给指令的修饰符组成的对象,可选,每个修饰符对应一个布尔值
    • oldValue : 指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用,无论值是否改变都可用

7. 案例

7.1 官网的例子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

    <div id="app">
        <input type="text" v-focus>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>

        Vue.directive('focus', {
            inserted(el) {
                el.focus();
            }
        });
        
        let app = new Vue({
            el: '#app'
        });
    </script>
</body>
</html>

7.2 example02

7.2.1 example02-1

我们先看看bind的使用

指令定义的时候不需要使用 v-,但是调用的时候,是需要的

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">

    <input type="text" v-focus />
    <button @click="setFocus">设置焦点</button>

</div>

<script src="./js/vue.js"></script>
<script>
    
    Vue.directive('focus', {
        bind(el, binding) {
            console.log('bind', el);
            el.focus();
        },
        inserted(el, binding) {
            console.log('inserted',el);
        }
    });

    let app = new Vue({
        el: '#app',
        methods: {
            setFocus() {

            }
        }
    });
</script>

</body>
</html>

可是感觉没有任何效果。

image-20200729105832126

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.59
Branch: branch02

commit description:a0.59(example02-1——bind中获取焦点,但没有反应)

tag:a0.59

7.2.2 example02-2

        bind(el, binding) {
            console.log('bind', el);
            // el.focus();
            el.value = 'CCCCCCCCCCCCCCCCCCC';
        },
        inserted(el, binding) {
            console.log('inserted');
        }
    });

发现有效果了。 但是focus为什么没效果呢?

因为focus有效果的前提是当前这个元素已经在dom树中存在了。

image-20200623082820786

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.60
Branch: branch02

commit description:a0.60(example02-2——bind中设置input的value却有反应。)

tag:a0.60

7.2.3 example02-3

如原生代码,不能创建一个div我们就去使用,肯定不行。除非将元素加入到dom树当中才可以。

    window.onload = function() {
        let input = document.createElement('input');
        input.focus();
        document.body.appendChild(input);
    }

image-20200623083552122

    window.onload = function() {
        let input = document.createElement('input');
        document.body.appendChild(input);
        input.focus();
    }

很明显,元素在页面当中存在的时候,focus才能生效。

image-20200623083341658

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.61
Branch: branch02

commit description:a0.61(example02-3——bind中focus生效原理,原生代码演示)

tag:a0.61

7.2.4 example02-4

有些操作是直接可以针对dom对象进行的,而有些操作必须是基于当前在dom树中存在的对象 => 如与宽、高打交道的一些操作等。

bind操作的话,是不能保证当前元素已经在dom中存在了,因为还存在解析过程和渲染过程,而inserted 操作则代表当前元素已经在dom节点当中了。

        bind(el, binding) {
            console.log('bind', el);
            // el.focus();
            // el.value = 'CCCCCCCCCCCCCCCCCCC';
        },
        inserted(el, binding) {
            console.log('inserted');
            el.focus();
        }

image-20200623084006239

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.62
Branch: branch02

commit description:a0.62(example02-4——insert中focus才能生效)

tag:a0.62

7.2.5 example02-5

然后我们想实现上来没有焦点,而是通过点击按钮的时候才有焦点=>可利用绑定值的方式来实现。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 
<div id="app">
 
    <input type="text" v-focus="isFocus" />
    <button @click="setFocus">设置焦点</button>
 
</div>
 
<script src="./js/vue.js"></script>
<script>
 
    Vue.directive('focus', {
        bind(el, binding) {
            console.log('....');
        },
        inserted(el, binding) {
            console.log(binding);
        }
    });
 
    let app = new Vue({
        el: '#app',
        data: {
            isFocus: false
        },
        methods: {
            setFocus() {
            }
        }
    });
 
</script>
 
</body>
</html>

通过binding参数可获取一个对象

value : 存储的是(v-focus="isFocus")指令的值(作为表达式解析过后的)

expression : 表达式原始内容(v-focus="isFocus"

image-20200623085617801

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.63
Branch: branch02

commit description:a0.63(example02-5——binding参数的使用)

tag:a0.63

7.2.6 example02-6

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">

    <input type="text" v-focus="isFocus" />
    <button @click="setFocus">设置焦点</button>

</div>

<script src="./js/vue.js"></script>
<script>

    Vue.directive('focus', {
        bind(el, binding) {
            console.log('....');
        },
        // {value}解构binding中的value属性
        inserted(el, {value}) {
            // value : 存储的是 指令的值(作为表达式解析过后的)
            // expression : 表达式原始内容
            // console.log(binding);
            if (value) {
                el.focus();
            }
        }
    });

    let app = new Vue({
        el: '#app',
        data: {
            isFocus: false
        },
        methods: {
            setFocus() {
            }
        }
    });

</script>

</body>
</html>

image-20200623090624377

希望当数据更新的时候,与数据关联的组件会重新渲染,在重新渲染过程中会看到v-focus,那会不会重新调用bindinserted呢?

显然是不会的。

指令和组件很相似,并不是指令重新渲染,它就重新销毁再创建的。

这个时候触发的是componentUpdated

    Vue.directive('focus', {
        bind(el, binding) {
            console.log('....');
        },
        // {value}解构binding中的value属性
        inserted(el, {value}) {
            // value : 存储的是 指令的值(作为表达式解析过后的)
            // expression : 表达式原始内容
            // console.log(binding);
            if (value) {
                el.focus();
            }
        },
        componentUpdated(el, binding) {
            console.log(binding);
        }
    });

    let app = new Vue({
        el: '#app',
        data: {
            isFocus: false
        },
        methods: {
            setFocus() {
                this.isFocus = true;
            }
        }
    });

新值value变为true,而在这里也显示原始值oldValuefalse

image-20200623091030681

以后复用,直接绑定我们自定义的v-focus指令就行了。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">

    <input type="text" v-focus="isFocus" />
    <button @click="setFocus">设置焦点</button>

</div>

<script src="./js/vue.js"></script>
<script>

    Vue.directive('focus', {
        bind(el, binding) {
            console.log('....');
        },
        // {value}解构binding中的value属性
        inserted(el, {value}) {
            // value : 存储的是 指令的值(作为表达式解析过后的)
            // expression : 表达式原始内容
            // console.log(binding);
            if (value) {
                el.focus();
            }
        },
        componentUpdated(el, {value}) {
            //     console.log(binding);
            if (value) {
                el.focus();
            }
        }
    });

    let app = new Vue({
        el: '#app',
        data: {
            isFocus: false
        },
        methods: {
            setFocus() {
                this.isFocus = true;
            }
        }
    });

</script>

</body>
</html>

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.64
Branch: branch02

commit description:a0.64(example02-6——实现指令获取焦点行为的最终版)

tag:a0.64

7.3 扩展:自定义拖拽指令

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .box {
            position: absolute;
            left: 100px;
            top: 100px;
            width: 100px;
            height: 100px;
            background: red;
        }
    </style>
</head>
<body>

    <div id="app">
        <button @click="canDrag = !canDrag">Drag : {{canDrag}}</button>
        <div class="box" v-drag.limit="canDrag"></div>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>

        Vue.directive('drag', {
            bind(el, {modifiers,value}) {
                let isDragStart = false;
                let disX = 0;
                let disY = 0;
                el.canDrag = value;
                el.addEventListener('mousedown', e => {
                    if (!el.canDrag) return;
                    disX = e.clientX - el.offsetLeft;
                    disY = e.clientY - el.offsetTop;
                    isDragStart = true;

                    e.preventDefault();
                });
                document.addEventListener('mousemove', e => {
                    if (isDragStart) {
                        let x = e.clientX - disX;
                        let y = e.clientY - disY;

                        if (modifiers.limit) {
                            if (x < 0) {
                                x = 0;
                            }
                            if (y < 0) {
                                y = 0;
                            }
                        }

                        el.style.left = x + 'px';
                        el.style.top = y + 'px';
                    }
                });
                document.addEventListener('mouseup', e => {
                    isDragStart = false;
                });
            },
            componentUpdated(el, {value}) {
                console.log('componentUpdated', value);
                el.canDrag = value;
            }
        });
        
        let app = new Vue({
            el: '#app',
            data: {
                canDrag: false
            }
        });
    </script>
</body>
</html>

7.4 example03

具体拖住原理,请参考小迪之前写的文章。

Event事件学习实用路线(10)——Event事件之拖拽原理思路详解

7.4.1 example03-1

注意:事件绑定是不需要元素在这个页面存在的,除非触发该事件,元素就必须在页面上了

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .box {
            position: absolute;
            left: 100px;
            top: 100px;
            width: 100px;
            height: 100px;
            background: red;
        }
    </style>
</head>
<body>
 
<div id="app">
 
    <div class="box" v-drag></div>
 
</div>
 
<script src="./js/vue.js"></script>
<script>
 
    Vue.directive('drag', {
        bind(el, binding) {
            // 事件绑定是不需要元素在这个页面存在的,除非触发该事件,元素就必须在页面上了
            let isDown = false; // 鼠标是否按下
            let _x = 0;
            let _y = 0;
            el.addEventListener('mousedown', function(e) {
                isDown = true;
                // 鼠标与元素差值,便于计算拖拽后的位置
                _x = e.clientX - el.offsetLeft;
                _y = e.clientY - el.offsetTop;
 
                e.stopPropagation(); // 阻止冒泡
                e.preventDefault();  // 阻止默认行为
            });
 
            el.addEventListener('mousemove', function(e) {
                if (isDown) {
 
                    el.style.left = e.clientX - _x + 'px';
                    el.style.top = e.clientY - _y + 'px';
                }
            });
 
            el.addEventListener('mouseup', function() {
                isDown = false;
            });
 
        }
    });
 
    let app = new Vue({
        el: '#app'
    });
 
</script>
 
</body>
</html>

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.65
Branch: branch02

commit description:a0.65(example03-1——初步实现自定义拖拽指令)

tag:a0.65

7.4.2 example03-2

我们进行优化,绑定数据 => 是否允许拖拽,

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .box {
            position: absolute;
            left: 100px;
            top: 100px;
            width: 100px;
            height: 100px;
            background: #e30505;
        }
    </style>
</head>
<body>
 
<div id="app">
 
    <button @click="isDrag=!isDrag">开启拖拽 - {{isDrag}}</button>
 
    <div class="box" v-drag="isDrag"></div>
 
</div>
 
<script src="./js/vue.js"></script>
<script>
    Vue.directive('drag', {
        bind(el, {value: isDrag}) {
 
            let isDown = false;
            let _x = 0;
            let _y = 0;
            el.addEventListener('mousedown', function(e) {
                console.log(isDrag)
 
                if (!isDrag) {
                    return;
                }
 
                isDown = true;
                _x = e.clientX - el.offsetLeft;
                _y = e.clientY - el.offsetTop;
 
                e.stopPropagation();
                e.preventDefault();
            });
 
            el.addEventListener('mousemove', function(e) {
                if (isDown) {
 
                    el.style.left = e.clientX - _x + 'px';
                    el.style.top = e.clientY - _y + 'px';
                }
            });
 
            el.addEventListener('mouseup', function() {
                isDown = false;
            });
 
        }
    });
 
    let app = new Vue({
        el: '#app',
        data: {
            // 是否允许拖拽
            isDrag: false
        }
    });
 
</script>
 
</body>
</html>

bind只能执行一次,而实际在函数中的isDrag是从bind取出来的,因此鼠标在元素身上按下的时候,它根据作用域链找到执行的bind函数之后,去拿isDrag,但它是初始化传进来的,永远都是false(取不到最新值)。

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.66
Branch: branch02

commit description:a0.66(example03-2——优化,绑定数据 => 是否允许拖拽,bind带来的问题)

tag:a0.66

7.4.3 example03-3

实际只要事件触发,update就会执行。

如何在update中更新bind中参数值(它俩是不同的汉化)呢?

这就和数据传参组件传递一样,原生js中最容易想到的就是利用全局变量

这样写容易造成混乱,因此我们可以将其挂载到对象下,挂载都共同的父级,这里我们选择指令所绑定的共同元素对象el

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .box {
            position: absolute;
            left: 100px;
            top: 100px;
            width: 100px;
            height: 100px;
            background: #e30505;
        }
    </style>
</head>
<body>

<div id="app">

    <button @click="isDrag=!isDrag">开启拖拽 - {{isDrag}}</button>

    <div class="box" v-drag="isDrag"></div>

</div>

<script src="./js/vue.js"></script>
<script>
    Vue.directive('drag', {
        bind(el, {value: isDrag}) {

            let isDown = false;
            el._isDrag = isDrag;
            let _x = 0;
            let _y = 0;
            el.addEventListener('mousedown', function(e) {
                // console.log('downdowndown')
                console.log(el._isDrag)

                if (!el._isDrag) {
                    return;
                }

                isDown = true;
                _x = e.clientX - el.offsetLeft;
                _y = e.clientY - el.offsetTop;

                e.stopPropagation();
                e.preventDefault();
            });

            el.addEventListener('mousemove', function(e) {
                if (isDown) {

                    el.style.left = e.clientX - _x + 'px';
                    el.style.top = e.clientY - _y + 'px';
                }
            });

            el.addEventListener('mouseup', function() {
                isDown = false;
            });

        },

        update(el, {value: isDrag}) {
            el._isDrag = isDrag;
            console.log(el._isDrag)
        }
    });

    let app = new Vue({
        el: '#app',
        data: {
            // 是否允许拖拽
            isDrag: false
        }
    });

</script>

</body>
</html>

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.67
Branch: branch02

commit description:a0.67(example03-3——优化,绑定数据 => 是否允许拖拽,解决bind带来的问题)

tag:a0.67

7.4.4 example03-4

实现限制拖拽范围:

modifiers : 传给指令的修饰符组成的对象,可选,每个修饰符对应一个布尔值

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .box {
            position: absolute;
            left: 100px;
            top: 100px;
            width: 100px;
            height: 100px;
            background: red;
        }
        .box2 {
            position: absolute;
            left: 300px;
            top: 100px;
            width: 100px;
            height: 100px;
            background: green;
        }
    </style>
</head>
<body>

<div id="app">

    <button @click="isDrag=!isDrag">开启拖拽 - {{isDrag}}</button>

    <div class="box" v-drag.limit="isDrag"></div>

    <div class="box2" v-drag="isDrag"></div>

</div>

<script src="./js/vue.js"></script>
<script>
    Vue.directive('drag', {
        bind(el, {value: isDrag, modifiers}) {
            console.log(modifiers);
            console.log(modifiers.limit);

            let isDown = false;
            el._isDrag = isDrag;
            el._isLmit = modifiers.limit;
            let _x = 0;
            let _y = 0;
            el.addEventListener('mousedown', function(e) {
                // console.log('downdowndown')
                // console.log(el._isDrag)

                if (!el._isDrag) {
                    return;
                }

                isDown = true;
                _x = e.clientX - el.offsetLeft;
                _y = e.clientY - el.offsetTop;

                e.stopPropagation();
                e.preventDefault();
            });

            el.addEventListener('mousemove', function(e) {
                if (isDown) {

                    let L = e.clientX - _x;
                    let T = e.clientY - _y;

                    if (el._isLmit) {
                        // 限制左侧
                        if (L < 0) {
                            L = 0;
                        }
                    }

                    el.style.left = L + 'px';
                    el.style.top = T + 'px';
                }
            });

            el.addEventListener('mouseup', function() {
                isDown = false;
            });

        },

        update(el, {value: isDrag}) {
            el._isDrag = isDrag;
            // console.log(el._isDrag)
        }
    });

    let app = new Vue({
        el: '#app',
        data: {
            isDrag: false
        }
    });

</script>

</body>
</html>

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.68
Branch: branch02

commit description:a0.68(example03-4——实现限制拖拽范围-modifiers的使用)

tag:a0.68

同时可以实现一个自定义右键菜单指令,如给标签加一个v-contextmenu指令,里面传一个数组 => v-contextmenu="items"

8. 小结-对比React

什么情况下去使用指令呢?

其实是期望对于某一种已存在的元素进行行为扩展的时候,不是结构扩展,结构扩展是用组件去实现的。

而在React是没有这种指令存在的,那如果在React中想实现拖拽,是怎么办到的呢?

可以使用容器组件,当然vue中也可以通过这种形式实现

<drag>
        <div class="box"></div>
</drag>


(后续待补充)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值