vue基础--模板语法、常用指令:v-if、v-show、v-for、虚拟DOM、v-once、v-cloak、v-text、v-html、v-bind、v-on、自定义指令

一、模板语法

Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。

在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。

1.1 文本

在App.vue里引入 TemplateSyntax.vue

components/TemplateSyntax.vue

<template>
  <div>
    <p>{{message}}</p>
    <p>{{version}}</p>
  </div>
</template>

<script>
export default {
  data () {
    return {
      message: 'vue',
      version: '2.x'
    }
  }
}
</script>


1.2 原始HTML

<template>
  <div>
    <p v-html="aLink"></p>
  </div>
</template>

<script>
export default {
  data () {
    return {
      aLink: '<a href="https://www.baiduu.com">百度</a>'
    }
  }
}
</script>


1.3 Attribute

只要是属性都可以通过 v-bind的形式绑定

<template>
  <div>
    <!-- v-bind可以简写为 : -->
    <p :class="classActive">高亮</p>
    <p :id="ids">id属性绑定</p>
    <p :data-id="ids1">自定义属性绑定</p>
  </div>
</template>

<script>
export default {
  data () {
    return {
      classActive: 'active',
      ids: 'box',
      ids1: 'box1'
    }
  }
}
</script>


1.4 使用JavaScript表达式

{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}


1.5 数据绑定注意事项

每个绑定都只能包含单个表达式

var a = 10;    不是(不是表达式)

10 > 5 ? 'yes' : 'no'     是

if(a>b){return  b;}     不是(不是单个表达式)


二、常用指令

1. v-if与v-show

v-show:通过 display 来控制其显示和隐藏(display:none/block;)

v-if:通过直接从DOM树删除和创建其结构来控制显示和隐藏

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好

<template>
  <div>
    <div v-if="show">hello world</div>
    <div v-show="show">by world</div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      show: true
    }
  }
}
</script>

当 show: false,

 


1.1 在<template>元素上使用

因为 v-if 是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 <template> 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 <template> 元素。

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>


1.2 key管理可复用的元素

Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address">
</template>

那么在上面的代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,<input> 不会被替换掉——仅仅是替换了它的 placeholder


1.3 v-if 和 v-else

注意点:在使用v-if和v-else时,中间不能插入其他内容

<template>
  <div>
    <div v-if="conditionOne">if</div>
    <div v-else>else</div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      conditionOne: true
    }
  }
}
</script>


1.4 v-else-if

v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。 

<template>
  <div>
    <div v-if="conditionOne">if</div>
    <div v-else-if="conditionTwo">elseif</div>
    <div v-else>else</div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      conditionOne: false,
      conditionTwo: true,
    }
  }
}
</script>

 


1.5 注意

  • 在v-if里也可以直接写表达式
  • v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别
  • 类似于 v-elsev-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后
  • v-show 不支持 <template> 元素,也不支持 v-else
  • v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建
  • v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块
  • v-show 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换
  • 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好
  • 不推荐同时使用 v-ifv-for


2. v-for

语法:

v-for="(值变量, 索引变量) in 目标结构"

v-for="值变量 in 目标结构"

目标结构:

可以遍历数组 / 对象 / 数字 / 字符串 (可遍历结构)

注意:

v-for的临时变量名不能用到v-for范围外 

谁想循环就把v-for写谁身上

 Components/VforDemo.vue

2.1 循环数组

<template>
  <div>
    <div v-for="(item,index) of listArray" :key="index">
      {{item}} -- {{index}}
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      listArray: ['dell', 'lee', 'teacher'],
    }
  }
}
</script>


2.2 循环渲染对象

<template>
  <div>
    <div v-for="(value,key,index) of listObject" :key="index">
      {{value}}--{{key}}--{{index}}
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      listObject: {
            firstName: 'dell',
            lastName: 'lee',
            job: 'teacher'
        }
    }
  }
}
</script>


2.3 变更函数(方法)

