【Vue】模板语法,事件处理器及综合案例、自定义组件、组件通信

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
可观测可视化 Grafana 版,10个用户账号 1个月
简介: 组件(Component)是Vue最强大的功能之一组件可以扩展HTML元素,封装可重用的代码组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树。

 一、事件处理器

我们之前事件监听可以使用v-on 指令

1、事件修饰符

Vue中我们通过由点(.)表示的指令后缀来调用修饰符,比如:

    1. .stop:阻止事件冒泡。当事件触发时,该修饰符将停止事件进一步冒泡到父元素。相当于调用了 event.stopPropagation()
    2.  .prevent:阻止默认事件。默认情况下,某些元素会有默认的事件行为,比如<a>标签的点击跳转,使用.prevent可以阻止默认事件的触发。相当于调用了 event.preventDefault()
    3.  .capture:使用事件捕获模式。默认情况下,事件是在冒泡阶段处理的(即从子元素到父元素)。使用.capture 修饰符将事件处理移到事件捕获阶段(即从父元素到子元素)。
    4.  .self:只触发当前元素本身的事件。当事件绑定在子元素上时,该修饰符只允许事件在子元素上触发,而不会触发父元素上相同事件。
    5.  .once::只触发一次事件。使用 .once修饰符可以确保事件只被触发一次,之后该事件监听器会自动被移除。
    <!-- 阻止单击事件冒泡 -->
      <a v-on:click.stop="doThis"></a>
      <!-- 提交事件不再重载页面 -->
      <form v-on:submit.prevent="onSubmit"></form>
      <!-- 修饰符可以串联  -->
      <a v-on:click.stop.prevent="doThat"></a>
      <!-- 只有修饰符 -->
      <form v-on:submit.prevent></form>
      <!-- 添加事件侦听器时使用事件捕获模式 -->
      <div v-on:click.capture="doThis">...</div>
      <!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
      <div v-on:click.self="doThat">...</div>
      <!-- click 事件只能点击一次 -->
      <a v-on:click.once="doThis"></a>

    image.gif

    2、冒泡案例(.stop)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>事件处理器</title>
        <!--  jQuery-->
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
        <!--  vue.js-->
        <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.js"></script>
    </head>
    <style>
        .red {
            width: 400px;
            height: 400px;
            background-color: red;
        }
        .orange {
            width: 300px;
            height: 300px;
            background-color: orange;
        }
        .blue {
            width: 200px;
            height: 200px;
            background-color: blue;
        }
        .black {
            width: 500px;
            height: 500px;
            background-color: black;
        }
    </style>
    <body>
    <!-- 定义边界 -->
    <div id="app">
        <p>冒泡事件</p>
        <div class="black" @click="black">
            <div class="red" @click="red">
                <div class="orange" @click="orange">
                    <div class="blue" @click="blue">
                    </div>
                </div>
            </div>
        </div>
    </div>
    </body>
    <script type="text/javascript">
        // 绑定边界 ES6具体体现
        new Vue({
            el: '#app',
            data() {
                return {
                    f200: 'f200'
                };
            },
            methods: {
                red() {
                    alert("red(红色)");
                },
                orange() {
                    alert("orange(橙色)");
                },
                blue() {
                    alert("blue(蓝色)");
                },
                black() {
                    alert("black(黑色)");
                }
            }
        })
    </script>
    </html>

    image.gif

    image.gif编辑

    当我们加上了.stop修饰符

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>事件处理器</title>
        <!--  jQuery-->
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
        <!--  vue.js-->
        <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.js"></script>
    </head>
    <style>
        .red {
            width: 400px;
            height: 400px;
            background-color: red;
        }
        .orange {
            width: 300px;
            height: 300px;
            background-color: orange;
        }
        .blue {
            width: 200px;
            height: 200px;
            background-color: blue;
        }
        .black {
            width: 500px;
            height: 500px;
            background-color: black;
        }
    </style>
    <body>
    <!-- 定义边界 -->
    <div id="app">
        <p>冒泡事件</p>
        <div class="black" @click.stop="black">
            <div class="red" @click.stop="red">
                <div class="orange" @click.stop="orange">
                    <div class="blue" @click.stop="blue">
                    </div>
                </div>
            </div>
        </div>
    </div>
    </body>
    <script type="text/javascript">
        // 绑定边界 ES6具体体现
        new Vue({
            el: '#app',
            data() {
                return {
                    f200: 'f200'
                };
            },
            methods: {
                red() {
                    alert("red(红色)");
                },
                orange() {
                    alert("orange(橙色)");
                },
                blue() {
                    alert("blue(蓝色)");
                },
                black() {
                    alert("black(黑色)");
                }
            }
        })
    </script>
    </html>

    image.gif

    image.gif编辑

    3、触发案例(.once)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>事件处理器</title>
        <!--  jQuery-->
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
        <!--  vue.js-->
        <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.js"></script>
    </head>
    <body>
    <!-- 定义边界 -->
    <div id="app">
        <p>点击</p>
        <input :value="msg"/>
        <button @click="dosub">提交</button>
    </div>
    </body>
    <script type="text/javascript">
        // 绑定边界 ES6具体体现
        new Vue({
            el: '#app',
            data() {
                return {
                    msg: '偶买噶'
                };
            },
            methods: {
                dosub() {
                    alert(this.msg);
                }
            }
        })
    </script>
    </html>

    image.gif

    image.gif编辑

    添加.once之后只能点击一次

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>事件处理器</title>
        <!--  jQuery-->
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
        <!--  vue.js-->
        <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.js"></script>
    </head>
    <body>
    <!-- 定义边界 -->
    <div id="app">
        <p>点击</p>
        <input :value="msg"/>
        <button @click.once="dosub">提交</button>
    </div>
    </body>
    <script type="text/javascript">
        // 绑定边界 ES6具体体现
        new Vue({
            el: '#app',
            data() {
                return {
                    msg: '偶买噶'
                };
            },
            methods: {
                dosub() {
                    alert(this.msg);
                }
            }
        })
    </script>
    </html>

    image.gif

    image.gif编辑

    4、综合案例(表单)

    需要注意的是复选框v-model="hobbyMax"中的hobbyMax使用数组来接收

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>表单</title>
        <!--  jQuery-->
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
        <!--  vue.js-->
        <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.js"></script>
    </head>
    <body>
    <div id="app">
        <label>姓名:</label><input v-model="username"/><br/>
        <label>密码:</label><input v-model="pwd" type="password"/><br/>
        <!-- 将用户的输入值转为 Number 类型 -->
        <label>年龄:</label><input v-model.number="age" type="number"/><br/>
        <label>性别:</label>
        <div v-for="s in sexMax">
            <input type="radio" v-model="sex" name="sex" v-bind:value="s.id"/>{{s.name}}<br/>
        </div>
        <label>爱好:</label>
        <div v-for="h in hobby">
            <input type="checkbox" v-model="hobbyMax" v-bind:value="h.id"/>{{h.name}}
        </div>
        <label>类别:</label>
        <select v-model="type">
            <option v-for="t in types" v-bind:value="t.id">{{t.name}}</option>
        </select><br/>
        <label>备注:</label>
        <!--    v-bind:value="info"-->
        <textarea v-model="info"></textarea><br/>
        确认<input type="checkbox" v-model="flag"/>
        <input type="submit" v-bind:disabled="show" v-on:click="doSubmit"/>
    </div>
    </body>
    <script type="text/javascript">
        new Vue({
            el: '#app',
            data() {
                return {
                    username: null,
                    pwd: null,
                    age: 10,
                    sex: 1,
                    sexMax: [{id: 1, name: "男"}, {id: 2, name: "女"}, {id: 3, name: "其他"}],
                    hobby: [
                        {
                            id: 1,
                            name: '篮球'
                        },
                        {
                            id: 2,
                            name: '唱'
                        },
                        {
                            id: 3,
                            name: '跳'
                        },
                        {
                            id: 4,
                            name: 'rap'
                        }],
                    hobbyMax: [],
                    types: [
                        {
                            id: 1,
                            name: '职业人'
                        },
                        {
                            id: 2,
                            name: '学生'
                        },
                        {
                            id: 3,
                            name: '社会人'
                        }],
                    type: null,
                    info: '请输入你的个性签名',
                    flag: false
                }
            },
            computed: {
                show: function () {
                    return !this.flag;
                }
            },
            methods: {
                doSubmit: function () {
                    var obj = {
                        username: this.username,
                        pwd: this.pwd,
                        age: this.age,
                        sex: this.sex,
                        hobbyMax: this.hobbyMax,
                        type: this.type,
                        info: this.info,
                    }
                    console.log(obj);
                }
            }
        })
    </script>
    </html>

    image.gif

    效果演示

    image.gif编辑

    二、自定义组件

    1、 vue组件

    1.1、组件简介

         组件(Component)是Vue最强大的功能之一

         组件可以扩展HTML元素,封装可重用的代码

         组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树

     1.2、 全局和局部组件

      • 全局组件Vue.component(tagName, options),tagName为组件名,options为配置选项。
      • 局部组件: new Vue({el:'#d1',components:{...}})

           注册后,我们可以使用以下方式来调用组件:

      <tagName></tagName>
      image.gif

       1.3 props

           props是父组件用来传递数据的一个自定义属性。

      父组件的数据需要通过props把数据传给子组件,子组件需要显式地用props选项声明 "prop"

        1:因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods

             以及生命周期钩子等。仅有的例外是像el这样根实例特有的选项。

        2:当我们定义这个 <button-counter> 组件时,你可能会发现它的data并不是像这样直接提供一个对象

       

      data: {
                count: 0
              }
      image.gif

             取而代之的是,一个组件的data选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:

      data: function () {
                return {
                  count: 0
                }
              }
      image.gif

         3:定义组件名的方式有两种

             短横线分隔命名(建议使用)

      Vue.component('my-component-name', { /* ... */ }),
      引用方式:<my-component-name>

      image.gif

             首字母大写命名

           

      Vue.component('MyComponentName', {  ...  }),
          引用方式: <my-component-name>和<MyComponentName>都是可接受的

      image.gif

         4:HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,

              camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:

           

      props: ['postTitle'],<my-tag post-title="hello!"></my-tag>

      image.gif

         5:props: ['title', 'likes', 'isPublished', 'commentIds', 'author']

              希望每个 prop 都有指定的值类型  

      props: {
                 title: String,
                 likes: Number,
                 isPublished: Boolean,
                 commentIds: Array,
                 author: Object,
                 callback: Function,
                 contactsPromise: Promise // or any other constructor
               }

      image.gif

      2、案例

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>组件</title>
          <!--  jQuery-->
          <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
          <!--  vue.js-->
          <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.js"></script>
      </head>
      <body>
      <!-- 定义边界 -->
      <div id="app">
          <!-- 定义组件不能用驼峰命名 -->
          <!-- 需求是:当引用一个myButton,也页面上一个独特标记按钮 -->
          <my-img></my-img>
          <my-button m="卡拉米"></my-button>
          <!-- <button onclick=""></button> -->
      </div>
      </body>
      <script type="text/javascript">
          Vue.component('my-button', {
              // props是定义组件中的变量的
              props: ['m'],
              // template代表了自定义组件在页面上显示的类容
              template: '<button v-on:click="incrn">我被{{m}}点击{{n}}次</button>',
              data: function () {
                  return {
                      n: 1
                  }
              },
              methods: {
                  incrn() {
                      this.n++;
                  }
              }
          });
          Vue.component('my-img', {
              // template代表了自定义组件在页面上显示的类容
              template: '<img style="width: 100px;height: 100px;" src="https://ts1.cn.mm.bing.net/th/id/R-C.b0ea268fa1be279d112489ce83ad4696?rik=qItsh%2fBiy33hlg&riu=http%3a%2f%2fwww.quazero.com%2fuploads%2fallimg%2f140303%2f1-140303215009.jpg&ehk=S6PLWamt%2bMzQV8uO9ugcU5d5M19BpXtCpNz2cRJ7q9M%3d&risl=&pid=ImgRaw&r=0">',
          });
          // 绑定边界 ES6具体体现
          new Vue({
              el: '#app',
              data() {
                  return {};
              }
          })
      </script>
      </html>

      image.gif

      image.gif编辑

      三、组件通信

      1. 自定义事件

        1.   监听事件$on(eventName)
        2.  触发事件$emit(eventName)

          1.1、Vue自定义事件是为组件间通信设计  

               vue中父组件通过prop传递数据给子组件,而想要将子组件的数据传递给父组件,则可以通过自定义事件的绑定

          1.        父Vue->子Vue,通过prop传递数据
          2.        子Vue->父Vue,通过事件传递数据

            1.2、事件名

                 不同于组件和prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。

                 建议使用“短横线分隔命名”

          2、案例

          2.1、父传子

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>通信</title>
              <!--  vue.js-->
              <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.js"></script>
          </head>
          <body>
          <div id="app">
              <h3>父传子1</h3>
              <my-button m="牛马"></my-button>
              <h3>父传子2</h3>
              <my-button m="小卡拉米" n="2"></my-button>
          </div>
          </body>
          <script>
              // 定义全局组件的方式
              Vue.component('my-button', {
                  props: ['m', 'n'],
                  template: '<button v-on:click="MyButton">{{m}}被点了{{n}}次</button>',
                  data: function () {
                      return {
                          n: 1
                      };
                  },
                  methods: {
                      MyButton: function () {
                          this.n++;
                      }
                  }
              })
              var vm = new Vue({
                  el: "#app",
                  data: {
                      msg: "999"
                  }
              });
          </script>
          </html>

          image.gif

          image.gif编辑

          2.2、子传父

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>通信</title>
              <!--  vue.js-->
              <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.js"></script>
          </head>
          <body>
          <div id="app2">
              <h3>子传父</h3>
              <!-- 使用自定义组件my-button的时候进行传值(相当于jsp标签往助手类中传值的概念) -->
              <my-buttons m="666" @getBut="getXx"></my-buttons>
          </div>
          </body>
          <script>
              // 定义全局组件的方式
              Vue.component('my-buttons', {
                  props: ['m'],
                  template: '<button v-on:click="MyButton">{{m}}被点了</button>',
                  methods: {
                      MyButton: function () {
                          let id = 123;
                          let name = "天才";
                          this.$emit('getbut', id, name);
                      }
                  }
              })
              var vm = new Vue({
                  el: "#app2",
                  data: {
                      msg: "666"
                  },
                  methods: {
                      getXx: function (a, b) {
                          console.log(a);
                          console.log(b);
                      }
                  }
              });
          </script>
          </html>

          image.gif

          image.gif编辑


          相关文章
          |
          12天前
          |
          JavaScript 数据库
          ant design vue日期组件怎么清空 取消默认当天日期
          ant design vue日期组件怎么清空 取消默认当天日期
          |
          12天前
          |
          JavaScript C++
          vue高亮显示组件--转载
          vue高亮显示组件--转载
          22 0
          |
          5天前
          |
          JavaScript API
          Vue3 基础语法
          该内容介绍了Vue项目的创建和Vue3的语法、响应式API、生命周期、组件通信及跨组件通信方法。包括使用`npm init vue@latest`创建项目,`npm install`初始化,Vue3的`setup`语法,`reactive`、`ref`、`computed`和`watch`的用法,生命周期图解,以及父子组件间的数据传递。此外,还提到了Vue3中使用`provide`和`inject`进行跨层数据传递,以及通过Pinia库进行状态管理。
          28 0
          Vue3 基础语法
          |
          12天前
          |
          JavaScript 前端开发 UED
          Vue class和style绑定:动态美化你的组件
          Vue class和style绑定:动态美化你的组件
          |
          12天前
          |
          JavaScript
          vue封装面包屑组件
          vue封装面包屑组件
          19 0
          |
          12天前
          |
          缓存 监控 JavaScript
          探讨优化Vue应用性能和加载速度的策略
          【5月更文挑战第17天】本文探讨了优化Vue应用性能和加载速度的策略:1) 精简代码和组件拆分以减少冗余;2) 使用计算属性和侦听器、懒加载、预加载和预获取优化路由;3) 数据懒加载和防抖节流处理高频事件;4) 图片压缩和选择合适格式,使用CDN加速资源加载;5) 利用浏览器缓存和组件缓存提高效率;6) 使用Vue Devtools和性能分析工具监控及调试。通过这些方法,可提升用户在复杂应用中的体验。
          32 0
          |
          2天前
          |
          JavaScript 前端开发 C++
          【Vue】Vue快速入门、Vue常用指令、Vue的生命周期
          【Vue】Vue快速入门、Vue常用指令、Vue的生命周期
          12 2
          |
          4天前
          |
          存储 缓存 JavaScript
          谈谈你对vue的了解
          谈谈你对vue的了解
          14 3
          |
          4天前
          |
          JavaScript API
          Vue axjx 跨域请求
          Vue应用中解决跨域问题可通过配置代理服务器。方法一是设置`devServer.proxy`到目标服务器端口,如`http://localhost:3000`,然后使用axios发送请求。方法二是为多个代理配置,如`/api`和`/api2`,分别指向不同端口,利用`pathRewrite`重写路径。请求时需加上相应前缀,如`/api/index`。
          13 1
          |
          4天前
          |
          JavaScript 前端开发 Java
          JavaSE精选-Vue
          JavaSE精选-Vue
          7 1