Vue 内置指令以及自定义指令

1. 内置指令

  • v-show :

    • 说明:根据条件展示元素,true展示元素,false隐藏元素
<template>
    <div>
        <button v-show="isShow"></button>
    </div>
</template>
<script>
export default {
    name: 'HomeView',
    data() {
        return {
            isShow: false
        };
    }
};
</script>

注意:v-show 不支持写在 template 元素标签上,也不支持同时写在 v-else 标签中

v-show 是采用切换css属性display:block,display:none来控制显示或隐藏dom,所以初始页面render时,此dom就会渲染至页面中,只不过是隐藏状态。

  • v-if:

    • 说明:根据条件展示元素,true在dom树中渲染元素,false从dom树中移除元素
<template>
    <div>
        <button v-if="isShow"></button>
    </div>
</template>
<script>
export default {
    name: 'HomeView',
    data() {
        return {
            isShow: false
        };
    }
};
</script>

v-if可以作用于template中,如果表达式为true,那么template标签块中的代码都会渲染,反之都不渲染

v-if也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块

  • v-else

    • 说明:表示 v-if 的“else 块”
<template>
    <div>
        <button v-if="isShow">按钮1</button>
        <button v-else>按钮2</button>
    </div>
</template>

<script>
export default {
    name: 'HomeView',
    data() {
        return {
            isShow: false
        };
    }
};
</script>

v-else元素必须紧跟在带v-if或者v-else-if的元素的后面,否则它将不会被识别

  • v-else-if

    • 说明:表示 v-if 的“else 块”
<template>
    <div>
        <button v-if="type === 'a'">按钮a</button>
        <button v-else-if="type === 'b'">按钮b</button>
        <button v-else-if="type === 'c'">按钮c</button>
        <button v-else="type === 'd'">按钮d</button>
    </div>
</template>

<script>
export default {
    name: 'HomeView',
    data() {
        return {
            type: 'a'
        };
    }
};
</script>

类似于 v-elsev-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。

  • v-bind

    • 说明:动态地绑定一个或多个 attribute,或一个组件 prop 到表达式
    • 缩写::

a. 绑定一个 attribute

<template>
    <div>
        <img v-bind:src="imgSrc" />
        <img :src="imgSrc" />
    </div>
</template>

<script>
export default {
    name: 'HomeView',
    data() {
        return {
            imgSrc: 'https://picsum.photos/200/300/?random'
        };
    }
};
</script>

b. class 绑定

<template>
    <div>
        <div :class="{ red: isRed }"></div>
        <div :class="[classA, classB]"></div>
        <div :class="[classA, { classB: isB, classC: isC }]"></div>
    </div>
</template>

<script>
export default {
    name: 'HomeView',
    data() {
        return {
            isRed: true,
            classA: 'classA',
            classB: 'classB',
            isB: true,
            isC: true
        };
    }
};
</script>

c. style 绑定

<template>
    <div>
        <div :style="{ fontSize: size + 'px' }"></div>
        <div :style="[styleObjectA, styleObjectB]"></div>
    </div>
</template>

<script>
export default {
    name: 'HomeView',
    data() {
        return {
            size: 20,
            styleObjectA: {
                color: 'red',
                fontSize: '20px'
            },
            styleObjectB: {
                color: 'blue',
                fontSize: '30px'
            }
        };
    }
};
</script>

d. 组件传值

<template>
    <div>
        <child-component :title="text" />
    </div>
</template>

<script>
export default {
    name: 'HomeView',
    components: {
        'child-component': {
            props: {
                title: String
            },
            template: '<div>{{ title }}</div>'
        }
    },
    data() {
        return {
            text: 'test'
        };
    }
};
</script>

e. 传递当前所有 props

<template>
    <div>
        <child-component v-bind="$props" />
    </div>
</template>

<script>
export default {
    name: 'HomeView',
    components: {
        'child-component': {
            props: {
                title: String
            },
            template: '<div>{{ title }}</div>'
        }
    },
    props: {
        propsValue: String
    },
    data() {
        return {
            text: 'test'
        };
    }
};
</script>
  • v-text

    • 说明:更新元素的 textContent
<template>
    <div>
        <span v-text="text"></span>
        <!-- 和下面的一样 -->
        <span>{{ text }}</span>
    </div>
</template>

<script>
export default {
    name: 'HomeView',
    data() {
        return {
            text: 'test'
        };
    }
};
</script>
  • v-html

    • 说明:更新元素的 innerHTML
    • 版本:vue2,vue3
<template>
    <div>
        <p v-html="innerHTML"></p>
    </div>
</template>

<script>
export default {
    name: 'HomeView',
    data() {
        return {
            innerHTML: '<button>click</button>'
        };
    }
};
</script>

页面展示:

  • v-for

    • 说明:遍历数据
<template>
    <div class="container">
        <ul>
            <li v-for="(item, index) in list" :key="item.name">{{ item.name }}{{ index }}</li>
        </ul>

        <ol>
            <li v-for="(item, index) of list" :key="item.version">{{ item.version }}{{ index }}</li>
        </ol>
    </div>
</template>

<script>
export default {
    name: 'HomeView',
    data() {
        return {
            list: [
                {
                    name: 'vue',
                    version: '2'
                },
                {
                    name: 'react',
                    version: '17'
                }
            ]
        };
    }
};
</script>

注意:请不要将 v-forv-if 一起使用,当和 v-if 一起使用时,v-for 的优先级比 v-if 更高,v-for 可以与 v-show 一起使用,如果需要带条件渲染,请考虑使用 computed 属性
最佳建议,在使用 v-for 时,使用 key 属性,来保证内部 diff 算法更新 dom 时最佳优化,不推荐使用 index 属性