<template>
  <div>
    <div v-for="(item,index) in listArray" :key="index">
      {{item}}--{{index}}
    </div>
    <button @click="handleAddBtnClick">新增</button>
  </div>
</template>

<script>
export default {
  data () {
    return {
      listArray: ['dell', 'lee', 'teacher'],
    }
  },
  methods: {
     handleAddBtnClick() {
      //使用数组的变更函数 push pop shift unshift splice sort reverse
      this.listArray.push('hi');
    }
  }
}
</script>


2.4 直接替换数组

<template>
  <div>
    <div v-for="(item,index) in listArray" :key="index">
      {{item}}--{{index}}
    </div>
    <button @click="handleAddBtnClick">新增</button>
  </div>
</template>

<script>
export default {
  data () {
    return {
      listArray: ['dell', 'lee', 'teacher'],
    }
  },
  methods: {
     handleAddBtnClick() {
      //filter、concat、slice                    

      //直接替换数组
      this.listArray = ['by', 'world'];
      // this.listArray = ['by', 'world'].concat(['hi']);
      //过滤
      // this.listArray = ['bye', 'world'].filter(item => item === 'bye');
    }
  }
}
</script>


2.5 更新数组

 <script>
        const app = Vue.createApp({
            data() {
                return {
                    listArray: ['dell', 'lee', 'teacher'],
                }
            },
            methods: {
                handleAddBtnClick() {
                    //3.直接更新数组内容
                    this.listArray[1] = 'hello';
                }
            },
            template: `
              <div>
                <div v-for="(item,index) in listArray" :key="index">
                    {{item}}--{{index}}
                </div>
                <button @click="handleAddBtnClick">新增</button>
              </div>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';
</script>


2.6 直接添加对象的内容:

<script>
        const app = Vue.createApp({
            data() {
                return {
                    listArray: ['dell', 'lee', 'teacher'],
                    listObject: {
                        firstName: 'dell',
                        lastName: 'lee',
                        job: 'teacher'
                    }
                }
            },
            methods: {
                handleAddBtnClick() {
                    //直接添加对象的内容
                    this.listObject.age = 100;
                    this.listObject.sex = 'male';
                }
            },
            template: `
              <div>
                <div v-for="(value,key,index) in listObject" :key="index">
                    {{value}}--{{key}}
                </div>
                <button @click="handleAddBtnClick">新增</button>
              </div>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';
</script>

 点击按钮后,


2.7 循环一个数字

<script>
        const app = Vue.createApp({
            template: `
                <div v-for="item in 10">{{item}}</div>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';
</script>


2.8 示例

<script>
        const app = Vue.createApp({
            data() {
                return {
                    listArray: ['dell', 'lee', 'teacher'],
                    listObject: {
                        firstName: 'dell',
                        lastName: 'lee',
                        job: 'teacher'
                    }
                }
            },
            methods: {
                handleAddBtnClick() {
                }
            },
            template: `
              <div>
                <template 
                v-for="(value,key,index) in listObject" 
                :key="index">
                    <div v-if="key !== 'lastName'">
                        {{value}}--{{key}}
                    </div>
                </template>
                <button @click="handleAddBtnClick">新增</button>
              </div>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';
</script>


2.9 注意

v-for为了提升性能,在更新已渲染过的元素列表时,会采用“就地复用”策略,也正是因为这个策略,在某些时刻会导致我们的数据混乱

数组变更方法(即可以改变原数组的方法,例如:push/pop/shfit/unshifi/splice/sort/reverse), 就会导致v-for更新, 页面更新

数组非变更方法(即不改变原数组的方法,例如:filter/concat/slice), 返回新数组, 就不会导致v-for更新, 可采用覆盖数组或this.$set():

拿返回的新数组,直接替换旧数组

例如:在列表前面新增了内容

为了解决这个问题,我们可以在渲染列表的时候给每一个元素加上一个独一无二的key,v-for在更新已经渲染过的元素列表时,会先判断key是否相同,如果相同则复用,如果不同则重新创建

key属性注意点:

不能使用index作为key,因为当列表的内容新增或删除时,index都会发生变化,这就导致了不能很好的复用没有发生改变的元素,大大降低了渲染的效率

 <script src="js/vue.js"></script>
<div id="app">
        <form>
            <input type="text" v-model="name">
            <input type="submit" value="添加" @click.prevent="add">
        </form>
        <ul>
            <li v-for="(person,index) in persons" :key="person.id">
                <!-- <li v-for="(person,index) in persons" :key="index"> -->
                <input type="checkbox">
                <span>{{index}} --- {{person.name}}</span>
            </li>
        </ul>
    </div>
<script>
        let vue = new Vue({
            el: '#app',
            // 这里就是MVVM中的Model
            data: {
                persons: [{
                    name: "zs",
                    id: 1
                }, {
                    name: "ls",
                    id: 2
                }, {
                    name: "ww",
                    id: 3
                }],
                name: ""
            },
            // 专门用于存储监听事件回调函数
            methods: {
                add() {
                    let lastPerson = this.persons[this.persons.length - 1];
                    let newPerson = {
                        name: this.name,
                        id: lastPerson.id + 1
                    };
                    // 在尾部添加 推荐
                    this.persons.push(newPerson);

                    //在头部添加
                    // this.persons.unshift(newPerson);
                    this.name = "";
                }
            },
            // template: `
            // <p>{{time | dateFormate("yyyy-MM-dd")}}</p>
            // `
        });
    </script>

虚拟DOM:

  • 本质是保存节点信息, 属性和内容的一个JS对象

  •  真实DOM属性过多, 遍历耗时:

  •  在内存中比较变化部分, 然后给真实DOM打补丁(更新):

  •  新的虚拟DOM根元素, 或者属性变了呢? 如何更新?

同级比较-根元素变化-整个dom树删除重建

 同级比较-根元素不变-属性改变更新属性

  •  如果标签内子标签/内容改变, diff算法是如何对比的?

此时会根据有没有 key 属性来进行比较

a.如果没有 key:最大限度尝试就地修改--复用相同类型元素

 b.有key属性:基于key的来比较新旧虚拟DOM, 移除key不存在元素,先产生新旧虚拟DOM, 根据key比较, 还是就地更新

 c.有key, 值唯一不重复的字符串或数字: 基于key的来比较新旧虚拟DOM, 移除key不存在元素,先产生新旧虚拟DOM, 根据key比较,再插入/删除新的DOM(推荐)

唯一不重复的字符串或者数值

key用法:有id用id, 无id用索引

key的好处?--可以配合虚拟DOM提高更新的性能

d.虚拟DOM总结

v-for什么时候会更新页面呢?
数组采用更新方法, 才导致v-for更新页面


vue是如何提高更新性能的?
采用虚拟DOM+diff算法提高更新性能


虚拟DOM是什么?
本质是保存dom关键信息的JS对象


diff算法如何比较新旧虚拟DOM?
根元素改变 – 删除当前DOM树重新建
根元素未变, 属性改变 – 更新属性
根元素未变, 子元素/内容改变
无key – 就地更新 / 有key – 按key比较


 公共部分:

<div id="root"></div>
<script src="https://unpkg.com/vue@next"></script>


3.v-once

只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过

<script>
        //
        const app = Vue.createApp({
            data() {
                return {
                    count: 1
                }
            },
            template: `
                <div @click="count+=1" v-once>
                   {{count}}
                </div>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';
</script>

 


4.v-cloak

保持在元素上直到关联实例结束编译

和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕

 [v-cloak] {
            display: none
        }

        const app = Vue.createApp({
            data() {
                return {
                    name: '张三'
                }
            },
            template: `
                <p v-cloak>{{name}}</p>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';


5.v-text和v-thml

v-text:

  • 相当于过去学习的innerText
  • 会覆盖原来的内容
  • 不会解析HTML

v-html:

  • 相当于过去学的innerHTML
  • 会覆盖原来的内容
  • 会解析HTML

v-text 和 v-html 会覆盖插值表达式

        const app = Vue.createApp({
            data() {
                return {
                    name: '张三',
                    message: '<span>我是span</span>'
                }
            },
            template: `
                <p>{{name}}</p>
                <p>{{message}}</p>
                <p v-html="message">{{message}}</p>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';


6.v-bind

1.基本用法:

在企业开发中想要给元“元素”绑定数据,我们可以使用 {{}} ,v-text,v-html

但是要想给“元素的属性”绑定数据,就必须使用 v-bind

因此 v-bind 的作用是专门用于给“元素的属性”绑定数据的

格式:

v-bind:属性名称=“绑定的数据”  或 

:属性名称=“绑定的数据”

特点:

赋值的数据可以是任意一个合法的JS表达式即可

        const app = Vue.createApp({
            data() {
                return {
                    name: '张三',
                    message: '<span>我是span</span>'
                }
            },
            template: `
                <p>{{name}}</p>
                <p v-text="name"></p>
                <p v-html="message">{{message}}</p>
                <input type="text" v-bind:value="name">
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';

2.绑定类名

注意点:

  • 如果需要通过v-bind给class绑定类名,那么不能直接赋值,默认情况下v-model会去Model中查找数据,但是Model中没有对应的类名,所以无效,因此不能直接赋值
  • 如果想让v-bind去style中查找类名,那么就必须把类名放到数组中,并且需要利用引号将类名括起来
  • 如果是通过v-bind绑定类名,那么在绑定的时候可以编写一个三目运算符来实现按需绑定
  • 如果是通过v-bind绑定类名,那么在绑定的时候还可以通过对象来决定是否需要绑定
  • 如果是通过v-bind绑定类名,那么在绑定的时候还可以使用model中的对象来替换数组

格式:

:class="['需要绑定的类名',...]"

示例1:

    .red {
            color: red;
        }
       
<script>
        //生命周期函数:在某一时刻会自动执行的函数
        // computed 和 watch 都能实现的一个功能,建议使用 computed,因为更加简洁 
        const app = Vue.createApp({
            data() {
                return {
                    //通过字符串的方式改变数据来控制样式
                    classString: 'red'
                }
            },
            template: `
               <div :class="classString">hello world</div>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';
</script>

示例2:

        * {
            margin: 0;
            padding: 0;
        }
        
        .size {
            font-size: 20px;
        }
        
        .color {
            color: red;
        }
        
        .active {
            background: skyblue;
        }
        const app = Vue.createApp({
            data() {
                return {
                    name: '张三',
                    message: '<span>我是span</span>',
                    flag: false,
                    obj: {
                        'size': true,
                        'color': false,
                        'active': false
                    }
                }
            },
            template: `
              <p :class="['size','color','active']">我是p标签</p>
              <p :class="['size','color',flag ? 'active' : '']">我是p1标签</p>
              <p :class="['size','color',{'active' : true}]">我是p2标签</p>
              <p :class="obj">我是p3标签</p>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';

3.绑定样式

注意:

  • 和绑定类名一样,默认情况下会去model中查找,若找不到则无效果
  • 我们需要将样式代码放到对象中并赋值给style即可,但是取值必须用引号括起来
  • 如果样式的名称带横线必须用引号括起来或写成驼峰式
  • 如果model中保存了多个样式的对象,想将多个对象都绑定到一个style,那么可以将多个对象放到数组中再赋值给style

         const app = Vue.createApp({
            data() {
                return {
                    name: '张三',
                    message: '<span>我是span</span>',
                    flag: false,
                    obj1: {
                        'font-size': '30px',
                        'color': 'red',
                    },
                    obj2: {
                        'background-color': 'skyblue'
                    }
                }
            },
            template: `
              <p :style="{color: 'skyblue','font-size':'30px'}">我是p标签</p>
              <p :style="[obj1,obj2]">我是p标签</p>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';

4.其他--行内样式

<script>
        //生命周期函数:在某一时刻会自动执行的函数
        // computed 和 watch 都能实现的一个功能,建议使用 computed,因为更加简洁 
        const app = Vue.createApp({
            data() {
                return {}
            },
            template: `
               <div style="color:skyblue">
                hello world
               </div>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';
</script>

<script>
        //生命周期函数:在某一时刻会自动执行的函数
        // computed 和 watch 都能实现的一个功能,建议使用 computed,因为更加简洁 
        const app = Vue.createApp({
            data() {
                return {
                    styleString: 'color:yellow'
                }
            },
            template: `
               <div :style="styleString">
                hello world
               </div>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';
</script>

<script>
        //生命周期函数:在某一时刻会自动执行的函数
        // computed 和 watch 都能实现的一个功能,建议使用 computed,因为更加简洁 
        const app = Vue.createApp({
            data() {
                return {
                    styleObject: {
                        color: 'orange'
                    }
                }
            },
            template: `
               <div :style="styleObject">
                hello world
               </div>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';
</script>


 7.v-on

专门用于给DOM元素/标签绑定监听事件

1.基本用法

格式:

v-on:/@事件名=“要执行的少量代码"

v-on:/@事件名=“methods中的函数名"

v-on:/@事件名=“methods中的函数名(实参)"

方法在methods选项定义

v-on: 等价于 @

<template>
  <div id="app">
    <p>你要购买的商品数量为:{{count}}</p>
    <button v-on:click="count = count +1">+1</button>
    <button @click="addFn">+1</button>
    <button @click="addCouuntFn(5)">+5</button>
  </div>
</template>

<script>
export default {
  name: 'App',
  components: {
  },
  data () {
    return {
      count: 1
    }
  },
  methods: {
    addFn(){
      this.count++
    },
    addCouuntFn(num){
      this.count += num
    }
  }
}
</script>

vue事件处理函数中拿到事件对象:

语法:

无传参, 通过形参直接接收

传参, 通过$event指代事件对象传给事件处理函数

<template>
  <div id="app">
    <a @click="one" href="https://www.baidu.com/">阻止去往百度</a> <hr>
    <a @click="two(10, $event)" href="https://www.baidu.com/">阻止去往百度</a>
  </div>
</template>

<script>
export default {
  name: 'App',
  components: {
  },
  data () {
    return {
      count: 1
    }
  },
  methods: {
    one(e){
      e.preventDefault();
    },
    two(num, e){
      e.preventDefault();
    }
  }
}
</script>


2.v-on修饰符

在事件中有很多东西需要我们处理,例如事件冒泡、事件捕获、阻止默认行为等

那么在Vue中我们可以通过v-on修饰符来处理

常见修饰符:

  • .once:程序运行期间, 只触发一次事件处理函数
  • .prevent:等价于调用 event.preventDefault(),阻止默认行为
  • .self:只当事件是从侦听器绑定的元素本身触发时才触发回调
  • .stop:等价于调用 event.stopProopagation(),阻止当前事件冒泡
  • .capture:添加事件侦听器时使用 capture 模式
  • ......
  • 例如:v-on:click.stop="xxx"   v-on:click.prevent.stop

注意:

  1. 默认情况下事件回调函数可以反复执行,只要事件被触发就会执行
  2. 如果想让事件监听的函数执行一次,那么可以使用.once修饰符
  3. 如果想阻止元素的默认行为,那么可以使用.prevent修饰符
  4. 默认情况下在嵌套的元素中,如果都监听了相同的事件,那么会触发事件冒泡,此时可以使用.stop修饰符阻止冒泡
  5. 如果想让回调只有当前元素触发事件时才执行,那么可以使用.self修饰符
  6. 默认情况下是事件冒泡,若想实现事件捕获,那么可以使用.capture修饰符
  7. 在绑定回调函数名称时,后面可以写()也可以不写
  8. 可以给绑定的回调函数传递参数
  9. 如果在绑定的函数中需要用到data中的数据,必须加上this

        * {
            margin: 0;
            padding: 0;
        }
        
        .a {
            width: 100px;
            height: 100px;
            background: red;
        }
        
        .b {
            width: 80px;
            height: 80px;
            background: skyblue;
        }
        const app = Vue.createApp({
            data() {
                return {
                    gender: 'male'
                }
            },
            methods: {
                myFn(name, age, e) {
                    // alert('myfn');
                    console.log('myfn');
                    console.log(name, age, e, this.gender);
                },
                myFn1() {
                    console.log("父亲");
                },
                myFn2() {
                    console.log("儿子");
                },
            },
            template: `
              <button v-on:click.once="myFn('zhangsan',21,$event)">我是按钮</button>
              <a href="http://www.baidu.com" v-on:click.prevent="myFn">我是a标签</a>
              <div class="a" v-on:click="myFn1">我是a
                <div class="b" v-on:click.stop="myFn2">我是b</div>
              </div>
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';

3.v-on按键修饰符

a.系统修饰符:

为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:

  • .enter
  • .tab
  • .delete (捕获“删除”和“退格”键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
  • middle
  • .ctrl
  • .alt
  • .shift
  • .meta 在 Mac 系统键盘上,meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)
  • .exact  允许你控制由精确的系统修饰符组合触发的事件
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button v-on:click.ctrl="onClick">A</button>

<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button v-on:click.ctrl.exact="onCtrlClick">A</button>

<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button v-on:click.exact="onClick">A</button>

示例:

        const app = Vue.createApp({
            data() {
                return {

                }
            },
            methods: {
                myFn() {
                    console.log('lng');
                }
            },
            // v-on: == @
            template: `
             <input type="text" @keyup.enter="myFn" />
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';

b.按键修饰符:

        Vue.config.keyCodes = {
            v: 86,
            f1: 112,
            // camelCase 不可用
            mediaPlayPause: 179,
            // 取而代之的是 kebab-case 且用双引号括起来
            "media-play-pause": 179,
            up: [38, 87]
        }

        const app = Vue.createApp({
            data() {
                return {

                }
            },
            methods: {
                myFn() {
                    console.log('lng');
                }
            },
            // v-on: == @
            template: `
             <input type="text" @keyup.v="myFn" />
            `
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';


三、自定义指令

注意:

在自定义指令的时候,在指定指令名称时,不需要写v-

指令可以在不同生命周期阶段执行 bind(指令被绑定到元素上的时候执行)、inserted(绑定指令的元素被添加到父元素上时执行)...

 i.全局自定义指令

<script>
    //自定义指令 directive 
    const app = Vue.createApp({
        template: `
      <div>
        <input v-focus />
      </div>
    `
    });

    //全局自定义指令
    app.directive('focus', {
        mounted(el) {
            el.focus();
        }
    });

    const vm = app.mount('#root');
</script>

或,

为了便于使用,我们可以在项目根目录 src 下新建一个 directives 文件夹,在文件夹里新建一个  index.js文件,将全局指令相关的代码写入该文件,再在 main.js 里通过 import 的方式引入即可 

App.vue

<template>
  <div id="app">
    <MyDirective />
  </div>
</template>

<script>
import MyDirective from "./components/MyDirective.vue"

export default {
  name: 'App',
  components: {
    MyDirective
  },
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

main.js

import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import "./dircectives/index"

Vue.config.productionTip = false

new Vue({
    render: h => h(App),
}).$mount('#app')

MyDirective.vue

<template>
  <div>
      <input type="text" v-focus>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>

src/directives/index.js

import Vue from "vue"

//全局指令
Vue.directive('focus', {
    //指令钩子函数 当被绑定的元素插入到 DOM 中时……
    inserted: function(el) {
        // 聚焦元素
        el.focus()
    }
})


//高亮显示
//Vue.directive('red', {
//     inserted: function(el) {
//         el.style.color = "#ff0000";
//     }
// })


ii.自定义指令参数

         //自定义指令 directive 
        const app = Vue.createApp({
            data() {
                return {
                    curColor: 'green'
                }
            },
            template: `
            <div>
                <p v-color="'blue'">我是段落</p>
                <p v-color="curColor">我是段落1</p>
            </div>
            `
        });

        //全局自定义指令
        app.directive('color', {
            mounted(el, obj) {
                // el.style.color = "red";
                el.style.color = obj.value;
            }
        });

        //将组件挂到root节点里,即只作用在id等于root的div元素里
        //vm 代表的就是 vue 应用的根组件
        const vm = app.mount('#root');

        //vm.$data 获得数据
        // vm.$data.message = 'root';


iii.局部自定义指令

<script>
    //局部自定义指令
    const directives = {
        focus: {
            mounted(el) {
                el.focus();
            }
        }
    };

    const app = Vue.createApp({
        directives: directives,
        template: `
      <div>
        <input v-focus />
      </div>
    `
    });

    const vm = app.mount('#root');
</script>


iv.其他

<script>
    //自定义指令 directive 

    const app = Vue.createApp({
        data() {
            return {
                hello: true
            }
        },
        template: `
      <div>
        <div v-if='hello'>
            <input v-focus />
        </div>
      </div>
    `
    });

    //全局自定义指令
    app.directive('focus', {
        //当元素即将挂在到页面还没挂载时
        beforeMount() {
            console.log('beforeMount');
        },
        mounted(el) {
            console.log('mounted');
            el.focus();
        },
        //当元素从新去更新渲染,还未渲染之前
        beforeUpdate() {
            console.log('beforeUpdate');
        },
        //当元素从新去更新渲染后
        updated() {
            console.log('updated');
        },
        //即将被销毁时执行
        beforeUnmount() {
            console.log('beforeUnmount');
        },
        //销毁时执行
        unmounted() {
            console.log('unmounted');
        }
    });

    const vm = app.mount('#root');
</script>

 

 .header {
            position: absolute;
        }
<script>
    const app = Vue.createApp({
        data() {
            return {
                top: 100
            }
        },
        // <div v-pos='50' class="header">
        template: `
      <div>
        <div v-pos="top" class="header">
            <input />
        </div>
      </div>
    `
    });

    //全局自定义指令
    app.directive('pos', {
        //挂载结束后调用
        mounted(el, binding) {
            el.style.top = binding.value + 'px';
        },
        updated(el, binding) {
            el.style.top = binding.value + 'px';
        }
    });
    //当 mounted 和 updated 所包含的内容一样时,可以作如下简写:
    // app.directive('pos', (el, binding) => {
    //     el.style.top = (binding.value + 'px');
    // });

    const vm = app.mount('#root');
</script>

 .header {
            position: absolute;
        }
<script>
    const app = Vue.createApp({
        data() {
            return {
                distance: 100
            }
        },
        // <div v-pos='50' class="header">
        template: `
      <div>
        <div v-pos:left="distance" class="header">
            <input />
        </div>
      </div>
    `
    });

    //全局自定义指令
    app.directive('pos', {
        //挂载结束后调用
        mounted(el, binding) {
            //binding.arg 获取参数,binding.value获取参数值
            el.style[binding.arg] = binding.value + 'px';
        },
        updated(el, binding) {
            el.style[binding.arg] = binding.value + 'px';
        }
    });
    //当 mounted 和 updated 所包含的内容一样时,可以作如下简写:
    // app.directive('pos', (el, binding) => {
    //     el.style.top = (binding.value + 'px');
    // });

    const vm = app.mount('#root');
</script>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白小白从不日白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值