• bootstrap插件学习-bootstrap.typehead.js


    先看bootstrap.typehead.js的结构

    var Typeahead = function ( element, options ){} //构造器
    Typeahead.prototype = {} //构造器的原型
    $.fn.typeahead = function ( option ){} //jQuery原型上自定义方法
    $.fn.typeahead.defaults ={} //默认参数
    $.fn.typeahead.Constructor = Typeahead //重写jQuery原型上的自定义方法的构造器名
    $(function () {}) //初始化

    HTML结构

    <input class="span3" type="text"
           data-source="['Alabama','Alaska','Arizona','Arkansas','California','Colorado','Connecticut','Delaware','Florida'
           ,'Georgia','Hawaii','Idaho','Illinois','Indiana','Iowa','Kansas','Kentucky','Louisiana','Maine','Maryland'
           ,'Massachusetts','Michigan','Minnesota','Mississippi','Missouri','Montana','Nebraska','Nevada','New Hampshire'
           ,'New Jersey','New Mexico','New York','North Dakota','North Carolina','Ohio','Oklahoma','Oregon','Pennsylvania'
           ,'Rhode Island','South Carolina','South Dakota','Tennessee','Texas','Utah','Vermont','Virginia','Washington'
           ,'West Virginia','Wisconsin','Wyoming']" data-items="4" data-provide="typeahead" style="margin: 0 auto;"/>

    先从初始化开始

    /*
        * 初始化
        * */
        $(function () {
            $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
                var $this = $(this)
                if ($this.data('typeahead')) return
                e.preventDefault() //阻止冒泡
                $this.typeahead($this.data())
            })
        })

    为所有拥有data-provide='typehead'属性的标签绑定focus事件,并且阻止事件冒泡,进入jQuery的原型方法中

    /*
        * jQuery原型上自定义方法
        * */
        $.fn.typeahead = function ( option ) {
            return this.each(function () {
                var $this = $(this)
                    , data = $this.data('typeahead')
                    , options = typeof option == 'object' && option
                if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))//实例化构造器
                if (typeof option == 'string') data[option]()
            })
        }

    由于,$this.data('typehead')为空,我们执行实例化。

    /*
        * 构造器
        * */
        var Typeahead = function ( element, options ) {
            this.$element = $(element)
            this.options = $.extend({}, $.fn.typeahead.defaults, options)
            this.matcher = this.options.matcher || this.matcher//原型上的matcher方法
            this.sorter = this.options.sorter || this.sorter//原型上的sorter方法
            this.highlighter = this.options.highlighter || this.highlighter//原型上的highlighter方法
            this.$menu = $(this.options.menu).appendTo('body')//将下拉框ul加入body中,返回ul的jQuery对象
            this.source = this.options.source //获得input控件里的参数。input优先级大于默认项
            this.shown = false
            this.listen()
        }

    这里注意一点是,控件中的data属性与默认项中如果有重名属性的话,data属性优先级高,会覆盖。进入listen方法

    listen: function () {
                this.$element
                    .on('blur',     $.proxy(this.blur, this))//绑定blur事件
                    .on('keypress', $.proxy(this.keypress, this))//绑定keypress事件
                    .on('keyup',    $.proxy(this.keyup, this))//绑定keyup事件
                /*
                * 如果浏览器内核是webkit或者是ie内核的,绑定keydown事件。
                * */
                if ($.browser.webkit || $.browser.msie) {
                    this.$element.on('keydown', $.proxy(this.keypress, this))
                }
                /*
                * ul绑定click事件和mouserenter事件
                * */
                this.$menu
                    .on('click', $.proxy(this.click, this))
                    .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
            }

    完成事件监听的绑定工作,至此初始化工作完成。原型上拥有一堆API,让我们一一尝试。

    先看input的keypress事件,对应的keypress方法

    keypress: function (e) {
                if (!this.shown) return
    
                switch(e.keyCode) {
                    case 9: // tab
                    case 13: // enter
                    case 27: // escape
                        e.preventDefault()
                        break
    
                    case 38: // up arrow
                        e.preventDefault()
                        this.prev()
                        break
    
                    case 40: // down arrow
                        e.preventDefault()
                        this.next()
                        break
                }
    
                e.stopPropagation()  //阻止冒泡

    键盘上的按钮对应响应的keyCode,preventDefault方法将阻止元素放生默认行为。如果按了向上的箭头,进入prev方法

    prev: function (event) {
                var active = this.$menu.find('.active').removeClass('active')
                    , prev = active.prev()
    
                if (!prev.length) {
                    prev = this.$menu.find('li').last()
                }
    
                prev.addClass('active')
            }

    ul中li元素遍历,上箭头可以向上选择li元素,如果到顶了,则返回最下面的li元素重新开始。被选中的li元素会拥有active类,一个选中样式,其他li则没有。

    next: function (event) {
                var active = this.$menu.find('.active').removeClass('active')
                    , next = active.next()
    
                if (!next.length) {
                    next = $(this.$menu.find('li')[0])
                }
    
                next.addClass('active')
            }

    next的方法与prev类似,像API中还有类似的方法,大家依照demo,一调试就可以出来,比如mouseenter,click,blur,show,hide方法等。

    对于具有联想功能的插件,学习学习它的联想功能如何实现比较重要。

    好,我们从keyup开始

    keyup: function (e) {
                switch(e.keyCode) {
                    case 40: // down arrow
                    case 38: // up arrow
                        break
    
                    case 9: // tab
                    case 13: // enter
                        if (!this.shown) return
                        this.select()
                        break
    
                    case 27: // escape
                        if (!this.shown) return
                        this.hide()
                        break
    
                    default:
                        this.lookup()// 一般按键
                }
    
                e.stopPropagation()
                e.preventDefault()
            }

    如果我们输入一般字母,进入默认的lookup方法

     /*
              * 查询匹配方法
              * */
            , lookup: function (event) {
                var that = this
                    , items
                    , q
    
                this.query = this.$element.val()//获取用户输入内容
                if (!this.query) {   //不输入空格
                    return this.shown ? this.hide() : this
                }
    
                items = $.grep(this.source, function (item) {
                    if (that.matcher(item)) return item
                })//遍历this.source,其中的成员执行函数,最后返回结果
                items = this.sorter(items)
    if (!items.length) { return this.shown ? this.hide() : this } /*截取前4位*/ return this.render(items.slice(0, this.options.items)).show() }

     这里代码有个错误,就是这个this.source,它的类型不是object,或者是一个数组,导致最后联想功能只能匹配一个字符串,现在的this.source只是字符串,所以我们需要让它变成object对象,有人用json的API,可以,浏览器不兼容怎么办,引入J相关JSON的兼容包就可以搞定了,那还有了,对,eval。这个方法缺点一大堆,不过简单粗暴直接。我们修改一下源码

    items = $.grep(eval(this.source), function (item) {
                    if (that.matcher(item)) return item
                })

    其实解决办法很多,我这里图方便了,我们继续。修改return

    return this.render(items).show();

    进入render方法

    /*
              * 生成li标签
              * */
            , render: function (items) {
                var that = this
                items = $(items).map(function (i, item) {
                    i = $(that.options.item).attr('data-value', item) //往li中塞值
                    i.find('a').html(that.highlighter(item))
                    return i[0]
                })
                items.first().addClass('active') //默认下拉内容中第一个显示
                this.$menu.html(items) //将生气li标签插入ul中
                return this
            }

    看一下highlighter函数

    highlighter: function (item) {
                return item.replace(new RegExp('(' + this.query + ')', 'ig'), function ($1, match) {
                    return '<strong>' + match + '</strong>'
                })
            }

    高亮处理,replace的用法,大家可以学习一下。

    最后是show出来

    /*
              * 显示
              * */
            , show: function () {
                var pos = $.extend({}, this.$element.offset(), {
                    height: this.$element[0].offsetHeight
                })
    
                this.$menu.css({
                    top: pos.top + pos.height
                    , left: pos.left
                })
    
                this.$menu.show()
                this.shown = true
                return this
            }

    调用jQuery的show方法显示。

    这个插件中也有不少写的很蛋疼的方法,不过稍作修改就可以完成了,其实关于搜索这块的效率,我没有提及。每个人思路不一样,实现也不一样。希望园友们也能思考一下,能给出更加高效的查询办法。

    内容不多,时间刚好,以上是我的一点读码体会,如有错误,请指出,大家共通学习。 

  • 相关阅读:
    stark
    MySQL与JDBC
    存储过程/视图/触发器
    MyCat部署运行(Windows环境)与使用步骤详解
    常用单词总结
    表单校验---validation检验
    jQuery简介
    javascript简单介绍
    HTML&&CSS
    消息队列Java的简单实现
  • 原文地址:https://www.cnblogs.com/wumadi/p/3275242.html
Copyright © 2020-2023  润新知