11、点击事件三种实现方式


视频

一、本节简介

上节我们把知识体系列表获取下来了,这节我们来看看知识体系点击条目进入详情功能,点击效果大概可以以下三种方式实现

  • html 中添加 onclick 方法
  • 使用 bui 数据驱动的 b-click
  • 使用 bui 的事件委托

跳转的话就是 bui 的路由机制就可以了,我们逐一来看看

二、点击事件

1、html 标签中添加 onclick 方法

直接在 knowledte.js 的知识体系列表中的模版字符串中「二级分类标签整个条目」添加一个 onclick 方法并把当前的索引传递过去,在路由中要使用

  <li onclick="showDetail(${index})"style="display: flex;justify-content: space-between;align-items: center;padding:10px;">
    <ul style="display:flex;flex-wrap: wrap;">
           ${el.children.map((child,childIndex)=>
               `${childIndex < 6? `<li style="padding:5px">
               <div style="padding:5px;border:1px solid red;background:#eee;">
                   <span>${child.name}</span>
               </div>
           </li>`:""}`

       ).join('')}
       </ul>
    <i class="icon-listright">
    </i>
</li>`

而后在 builist 的组件外定义一个 showDetail 方法,方便测试我简单的打一个 log,输出当前条目的索引

 function showDetail(index){
    console.log(index)
 }

运行起来点击条目看效果,在 chrome 的 console 中查看

方法未定义

很不幸报错了,说方法未定义,我们明明定义了一个 showDetail 方法,为何提示未定义「WTF」?为什么呢?其实这就涉及到 js 作用域的问题「此处是方法的作用域」

简单来说就是 onclick 只能调用自身代码块中的方法或是全局方法,这块涉及到方法声明和方法表达式之间的关系,具体可以查看这里,这么说还有点抽象那直接上个代码来说明一下问题

<script type="text/javascript">

    function test(params) {
        console.log(params)

        var test2 = function(){
            console.log('test2')
        }
    }

</script>

<button onclick="test2()">click</button>

这样直接调用 test2 是调用不了的,因为 test2 是公共方法 test 内部的,只有 test 能调用,别的调用不了会提示方法未定义,我们的情况和这个类似,如何解决呢?

我们直接写在标签中,或是直接把 showDetail 挂到 window 对象上把它变成全局方法即可

方式一:在 script 标签中写方法

 <script>
    function showDetail(index){
    console.log(index)
}
<\/script>

<li onclick="showDetail(${index})"style="display: flex;justify-content: space-between;align-items: center;padding:10px;">
    <ul style="display:flex;flex-wrap: wrap;">
           ${el.children.map((child,childIndex)=>
               `${childIndex < 6? `<li style="padding:5px">
               <div style="padding:5px;border:1px solid red;background:#eee;">
                   <span>${child.name}</span>
               </div>
           </li>`:""}`

       ).join('')}
       </ul>
    <i class="icon-listright">
    </i>
</li>`

方式二:定义全局方法

// 把 showDetail 变成全局方法
window.showDetail = function(index){
    console.log(index)
}

这样就解决了方法未定义的问题,其实上面两种方法最终都是把方法挂到 window 上面形成全局方法了

这种做好不太好,为啥呢?动不动把一个方法搞成全局的失去灵活性,下面我们来看看 bui 事件驱动中如何做

2、bui 事件驱动点击事件

完过 vue 的朋友玩 bui 的事件驱动那就是菜两者 api 几乎一样,我们直接来使,使用 bui-store 来快速创建事件驱动的代码片断

 // 初始化数据行为存储
var bs = bui.store({
    scope: "page",
    data: {
        // 声明数据
        datas: []
    },
    methods: {
        showDetail:function(index,e) {
            console.log(index);
            console.log(e);
            // 这里处理跳转逻辑
        }
    },
    watch: {},
    computed: {},
    templates: {},
    mounted: function() {
        // 数据解析后执行
        // 列表控件 js 初始化: 
        var that = this ;
        var uiList = bui.list({
            id: "#knowledge-list",
            url: baseUrl + "/tree/json",
            pageSize: 5,
            data: {},
            //如果分页的字段名不一样,通过field重新定义
            field: {
                page: "page",
                size: "pageSize",
                data: "data"
            },
            callback: function(e) {},
            template: function(data) {
                that.datas = data;
                var html = "";
                data.map(function(el, index) {
                    // console.log(el.name)
                    html += `
            <li class="bui-btn-title">
                ${el.name}
            </li>



            <li b-click="page.showDetail(${index})"  style="display: flex;justify-content: space-between;align-items: center;padding:10px;">
                <ul style="display:flex;flex-wrap: wrap;">
                       ${el.children.map((child,childIndex)=>
                           `${childIndex < 6? `<li style="padding:5px">
                           <div style="padding:5px;border:1px solid red;background:#eee;">
                               <span>${child.name}</span>
                           </div>
                       </li>`:""}`

                   ).join('')}
                   </ul>
                <i class="icon-listright">
                </i>
            </li>`
                });
                return html;
            },
            autoScroll: false, // 滚动到底部不自动加载
        });
    }
})

核心就是把数据定义出来「由于我们返回的是一个数组,扬所以定义为 datas:[]」,然后使用 b-click 来调用 methods 中创建的方法完成条目单击事件,运行起来看效果

使用 b-click 完成点击事件

我们看到 log 是打印出来了,可是点击一下方法都调用了两桨,事件冒泡了,我们直接在 methods 方法中修改即可

 methods: {
    showDetail:function(index,e) {
        console.log(index);
        console.log(e);

        // 阻止事件冒泡
        // e.stopPropagation();
        return false ;
    }
},

使用 e.stopPropagation() 或是 return false 都可以解决这个问题

这下我们就正确的处理了列表条目点击事件

3、使用事件委托解决点击事件

试想一下如果渲染列表有 100 项会声明 100 个 onclick ,1w 项那简直是噩梦,会严重影响性能,所以我们使用事件委托机制来解决这个问题

事件委托机制内部采用的是事件冒泡机制,来看代码

先给我们的标签 li 给一个 id knowledge-li ,然后我们这个 li 其实是对应 knowledge 的 class 为 bui-list 的 ul 下,我们就可以把事件委托给 ul

 router.$("ul").on("click", "#knowledge-li", function(e) {
    var index = $(this).index();
    console.log(index)

    // 阻止事件冒泡  
    e.stopPropagation();
    // return false ; 阻止后续事件和阻止事件冒泡效果相同
})   

这就搞定了代码单独编写也没有问题,这里 bui-store 外面 ,就这么简单。来看一下效果

事件委托 log

我们看到打出来的 log 是一组奇数,为什么呢?因为我们的 ul 下面还有一个标题呢,所以们点击标签条目的时候就会从 1 3 5 … 开始,这不行,我们拿到 data 才取索引值会有问题了,我们处理一下,将索引值 var index = $(this).index(); 换成下面的方法即可

var index = ($(this).index()-1)/2;

这样我就就正确打出来了索引值,就可以取出条目中的数据然后传递到下一页去了

本节到此为止,这节我们就把在 bui 中点击事件方式大概说了一下,下节我们完成知识体系条目点击进二级导航

作者: TigerChain 公号同名,订阅查看更多内容

本文出自 TigerChain 使用 bui 开发玩 Android app


交个朋友

如果觉得本篇对你有帮助,那么请你完成以下几件小事情

1、动动你的小手关注一下以下公众号「TigerChain」查看更多精彩分享

2、更多视频关注的我的 B站:https://space.bilibili.com/44242327/


文章作者: TigerChain
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 TigerChain !
评论
  目录