精华内容
下载资源
问答
  • HTMLAnchorElement:接口表示超链接元素,并提供一些特别的属性和方法(除了那些继承自普通 HTMLElement对象接口的之外)以用于操作这些元素的布局和显示。 这时HTMLAnchorElement 找不到定义的点击事件 需要初始化的...

    如果直接添加调用的话会报 xxxis not defined at HTMLAnchorElement.onclick

    HTMLAnchorElement:接口表示超链接元素,并提供一些特别的属性和方法(除了那些继承自普通 HTMLElement对象接口的之外)以用于操作这些元素的布局和显示。
    这时HTMLAnchorElement 找不到定义的点击事件 需要初始化的时候加在 window里面

      marker.content =  lnglats[i].name+""+lnglats[i].tel +" "+  (lnglats[i].address==null?" ":lnglats[i].address);

    <template>
      <div class="mapmain">
        <van-row>
          <van-col span="12">
            <button
              v-bind:class="[isActive ? 'myorder_active' : 'disActive']"
              @click="xq"
            >
              分公司
            </button>
          </van-col>
          <van-col span="12">
            <button
              v-bind:class="[lsActive ? 'myorder_active' : 'disActive']"
              @click="ly"
            >
              分理处
            </button>
          </van-col>
        </van-row>
    
        <!-- <div id="pickerBox">
          <input id="pickerInput" placeholder="请输入关键字选取地点" />
          <div id="poiInfo"></div>
        </div> -->
        <div id="container">
          <!-- <div id="centerCoord"></div> -->
        </div>
      </div>
    </template>
    <script>
    import {
      queryCityBranch, //分理处
      queryAreaBr, //分公司
    } from "@/api/getData";
    import AMap from "AMap"; //在页面中引入高德地图
    import AMapUI from "AMapUI";
    import { Toast } from "vant";
    export default {
      name: "mapmain",
      data() {
        return {
          city: "郑州",
          map: "",
          infoWindow: "",
          isActive: false,
          lsActive: true,
          thisPosition: {
            address: "",
            lng: "",
            lat: "",
            city: "",
            citycode: "",
          },
          flc: [],
        };
      },
      methods: {
        //
        xq() {
          this.flc.length = 0;
          this.isActive = false;
          this.lsActive = true;
          this.getqueryAreaBr();
        },
        ly() {
          this.flc.length = 0;
          this.isActive = true;
          this.lsActive = false;
          this.getqueryCityBranch();
          this.loadmap()
        },
        loadmap() {
          let that = this;
          // 分公司
          if (!this.isActive) {
            // alert(222)
            that.map = new AMap.Map("container",{resizeEnable: true});
          }
          //  分理处
          if (!this.lsActive) {
            that.map = new AMap.Map("container",{resizeEnable: true});
          }
          // that.map.clearMap(); // 清除地图覆盖物
          //构建点坐标  设置点标记的文本标签
          var lnglats = this.flc;
          // console.log(lnglats)
          // 添加一些分布不均的点到地图上,地图上添加三个点标记,作为参照
           var infoWindow = new AMap.InfoWindow({offset: new AMap.Pixel(0, -10)});
          for (var i = 0, marker; i < lnglats.length; i++) {
            let markers =Array.from([lnglats[i].lng,lnglats[i].lat])
            var marker = new AMap.Marker({
                position: markers,
                map: that.map
            });
            // let tel=lnglats[i].tel;
            marker.content =  lnglats[i].name+"<a id='cell' onclick='Phone(window)' style='color: #1d9beb;'>"+lnglats[i].tel +" </a>"+  (lnglats[i].address==null?" ":lnglats[i].address);
            marker.on('click', markerClick);
            marker.emit('click', {target: marker});
        }
         
        //  点击事件
        function markerClick(e) {
            infoWindow.setContent(e.target.content);
            infoWindow.open(that.map, e.target.getPosition());
           
        }
      
    
        that.map.setFitView();
        },
        // 点击弹出信息
       
      Phone (){
        let val =document.getElementById('cell').innerText;
        window.location.href = 'tel:'+val;
        // console.log(val,"222222")
       },
       
        // 分理处数据加载
        getqueryCityBranch() {
          queryCityBranch().then((res) => {
            // console.log(res.data, "分理处");
            if (res.data.success) {
              let arr = res.data.data;
              let arr2 = [],
                obj = {};
              for (let i = 0; i < arr.length; i++) {
                if (arr[i].lat && arr[i].lng) {
                  if (
                    arr[i].lat <= 90 &&
                    arr[i].lat >= 0 &&
                    arr[i].lng <= 180 &&
                    arr[i].lng >= 0
                  ) {
                    // obj.position = [arr[i].lng, arr[i].lat];
                    this.flc.push(
                      arr[i]
                    );
                  }
                  // console.log(obj)
                  // this.flc.push(obj);
                }
              }
              // console.log(this.flc, "flc分理处");
              this.loadmap(); //加载地图和相关组件
            }
          });
        },
        getqueryAreaBr() {
          queryAreaBr().then((res) => {
            // console.log(res.data, "分公司");
            if (res.data.success) {
              let arr = res.data.data;
              let arr2 = [],
                obj = {};
              for (let i = 0; i < arr.length; i++) {
                if (arr[i].lat && arr[i].lng) {
                  if (
                    arr[i].lat <= 90 &&
                    arr[i].lat >= 0 &&
                    arr[i].lng <= 180 &&
                    arr[i].lng >= 0
                  ) {
                    this.flc.push(
                     arr[i]
                    );
                  }
                }
              }
              // console.log(this.flc, "分公司flc");
              this.loadmap(); //加载地图和相关组件
            }
          });
        },
        //  分公司加载
      },
    
      created() {},
      mounted() {
        this.getqueryAreaBr();
        let _this = this;
        // console.log(this)
        // window.Close = _this.Close;
        window.Phone=_this.Phone;
        // _this.Phone();
        console.log(window)
      },
    };
    </script>
    <style  lang="less" scoped >
    html,
    body,
    .mapmain {
      width: 100%;
      height: 100%;
    }
    #container {
      width: 100%;
      height: calc(100% - 2.5rem);
      overflow-y: scroll;
    }
    .map_text {
      width: 3rem;
      height: 500px;
      /* position: absolute; left: 46px; top: 146px; */
      background: white;
    }
    #container.amap-icon img {
      width: 25px;
      height: 34px;
    }
    #pickerBox {
      margin: 0.5rem 0;
      // width: 300px;
      height: 30px;
      line-height: 30px;
      position: relative;
      font-size: 14px;
    }
    #pickerInput {
      // width: 178px;
      height: 24px;
      border: 1px solid #ccc;
      border-radius: 5px;
      padding: 0 5px;
      position: absolute;
    }
    .myorder_active {
      width: 100%;
      height: 2.5rem;
      color: black;
      background: white;
      border: 1px solid #ededed;
    }
    .disActive {
      width: 100%;
      height: 2.5rem;
      background: #1d9beb;
      border: 1px solid #1d9beb;
      color: #fff;
    }
    .callPhone{
      background: aqua;
       color:  #1d9beb;
    }
    </style>
    
    展开全文
  • 1、组件添加属性 像原始的html元素都有自己的一些属性,而我们自己创建的组件,也可以通过prop来添加自己的属性。这样别人在使用你创建的组件的时候就可以传递不同的参数了。 <!DOCTYPE html> <...

    1、给组件添加属性

    像原始的html元素都有自己的一些属性,而我们自己创建的组件,也可以通过prop来添加自己的属性。这样别人在使用你创建的组件的时候就可以传递不同的参数了。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
             <button_list v-bind:books="books"> </button_list>
    
        </div>
    </body>
    </html>
    
    <!--vue引入   必须联网-->
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
    <script>
        //组件
        Vue.component('button_list',{
    
            //给组件添加属性   propertys   关键字
            props:['books'],
            template:`
            <table>
                 <tr>
                     <th>序号</th>
                     <th>标题</th>
                 </tr>
                 <tr v-for="(book,index) in books">
                     <td>{{index+1}}</td>
                     <td>{{book.title}}</td>
                 </tr>
            </table>
            `,  //button_list中封装的内容模板就是这句
            data:function(){               //这里的data写法不同于new vue中的data
                return {                 //这里需要{}
                    count:0
                    }
            }
        })
        new Vue({
            el:"#app",
            data:{
                books:[
                    {'title':"python","id":1},
                    {'title':"java","id":2},
                    {'title':"php","id":3},
                ]
    
            }
        })
    
    </script>
    
    

    2、单一根元素

    如果自定义的组件中,会出现很多html元素,那么根元素必须只能有一个,其余的元素必须包含在这个根元素中。比如以下是一个组件中的代码,会报错:
    在这里插入图片描述

    3、子组件事件和传递事件到父组件

    子组件中添加事件跟之前的方式是一样的,然后如果发生某个事件后想要通知父组件,那么可以使用this.$emit函数来实现。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <button_list v-for="book in books" v-bind:book="book" @check_change="checks"></button_list>
            <div v-for="cbook in component_book">
                {{cbook.title}}
            </div>
       </div>
    </body>
    </html>
    
    <!--vue引入   必须联网-->
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
    <script>
        //组件
        Vue.component('button_list',{
            //给组件添加属性   propertys   关键字
            props:['book'],
            template:`
            <div>
                <span>{{book.title}}</span>
                <input type="checkbox" @click="Oncheck">
            </div>
            `,  //button_list中封装的内容模板就是这句
            methods:{
                Oncheck:function(){
                    this.$emit('check_change', this.book)
                }
            }
        })
        new Vue({
            el:"#app",
            data:{
                books:[
                    {'title':"python","id":1},
                    {'title':"java","id":2},
                    {'title':"php","id":3},
                ],
                component_book:[],
            },
            methods:{
                checks:function(book){
                    console.log(book)
                    var index=this.component_book.indexOf(book)    //indexOf   返回的是book的下标
                    if(index >= 0){
                        this.component_book.splice(index,1)     //删除一个下标为index的元素
                    }else{
                        this.component_book.push(book)
                    }
                    
                }
            }
        })
    </script>
    

    在这里插入图片描述

    4、自定义组件v-model

    一个组件上的v-model默认会利用名为value的prop(属性)和名为input的事件,但是像单选框、复选框等类型的输入控件可能会将value特性用于不同的目的。这时候我们可以在定义组件的时候,通过设置model选项可以用来实现不同的处理方式。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <stepper v-model:value="goods_count"></stepper> 
       </div>
    </body>
    </html>
    
    <!--vue引入   必须联网-->
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
    <script>
        //计步器
        Vue.component('stepper',{
            //给组件添加属性   propertys   关键字
            props:['count'],
    
            model:{                //代表什么情况下触发这个v-model的行为
                event:'count_change',
                prop:'count'
            },
            template:`
            <div>
                <button @click="sub">-</button>
                <span>{{count}}</span>
                <button @click="add">+</button>
                
            </div>
            `,  //button_list中封装的内容模板就是这句
            methods:{
                sub:function(){
                    this.$emit('count_change', this.count-1)
                },
                add:function(){
                    this.$emit('count_change', this.count+1)
                }
    
            }
        })
        new Vue({
            el:"#app",
            data:{
                goods_count:0,
            },
        })
    </script>
    

    在这里插入图片描述
    其中的props定义的属性分别是给外面调用组件的时候使用的。model中定义的prop:'count’是告诉后面使用v-model的时候,要修改哪个属性;event:'count-chang’是告诉v-model,后面触发哪个事件的时候要修改属性。

    5、插槽

    我们定义完一个组件后,可能在使用的时候还需要往这个组件中插入新的元素或者文本。这时候就可以使用插槽来实现。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <new_link v-bind:url="url">         
                个人中心
            </new_link>
       </div>
    </body>
    </html>
    
    <!--vue引入   必须联网-->
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
    <script>
        //计步器
        Vue.component('new_link',{
            //给组件添加属性   propertys   关键字
            props:['url'],
    
            template:`
            <a v-bind:href="url">
                <slot></slot>
            </a>
            `,  
        })
        new Vue({
            el:"#app",
            data:{
                url:"https://www.baidu.com",
            },
        })
    </script>
    

    当组件渲染的时候,将会被替换为“个人中心”。插槽内可以包含任何模板代码,包括HTML:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <new_link v-bind:url="url">
                个人中心
                {{name}}
                <template v-slot:header>这是header</template>
                <template v-slot:main>这是main</template>          
                <div></div>
            </new_link>
       </div>
    </body>
    </html>
    
    <!--vue引入   必须联网-->
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
    <script>
        //计步器
        Vue.component('new_link',{
            //给组件添加属性   propertys   关键字
            props:['url'],
    
            template:`
            <a v-bind:href="url">
                <div>
                    <slot></slot>
                </div>
    
                <div>
                    <slot name="main"></slot>
                </div>
                
                <div>
                    <slot name="header"></slot>
                </div>
            </a>
            `,  
            data:function(){
                return {
                    name:"zzz",
                }
            }
        })
        new Vue({
            el:"#app",
            data:{
                url:"https://www.baidu.com",
            },
        })
    </script>
    

    如果没有包含一个元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。

    6、生命周期函数

    生命周期函数代表的是Vue实例,或者是Vue组件,在网页中各个生命阶段所执行的函数。生命周期函数可以分为创建阶段和运行期间以及销毁期间。

    • 其中创建期间的函数有beforeCreate、created、beforeMount、mounted;
    • 运行期间的函数有beforeUpdate、updated;
    • 销毁期间有beforeDestroy、destroyed。

    以下是官方文档给到的一张图,从这种图中我们可以了解到每个部分执行的函数。
    在这里插入图片描述
    创建期间:

    beforeCreate:
    Vue或者组件刚刚实例化,data、methods都还没有被创建。

    created:
    此时data和methods已经被创建,可以使用了。模板还没有被编译。

    beforeMount:
    created的下一阶段。此时模板已经被编译了,但是并没有被挂在到网页中。

    mounted:
    模板代码已经被加载到网页中了。此时创建期间所有事情都已经准备好了,网页开始运行了。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <p id="username">{{username}}</p>
       </div>
    </body>
    </html>
    
    <!--vue引入   必须联网-->
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
    <script>
        Vue.component('content',{
            template:`
                <div>
                    <slot name="header" :navs="navs"></slot>
                </div>
                <div>
                    <slot name="footer" :navs="navs"></slot>
                </div>
            `,  
            data:function(){
                return {
                    navs:["1","2","3"]
                }
            }
        }),
    
        new Vue({
            el:"#app",
            data:{
                username:"yyy"
            },
            methods:{
                demo:function(){
                    return "hello"
                }
            },
            //beforeCreate:Vue或者组件刚刚实例化,data、methods都还没有被创建
            beforeCreate(){
                // console.log(this.username);
                // console.log(this.demo);
                // console.log(123);
                // console.log("----------------------");
            },
            //此时data和methods已经被创建,可以使用了。模板还没有被编译。
            created(){
                // console.log(this.username);
                // console.log(this.demo);
                // console.log(123);
                // console.log("----------------------");
            },
            // created的下一阶段。此时模板已经被编译了,但是并没有被挂在到网页中。
            beforeMount(){
                //console.log(document.getElementById('username').innerText)
            },
            mounted(){
                console.log(document.getElementById('username').innerText)   //获取文本信息
            }
        })
    </script>
    

    运行期间:

    beforeUpdate:
    在网页网页运行期间,data中的数据可能会进行更新。在这个阶段,数据只是在data中更新了,但是并没有在模板中进行更新,因此网页中显示的还是之前的。

    updated:
    数据在data中更新了,也在网页中更新了。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <p id="username">{{username}}</p>
            <!-- v-model双向绑定,修改username的值 -->
            <input type="text" v-model="username">
       </div>
    </body>
    </html>
    
    <!--vue引入   必须联网-->
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
    <script>
        Vue.component('content',{
            template:`
            `,  
            data:function(){
                return {
                    
                }
            }
        }),
    
        new Vue({
            el:"#app",
            data:{
                username:"yyy"
            },
            methods:{
                demo:function(){
                    return "hello world"
                }
            },
            mounted(){
                // console.log(document.getElementById('username').innerText)   //获取文本信息
            },
            // 数据在data中更新了,也在网页中更新了
            update(){
                console.log(document.getElementById('username').innerText)   
    
            }
        })
    </script>
    

    销毁期间:

    beforeDestroy:
    Vue实例或者是组件在被销毁之前执行的函数。在这一个函数中Vue或者组件中所有的属性都是可以使用的。

    destroyed:
    Vue实例或者是组件被销毁后执行的。此时Vue实例上所有东西都会解绑,所有事件都会被移除,所有子元素都会被销毁。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <p id="username">{{username}}</p>
            <!-- v-model双向绑定,修改username的值 -->
            <input type="text" v-model="username">
    
            <error-view v-bind:message="message" v-if="message"></error-view>
            <button @click="message=' ' ">点击</button>
       </div>
    </body>
    </html>
    
    <!--vue引入   必须联网-->
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
    <script>
        Vue.component('error-view',{
            props:['message'],
            template:`
                <p style="color:red">{{message}}</p>
            `, 
            methods:{
                
            },
            data:function(){
                return {
                    
                }
            },
            beforeDestroy(){
                console.log('hello')
            },
    
    
        }),
    
        new Vue({
            el:"#app",
            data:{
                username:"yyyyyyyyyy",
                message:"错误信息",
            },
            methods:{
                demo:function(){
                    return "hello world"
                }
            },
            mounted(){
                // console.log(document.getElementById('username').innerText)   //获取文本信息
            },
            // 数据在data中更新了,也在网页中更新了
            update(){
                console.log(document.getElementById('username').innerText)   
            }
        })
    </script>
    
    展开全文
  • vue中如何使用addEventListener添加事件、removeEventListener...添加事件元素加上ref属性 在mounted中添加事件 mounted() { this.$refs.box.addEventListener('scroll',()=>{ console.log('scroll',th

    在vue中如何使用addEventListener添加事件、removeEventListener移除事件

    最近在项目中需要用到addEventListener监听滚动条滚动的高度,所以就研究了一下在vue中是怎么进行事件监听的。

    添加事件

    给要添加事件的元素加上ref属性

    在mounted中添加事件

        mounted() {
          this.$refs.box.addEventListener('scroll',()=>{
            console.log('scroll',this.$refs.box.scrollTop)
          });
        }
    

    这样就添加成功了!

    移除事件

    如果要移除已添加的事件,removeEventListener中传入的方法必须和addEventListener中传入的是同一个方法才能成功移除,所以在添加时就不能用匿名函数啦。需改成如下写法

        mounted() {
          this.$refs.box.addEventListener('scroll',this.scrollEvent);
        },
        methods:{
          scrollEvent(){
            console.log('scroll',this.$refs.box.scrollTop)
          }
        }
    

    这里要注意 传入的方法 this.scrollEvent 后面不能加括号,否则无法成功添加

    组件销毁前移除事件

        beforeDestroy() {
          this.$refs.box.removeEventListener('scroll',this.scrollEvent);
        }
    

    如果是keep-alive组件,可以用下面这种方式

      activated() {
        this.$refs.box.addEventListener('scroll', this.scrollEvent);
      },
      deactivated(){
        this.$refs.box.removeEventListener('scroll',this.scrollEvent);
      },
    

    另外,addEventListener还可以给一个元素添加多个事件,并且不会覆盖已存在的事件,这里就不多展开了~

    展开全文
  • 首先 vue的点击事件 是用 @click = “clickfun()” 属性 在html中绑定的, ...以上这篇vue 的点击事件获取当前点击的元素方法就是小编分享大家的全部内容了,希望能大家一个参考,也希望大家多多支持软件开发网。
  • Vue.js内部有这样一段代码其中定义了Vue构造函数,然后分别调用initMiXin,stateMixin,eventsMixin,...当函数initMixin被调用时,会向Vue构造函数的prototype属性添加_init方法,执行new Vue()时,会...

    在Vue.js内部有这样一段代码

    6fbe14d24f6b39c6bf40efc7553e09a2.png

    其中定义了Vue构造函数,然后分别调用initMiXin,stateMixin,eventsMixin,lifecycleMixin,renderMixin,并将Vue构造函数当作参数传给这5个函数

    这5个函数的作用就是向Vue的原型上挂载方法。

    2795d0a03a59f7e9ee12fc29e91506f9.png

    当函数initMixin被调用时,会向Vue构造函数的prototype属性添加_init方法,执行new Vue()时,会调用_init方法。

    好,接下来进入到本文的标题,与事件相关的实例方法有4个,分别是,vm.

    emit,vm.
    off;

    这四个方法实在eventsMixin中挂在到Vue构造函数和prototype属性中的。

    当eventsMixin被调用的时候,会向Vue构造函数的prototype属性添加4个实例方法。

    95cf743474fd42827530078bec7b818b.png

    c88781662906150a1c4f6e890a35f8e1.png

    91f64b5069e0f2f7a2d369d1d123fcff.png

    下面将介绍一下这四种方法

    d6e31cd104c9ac5a5a704ed48b3b3c93.png

    用法:监听当前实例上的自定义事件,事件可以由vm.$emit触发,回调函数会接收所有传入事件所触发的函数的额外参数

    原理:只需要在注册事件时将回调函数收集起来,在触发事件时将收集起来的回调函数依次调用即可,代码如下

     Vue.prototype.$on = function (event, fn) {
        var vm = this;
        if (Array.isArray(event)) {
          for (var i = 0, l = event.length; i < l; i++) {
            vm.$on(event[i], fn);
          }
        } else {
          (vm._events[event] || (vm._events[event] = [])).push(fn);
        }
        return vm
      };
    


    当event为数组的时候,需要遍历数组,使得数组中的每一项都调用vm.$on,使回调可以注册到数组中每项事件名所指定的事件列表中,当event参数不为数组时,就像事件列表中添加回调。
    vm._events是一个对象,用来存储事件,使用事件名(event)从vm._events中取出事件列表,如果列表不存在,则使用空数组初始化,然后将回调函数添加到事件列表中。
    vm._events在执行new Vue()时,会执行this._init方法进行一系列操作,其中就在vue.js的实例上创建一个_events

    d305746ba1a6b9d862dced0f8dc0bcf4.png

    用法:触发当前实例上的事件,附加参数都会传给监听器回调。

    原理:vm.$emit作用是触发事件,所有的事件监听器回调都会存储在vm._events中,所以触发事件的实现思路是使用事件名从vm._events中取出对应的事件监听器回调

    列表,然后依次执行列表中的监听器回调并将参数传递给监听器回调,代码如下

    Vue.prototype.$emit = function (event) {
        var vm = this;
        var cbs = vm._events[event];
        if (cbs) {
        //   const args = toArray(arguments,1);
          cbs = cbs.length > 1 ? toArray(cbs) : cbs;
          var args = toArray(arguments, 1);
          var info = "event handler for "" + event + """;
          for (var i = 0, l = cbs.length; i < l; i++) {
              try{
                  cbs[i].apply(vm,args)
              }catch(e){
                  handleError(e,vm,`event handler for "${event}"`)
              }
          }
        }
        return vm
      };
      
    


    使用event从vm._events中取出事件监听器回调函数列表,并将其赋值给变量cbs,如果cbs存在,依次调用每一个监听器回调并将其所有参数传给监听器回调。
    toArray的作用是将类似于数组的数据换成真正的数组,它的第二个参数是起始位置,也就是说,args是一个数组,里面包含除第一个参数之外的所有参数。

    emit可以结合起来使用,大部分用于父子组件传值,但是这里有一个问题

    1、究竟是由子组件内部主动传数据给父组件,由父组件监听接收(由子组件中操作决定什么时候传值)

    2、还是通过父组件决定子组件什么时候传值给父组件,然后再监听接收 (由父组件中操作决定什么时候传值)

    两种情况都有

    emit

    emit

    第一种情况

    父组件 所以msg打印出来就是蜡笔小柯南

    37fb15d90858451e3419c62559b5dbac.png

    子组件

    3350d502ab83258d800dfa3fe49706d9.png

    第二种情况

    父组件 通过ref操作子组件触发事件

    681f1460f3f789fb4a049994eb556e50.png

    子组件

    a0789f9a934be28c87afc1ec875378a6.png

    将两者情况对比,区别就在于$emit 自定义事件的触发是有父组件还是子组件去触发

    第一种,是在子组件中定义一个click点击事件来触发自定义事件$emit,然后在父组件监听

    第二种,是在父组件中第一一个click点击事件,在组件中通过refs获取实例方法来直接触发事件,然后在父组件中监听

    5b718a336f69f57192ddd95793d06b53.png

    用法:

    移除自定义事件监听器。

    如果没有提供参数,则移除所有的事件监听器;

    如果只提供了事件,则移除该事件所有的监听器;

    如果同时提供了事件与回调,则只移除这个回调的监听器。

    Vue.prototype.$off = function(event,fn){
        const vm = this;
        //1-1、没有提供参数的情况,此时需要移除所有事件的监听器
        if(!arguments.length){
            // 当arguments.lengtha为0时,说明没有任何参数,这时需要移除所有事件监听器
            // 因此重置了vm._events属性,vm._events存储所有事件,所以将vm._events重置
            // 为初始状态就等同于将所有事件都移除了。
            vm._events = Object.create(null);
            return vm;
        }
        // 1-2、vm.$off的第一个参数支持数组,当event为数组的时候,只需要将数组遍历一遍,然后
        // 数组中的每一项依次调用vm.$off;
        if(Array.isArray(event)){
            for(let i = 0 ; i<event.length; i++){
                this.$off(event[i],fn)
            }
            return vm;
        }
        // 2、只提供了事件名,则移除该事件所有的监听器,只需要将vm._events中的event重置为空就行
        const cbs = vm._events[event];
        if(!cbs){
            return vm;
        }
        // 这里做了一个安全检测,如果这个事件没有被监听,vm._events内找不到任何监听器,直接退出
        // 程序,然后判断是否只有一个参数,如果是,将事件名在vm._events中所有事件都移除,只需要
        // 将vm._events上以该事件为属性的值设置为null即可
        if(arguments.length === 1){
            vm._events[event] = null;
            return vm;
        }
        // 3、如果同时提供了事件与回调,那么只移除这个回调的监听器,将使用参数中提供的事件名从
        // vm._events取出事件列表,然后从列表中找到与参数中提供的回调函数相同的那个函数,并
        // 将它从列表中移除
        if(fn){
            // 先判断是否有fn参数,有则说明用户同时提供了event和fn两个参数,然后从vm._events
            // 中取出事件监听器列表并遍历它,如果列表中的某一项与fn相同,或者某一项的fn属性与fn相同,
            // 使用splice方法将它从列表中移除,当循环结束后,列表中所有与用户参数中提供的fn相同的监听器
            // 都会被移除
            const cbd = vm._events[event];
            let cb;
            let i = cbs.length;
            while(i--){
                // 这里有一个细节要注意,在代码中遍历列表是从后向前循环,这样在列表中移除当前
                // 位置的监听器,不会影响列表中未遍历到的监听器位置,如果是从前向后遍历,那么当从
                // 列表中移除一个监听器时,后面的监听器会自动向前移动一个位置,会导致下一轮循环
                // 时跳过一个元素。
                cb = cbs[i];
                if(cb === fn || cb.fn === fn){
                    cbs.splice(i,1);
                    break;
                }
            }
        }
        return vm;
    }
    

    2b600ffbcb714409eeec861e04890ec5.png
    Vue.prototype.$once = function (event, fn) {
          var vm = this;
          function on () {
            vm.$off(event, on);
            fn.apply(vm, arguments);
          }
          on.fn = fn;
          vm.$on(event, on);
          return vm
        };
        
    

    在vm.

    on来实现监听自定义事件的功能,当自定义事件触发后会执行拦截器,将监听器从事件列表中移除。

    在vm.

    on来监听事件,首先,将函数on注册到事件中,当自定义事件被触发时,会执行函数on(在这个函数中,会用时vm.$off将自定义事件移除),然后

    手动执行函数,并将参数arguments传递给函数fn,这样就可以实现vm.$once的功能。

    但是要注意on.fn = fn这行代码,前面介绍vm.$off时提到,在移除监听器时,需要将用户提供的监听器函数与列表中的监听器函数进行对比,相同部分会被移除,这导致当我们使用拦截器代替监听器注入到事件列表中时,

    拦截器和用户提供的函数时不相同的,此时用户使用vm.$off来移除事件监听器,移除操作失败。

    这个问题的解决方案是将用户提供的原始监听器保存到拦截器的fn属性中,当vm.$off方法遍历事件监听器列表时,同时会检查监听器和监听器的fn属性是否与用户提供的监听器函数相同,只要有一个相同,就说明需要被移除

    的监听器找到了,将被找到的拦截器从监听器列表中移除

    展开全文
  • 首先想要添加class的元素,通过v-bind绑定一个class 二.在data中声明一个变量activeClass 三.在点击事件中 四.在style里面写想要的样式就可以了 <li :class="activeClass == index ? 'acti...
  • 此时,页面上的样式并不会动态切换,而且浏览器控制台上的vue实例也没有动态的监听到tradeDayList内元素属性的变化,因此我让每次点击事件结束后,调用this.$forceUpdate()方法,强制重新渲染,此时浏览器控制台能...
  • 介绍此contextmenu组件是基于vue 3.0-beta的一次试验性开发,其中包括一些新api的使用:template refs- 用来给元素或子组件注册引用信息provide and inject- 依赖注入computed- 计算属性reactive- 返回原始对象的...
  • 某个元素添加点击事件时,在click属性前加“v-on:或@”,属性值为点击事件方法。相应的点击事件方法仍然存放于methods当中。 双击事件,将click改为dblclick即可。 鼠标事件:方法与点击事件一样。 二.事件修饰符...
  • v-bind 给元素动态绑定属性 还可以绑定类名和css样式等。 v-on 给元素动态绑定事件 例如点击事件,change事件, input输入事件。 v-if 判断变量 根据真假条件渲染元素。 v-show 跟v-if一样 判断变量 切换元素的 ...
  • 我想整个页面添加一个键盘事件,也就是快捷键,于是我在当前页面根元素上绑定了keyup事件, ps: div 的 事件不像表单,我们需要在标签上添加tableIndex = "0"这个属性 但是每次还是得点一下页面才有用,那大大...
  • Vue访问子组件实例或子元素

    千次阅读 2019-01-29 05:51:01
    首先子组件上添加一个ref属性 <base-alert ref="baseAlert"></base-alert> 复制代码现在可以使用 this.$refs.baseAlert 复制代码来访问子组件 base-alert的方法, 比如点击父组件的按钮,调用子组件的...
  • vue常用指令 v-text 解析输出变量 不解析标签 ...v-if 条件输出 不符合的元素就不渲染 用于初始渲染和数据的筛选 ...​v-on 给元素绑定事件 用法 v-on:事件名=“方法名” 可以简写为@事件名=“方法” v-pre 跨过当前的
  • vue指令

    2018-12-16 16:31:00
    vue指令: 1. v-if、v-else、 v-else-if ... 2. v-for ...给属性添加data中的值 4.v-model 双向绑定,加表单元素 5.v-on 缩写 @ 绑定事件 6.v-show css进行display:none的操作 7.v-text、v-h...
  • 在JS中list添加属性 深复制list 阻止页面原生事件 获取鼠标位置 在JS中拼接style 转换时间格式 我觉得冷门却很好用的方法(我要我觉得,不要你觉得~) 通过元素属性查出元素在list中的位置 可以省去循环list的优雅...
  • 操作面板按钮添加一个点击事件:将面板显示出来 02- 将频道操作面板封装为组件 1.0 由于频道操作是在 home 中完成了,home 中的逻辑已经足够多了,如果我们再将频道操作的逻辑也放到 home 中。将
  • Vue学习笔记

    2020-07-15 00:15:47
    文章目录一、Vue模板语法视图更新注意事项二、事件的绑定1、双向绑定v-model2、计算属性3、set4、监听属性5、表单input输入绑定6、修饰符三、自定义组件1、自定义组件定义2、组件添加属性3、单一根元素4、事件的...
  • Vue自定义组件和生命周期函数一、组件添加属性和单一根元素1.自定义组件添加属性2.单一根元素二、子组件事件和传递事件到父组件三、自定义组件v-model四、Vue插槽1.插槽的定义和简单使用2.定义多个插槽3.插槽的...
  • vue的双向绑定

    2020-01-16 14:49:27
    vue的双向绑定其实就一些可输入的元素通过添加input事件在动态的监听某个值 说明:在vue中 v-model 指令自动组件绑定input事件和传递value属性的值 组件实现双向绑定: 逻辑:一般情况下,vue的数据绑定是单向...
  • 前言 公司项目需要做拖拽替换效果,本人用的vue框架。在网上找了很多资料都是用的 Vue....H5提供了专门的拖拽API 给元素添加 draggable 属性,设置为 true就能实现拖拽了。本文使用的H5提供的拖拽API 以及vue
  • Vue双向数据绑定

    2019-07-15 21:07:00
    一、引入  谈及Vue中的数据双向绑定,我们自然而然的想到是通过v-model指令实现的。但具体是怎么实现的呢... 原理:表单元素input绑定通过"v-bind:"绑定value属性的数据msg,再表单元素input添加监听value值...
  • web前端教程JavaScript学习笔记 DOM一DOM(Document Object Model): 文档对象模型 其实就是操作 html ...给元素绑定一些事件 获取元素的属性 给元素添加一些 css 样式 ... DOM 的核心对象就是 docuemnt 对象 ...

空空如也

空空如也

1 2 3 4
收藏数 66
精华内容 26
关键字:

vue事件给元素添加属性

vue 订阅