页面展示:

  • v-model

    • 说明:在表单控件或者组件上创建双向绑定
<template>
    <div class="container">
        <p>
            <span>input-</span>
            <span>v-model:</span>
            <span>{{ inputVal }}</span>
            <input type="text" v-model="inputVal" />
        </p>
        <p>
            <span>textarea-</span>
            <span>v-model:</span>
            <span>{{ textareaVal }}</span>
            <textarea type="text" v-model="textareaVal"></textarea>
        </p>
    </div>
</template>

<script>
export default {
    name: 'HomeView',
    data() {
        return {
            inputVal: '',
            textareaVal: ''
        };
    }
};
</script>

页面展示:

2. 自定义指令

  • 注册全局指令
import Vue from 'vue';

Vue.directive('directiveName', {
    bind(el, binding, vnode, oldVnode) {},
    inserted(el, binding, vnode, oldVnode) {},
    update(el, binding, vnode, oldVnode) {},
    componentUpdated(el, binding, vnode, oldVnode) {},
    unbind(el, binding, vnode, oldVnode) {}
});
<template>
    <div class="container" v-directiveName></div>
</template>
  • 局部注册指令
<template>
    <input class="container" v-focus />
</template>

<script>
export default {
    name: 'HomeView',
    directives: {
        focus: {
            bind(el, binding, vnode, oldVnode) {},
            inserted(el, binding, vnode, oldVnode) {},
            update(el, binding, vnode, oldVnode) {},
            componentUpdated(el, binding, vnode, oldVnode) {},
            unbind(el, binding, vnode, oldVnode) {}
        }
    }
};
</script>
  • 钩子函数

    • bind : 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
    • inserted : 被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
    • update : 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有
    • componentUpdated : 指令所在组件的 VNode 及其子 VNode 全部更新后调用。
    • unbind : 只调用一次,指令与元素解绑时调用。
  • 钩子函数参数

    • el : 指令所绑定的元素,可以用来直接操作 DOM。
    • binding : 一个对象,包含以下 property
      • name : 指令名,不包括 v- 前缀。
      • value : 指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
      • oldValue : 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
      • expression : 字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
      • arg : 传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
      • modifiers : 一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
    • vnode : Vue 编译生成的虚拟节点
    • oldVnode : 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
  • 指令完整参数写法

<template>
    <input v-focus:mount.foo.bar="1 + 1" />
</template>

<script>
export default {
    name: 'HomeView',
    directives: {
        focus: {
            bind(el, binding, vnode, oldVnode) {
                console.log(binding);
            },
            inserted(el, binding, vnode, oldVnode) {},
            update(el, binding, vnode, oldVnode) {},
            componentUpdated(el, binding, vnode, oldVnode) {},
            unbind(el, binding, vnode, oldVnode) {}
        }
    }
};
// [object Object]
{
  "name": "focus",
  "rawName": "v-focus:mount.foo.bar",
  "value": 2,
  "expression": "1 + 1",
  "arg": "mount",
  "modifiers": {
    "foo": true,
    "bar": true
  },
  "def": {}
}
</script>
  • 动态参数
<template>
    <input v-focus:[dynamic].foo.bar="1 + 1" />
</template>

<script>
export default {
    name: 'HomeView',
    data() {
        return {
            dynamic: [1, 2, 3, 4, 5]
        };
    },
    directives: {
        focus: {
            bind(el, binding, vnode, oldVnode) {
                console.log(binding);
            },
            inserted(el, binding, vnode, oldVnode) {},
            update(el, binding, vnode, oldVnode) {},
            componentUpdated(el, binding, vnode, oldVnode) {},
            unbind(el, binding, vnode, oldVnode) {}
        }
    }
};
</script>
// [object Object]
{
  "name": "focus",
  "rawName": "v-focus:[dynamic].foo.bar",
  "value": 2,
  "expression": "1 + 1",
  "arg": [
    1,
    2,
    3,
    4,
    5
  ],
  "modifiers": {
    "foo": true,
    "bar": true
  },
  "def": {}
}
  • 自定义指令示例
    • v-drag
<template>
    <div class="container" v-drag></div>
</template>

<script>
export default {
    name: 'HomeView',
    data() {
        return {
            dynamic: [1, 2, 3, 4, 5]
        };
    },
    directives: {
        drag: {
            bind(el, binding, vnode, oldVnode) {
                el.onmousedown = e => {
                    const disX = e.clientX - el.offsetLeft;
                    const disY = e.clientY - el.offsetTop;
                    document.onmousemove = e => {
                        el.style.left = e.clientX - disX + 'px';
                        el.style.top = e.clientY - disY + 'px';
                    };
                    document.onmouseup = () => {
                        document.onmousemove = null;
                        document.onmouseup = null;
                    };
                };
            },
            inserted(el, binding, vnode, oldVnode) {},
            update(el, binding, vnode, oldVnode) {},
            componentUpdated(el, binding, vnode, oldVnode) {},
            unbind(el, binding, vnode, oldVnode) {}
        }
    }
};
</script>

<style scoped>
.container {
    width: 500px;
    height: 300px;
    border: 1px solid red;
    position: fixed;
    left: 0;
    top: 0;
}
.container:hover {
    cursor: pointer;
}
</style>
posted @ 2022-05-25 09:47  半糖也甜吖  阅读(346)  评论(0编辑  收藏  举报