前端图标字体的提取和使用

原创
2017/11/27 21:14
阅读数 3.6K

     我想对于做过web开发的一定知道font图标字体,目前主流的图标字体库有FontAwesome、glyphicons等。这些图标库你可以使用css对它们进行更改,包括:大小、颜色、阴影或者其它任何支持的效果。使用这些公共的图标字体库也可以一定程度上减轻ui设计师的工作,当然对于前端比较有追求的一些公司可能会自己设计一套自己的图标字体库。关于图标字体如何在页面中使用不在本文的范畴,本文的重点是介绍如何提取像FontAwesome,glyphicons这样常用字体库的图标。

一、为什么提取图标?

        开发web的很多人可能或多或少接触过web系统中的权限模块,权限模块中通常有一个菜单资源的配置,在显示菜单的时候,我们希望菜单前面带上一个我们做喜欢的图标,因此在配置菜单资源时你需要去指定一个图标样式。这时问题来了,很多的图标样式,不可能每添加一个菜单都去复制一个字体图标的css样式代码粘贴到输入框吧,而且如果有产品设计,产品设计一定是希望这个图标能够通过鼠标来选取。相应的在界面交互上就友好了很多。如下图所示:

二、提取图标的关键思路

        平时在使用图标的时候,要显示图标通常这么写

//font-awesome的相机图标
<i class="fa fa-camera-retro"></i>

fa后面的fa-camera-retro就是图标的名称。因此如果把图标字体库中字体的名称提取出来,就可以制作一个图标库选择插件了。

        要提取图标,首先由两种方法可以做到,下面将讨论两种方法的思路:

        第一种 :将官网的图标字体显示页面拔取下来,编写代码解析页面的结构提取图标,如font-awesome的页面通常如下图:

其实就是获取到所有的i标签,然后解析i标签就能获取到。但是不同的字体库展现结构不相同,针对不同的字体库都需要书写代码。这个可以自行尝试,本文不提供代码。

         第二种:通过解析css文件样式来提取字体库,这种方法相对第一种速度更快,主要是不下载网页,也不用分析dom结构,只需要把字体库的一整个包下载下来,然后将压缩过的css放到编辑其中就重新格式化成人眼能识别的状态。例如font-awesome的css样式重新格式化后,如图:

重新格式话后从大致浏览其实发现所有带着:before的演示行前面都是一个图标的名称,因此就发现了秘密,我们只需要书写一个正则表达式来将带有before的样式代码都匹配出来,然后处理匹配到的字符串即可得到图标字体库的名称了。关键代码如下:

/**
 * 通过读取前端字体题库的css文件来生成字体库列表
 * @author yu
 *
 */
public class FontIconUtil {

    /**
     * 读取font-awesome.min.css等字体库样式文件获取图标列表
     * 注意:在读取文件前需要将css文件格式化,即转化为非压缩模式
     * @param cssFile
     * @return
     */
    public static List<String> getIcons(File cssFile) {
        List<String> icons = new ArrayList<>(790);
        final String  regex = ".(.*?):before\\s*\\{";
        String curLine;
        BufferedReader reader;
        try {
            reader = new BufferedReader(new FileReader(cssFile));
            while ((curLine = reader.readLine()) != null) {
                Matcher matcher = Pattern.compile(regex, Pattern.DOTALL | Pattern.MULTILINE).matcher(curLine);
                if (matcher.find()) {
                    String selector = matcher.group();
                    //处理特殊行,如.fa-thermometer-1:before, .fa-thermometer-quarter:before
                    if(selector.contains(",")){
                        String[] iconArr = selector.split(",");
                        for(String str:iconArr){
                            icons.add(getIcon(str));
                        }
                    }else{
                        icons.add(getIcon(selector));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return icons;
    }

    /**
     * 获取单个图标名称
     * @param selector
     * @return
     */
    private static String getIcon(String selector){
        return selector.substring(selector.indexOf(".")+1,selector.indexOf(":"));
    }
}

调用上面的工具:

/**
 * Created by yu on 2017/3/17.
 */
public class FontIconUtilTest {

    @Test
    public void testGetIcons() throws Exception {
        List<String> icons = FontIconUtil.getIcons(new File("D:\\me\\WEB\\css\\font-awesome.min.css"));
        StringBuilder builder = new StringBuilder();
        //拼装icon-picker插件的图标数据,输出为javascript数组
        //将生成的此数组复制到picker中替换
        builder.append("var icons = [");
        for(int i =0;i<icons.size();i++){
            String icon = icons.get(i);
            String simpleName = icon.substring(icon.indexOf("-")+1);
            if(i<icons.size()-1){
                builder.append("'").append(simpleName).append("',");
            }else {
                builder.append("'").append(simpleName).append("'");
            }
        }
        builder.append("];");
        System.out.println(builder.toString());
    }
}

注意:上面代码并不能保证能读取所有图标字体库的图标名称,重要的是根据文中的思路在实际过程中进行修改。

三、怎么去制作一个图标选择器

         完成第二步后,我很多前端的开发工程师已经有自己的思路了,例如这些图标字节放到一个javascript的数组中,然后做一个图标选择的下拉组件,当然实现方式有很多。还有一种比较懒惰的做法是像第一个图中的例子一样,借助Bootstrap-icon-picker(ps:https://github.com/titosust/Bootstrap-icon-picker)修改几行代码就实现了,因为本身Bootstrap-icon-picker本身是专门针对glyphicon字体库实现的,我们只需要将上面提取的名称去更新他原有的图标数组,并将glyphicon前缀改成你抽取的图标库的前缀,例如font-awesome的前缀是fa。基于font-awesome修改后的代码如下:

/*
 * Bootstrap 3.3.6 IconPicker - jQuery plugin for Icon selection
 *
 * Copyright (c) 20013 A. K. M. Rezaul Karim<titosust@gmail.com>
 * Modifications (c) 20015 Paden Clayton<fasttracksites.com>
 *
 * Licensed under the MIT license:
 *   http://www.opensource.org/licenses/mit-license.php
 *
 * Project home:
 *   https://github.com/titosust/Bootstrap-icon-picker
 *
 * Version:  1.0.1
 *  
 * updated by yu
 *
 */

(function ($) {

    $.fn.iconPicker = function (options) {

        var mouseOver = false;
        var $popup = null;
        var icons = ['glass', 'music', 'search', 'envelope-o', 'heart', 'star', 'star-o', 'user', 'film', 'th-large', 'th', 'th-list', 'check', 'remove', 'close', 'times', 'search-plus', 'search-minus', 'power-off', 'signal', 'gear', 'cog', 'trash-o', 'home', 'file-o', 'clock-o', 'road', 'download', 'arrow-circle-o-down', 'arrow-circle-o-up', 'inbox', 'play-circle-o', 'rotate-right', 'repeat', 'refresh', 'list-alt', 'lock', 'flag', 'headphones', 'volume-off', 'volume-down', 'volume-up', 'qrcode', 'barcode', 'tag', 'tags', 'book', 'bookmark', 'print', 'camera', 'font', 'bold', 'italic', 'text-height', 'text-width', 'align-left', 'align-center', 'align-right', 'align-justify', 'list', 'dedent', 'outdent', 'indent', 'video-camera', 'photo', 'image', 'picture-o', 'pencil', 'map-marker', 'adjust', 'tint', 'edit', 'pencil-square-o', 'share-square-o', 'check-square-o', 'arrows', 'step-backward', 'fast-backward', 'backward', 'play', 'pause', 'stop', 'forward', 'fast-forward', 'step-forward', 'eject', 'chevron-left', 'chevron-right', 'plus-circle', 'minus-circle', 'times-circle', 'check-circle', 'question-circle', 'info-circle', 'crosshairs', 'times-circle-o', 'check-circle-o', 'ban', 'arrow-left', 'arrow-right', 'arrow-up', 'arrow-down', 'mail-forward', 'share', 'expand', 'compress', 'plus', 'minus', 'asterisk', 'exclamation-circle', 'gift', 'leaf', 'fire', 'eye', 'eye-slash', 'warning', 'exclamation-triangle', 'plane', 'calendar', 'random', 'comment', 'magnet', 'chevron-up', 'chevron-down', 'retweet', 'shopping-cart', 'folder', 'folder-open', 'arrows-v', 'arrows-h', 'bar-chart-o', 'bar-chart', 'twitter-square', 'facebook-square', 'camera-retro', 'key', 'gears', 'cogs', 'comments', 'thumbs-o-up', 'thumbs-o-down', 'star-half', 'heart-o', 'sign-out', 'linkedin-square', 'thumb-tack', 'external-link', 'sign-in', 'trophy', 'github-square', 'upload', 'lemon-o', 'phone', 'square-o', 'bookmark-o', 'phone-square', 'twitter', 'facebook-f', 'facebook', 'github', 'unlock', 'credit-card', 'feed', 'rss', 'hdd-o', 'bullhorn', 'bell', 'certificate', 'hand-o-right', 'hand-o-left', 'hand-o-up', 'hand-o-down', 'arrow-circle-left', 'arrow-circle-right', 'arrow-circle-up', 'arrow-circle-down', 'globe', 'wrench', 'tasks', 'filter', 'briefcase', 'arrows-alt', 'group', 'users', 'chain', 'link', 'cloud', 'flask', 'cut', 'scissors', 'copy', 'files-o', 'paperclip', 'save', 'floppy-o', 'square', 'navicon', 'reorder', 'bars', 'list-ul', 'list-ol', 'strikethrough', 'underline', 'table', 'magic', 'truck', 'pinterest', 'pinterest-square', 'google-plus-square', 'google-plus', 'money', 'caret-down', 'caret-up', 'caret-left', 'caret-right', 'columns', 'unsorted', 'sort', 'sort-down', 'sort-desc', 'sort-up', 'sort-asc', 'envelope', 'linkedin', 'rotate-left', 'undo', 'legal', 'gavel', 'dashboard', 'tachometer', 'comment-o', 'comments-o', 'flash', 'bolt', 'sitemap', 'umbrella', 'paste', 'clipboard', 'lightbulb-o', 'exchange', 'cloud-download', 'cloud-upload', 'user-md', 'stethoscope', 'suitcase', 'bell-o', 'coffee', 'cutlery', 'file-text-o', 'building-o', 'hospital-o', 'ambulance', 'medkit', 'fighter-jet', 'beer', 'h-square', 'plus-square', 'angle-double-left', 'angle-double-right', 'angle-double-up', 'angle-double-down', 'angle-left', 'angle-right', 'angle-up', 'angle-down', 'desktop', 'laptop', 'tablet', 'mobile-phone', 'mobile', 'circle-o', 'quote-left', 'quote-right', 'spinner', 'circle', 'mail-reply', 'reply', 'github-alt', 'folder-o', 'folder-open-o', 'smile-o', 'frown-o', 'meh-o', 'gamepad', 'keyboard-o', 'flag-o', 'flag-checkered', 'terminal', 'code', 'mail-reply-all', 'reply-all', 'star-half-empty', 'star-half-full', 'star-half-o', 'location-arrow', 'crop', 'code-fork', 'unlink', 'chain-broken', 'question', 'info', 'exclamation', 'superscript', 'subscript', 'eraser', 'puzzle-piece', 'microphone', 'microphone-slash', 'shield', 'calendar-o', 'fire-extinguisher', 'rocket', 'maxcdn', 'chevron-circle-left', 'chevron-circle-right', 'chevron-circle-up', 'chevron-circle-down', 'html5', 'css3', 'anchor', 'unlock-alt', 'bullseye', 'ellipsis-h', 'ellipsis-v', 'rss-square', 'play-circle', 'ticket', 'minus-square', 'minus-square-o', 'level-up', 'level-down', 'check-square', 'pencil-square', 'external-link-square', 'share-square', 'compass', 'toggle-down', 'caret-square-o-down', 'toggle-up', 'caret-square-o-up', 'toggle-right', 'caret-square-o-right', 'euro', 'eur', 'gbp', 'dollar', 'usd', 'rupee', 'inr', 'cny', 'rmb', 'yen', 'jpy', 'ruble', 'rouble', 'rub', 'won', 'krw', 'bitcoin', 'btc', 'file', 'file-text', 'sort-alpha-asc', 'sort-alpha-desc', 'sort-amount-asc', 'sort-amount-desc', 'sort-numeric-asc', 'sort-numeric-desc', 'thumbs-up', 'thumbs-down', 'youtube-square', 'youtube', 'xing', 'xing-square', 'youtube-play', 'dropbox', 'stack-overflow', 'instagram', 'flickr', 'adn', 'bitbucket', 'bitbucket-square', 'tumblr', 'tumblr-square', 'long-arrow-down', 'long-arrow-up', 'long-arrow-left', 'long-arrow-right', 'apple', 'windows', 'android', 'linux', 'dribbble', 'skype', 'foursquare', 'trello', 'female', 'male', 'gittip', 'gratipay', 'sun-o', 'moon-o', 'archive', 'bug', 'vk', 'weibo', 'renren', 'pagelines', 'stack-exchange', 'arrow-circle-o-right', 'arrow-circle-o-left', 'toggle-left', 'caret-square-o-left', 'dot-circle-o', 'wheelchair', 'vimeo-square', 'turkish-lira', 'try', 'plus-square-o', 'space-shuttle', 'slack', 'envelope-square', 'wordpress', 'openid', 'institution', 'bank', 'university', 'mortar-board', 'graduation-cap', 'yahoo', 'google', 'reddit', 'reddit-square', 'stumbleupon-circle', 'stumbleupon', 'delicious', 'digg', 'pied-piper-pp', 'pied-piper-alt', 'drupal', 'joomla', 'language', 'fax', 'building', 'child', 'paw', 'spoon', 'cube', 'cubes', 'behance', 'behance-square', 'steam', 'steam-square', 'recycle', 'automobile', 'car', 'cab', 'taxi', 'tree', 'spotify', 'deviantart', 'soundcloud', 'database', 'file-pdf-o', 'file-word-o', 'file-excel-o', 'file-powerpoint-o', 'file-photo-o', 'file-picture-o', 'file-image-o', 'file-zip-o', 'file-archive-o', 'file-sound-o', 'file-audio-o', 'file-movie-o', 'file-video-o', 'file-code-o', 'vine', 'codepen', 'jsfiddle', 'life-bouy', 'life-buoy', 'life-saver', 'support', 'life-ring', 'circle-o-notch', 'ra', 'resistance', 'rebel', 'ge', 'empire', 'git-square', 'git', 'y-combinator-square', 'yc-square', 'hacker-news', 'tencent-weibo', 'qq', 'wechat', 'weixin', 'send', 'paper-plane', 'send-o', 'paper-plane-o', 'history', 'circle-thin', 'header', 'paragraph', 'sliders', 'share-alt', 'share-alt-square', 'bomb', 'soccer-ball-o', 'futbol-o', 'tty', 'binoculars', 'plug', 'slideshare', 'twitch', 'yelp', 'newspaper-o', 'wifi', 'calculator', 'paypal', 'google-wallet', 'cc-visa', 'cc-mastercard', 'cc-discover', 'cc-amex', 'cc-paypal', 'cc-stripe', 'bell-slash', 'bell-slash-o', 'trash', 'copyright', 'at', 'eyedropper', 'paint-brush', 'birthday-cake', 'area-chart', 'pie-chart', 'line-chart', 'lastfm', 'lastfm-square', 'toggle-off', 'toggle-on', 'bicycle', 'bus', 'ioxhost', 'angellist', 'cc', 'shekel', 'sheqel', 'ils', 'meanpath', 'buysellads', 'connectdevelop', 'dashcube', 'forumbee', 'leanpub', 'sellsy', 'shirtsinbulk', 'simplybuilt', 'skyatlas', 'cart-plus', 'cart-arrow-down', 'diamond', 'ship', 'user-secret', 'motorcycle', 'street-view', 'heartbeat', 'venus', 'mars', 'mercury', 'intersex', 'transgender', 'transgender-alt', 'venus-double', 'mars-double', 'venus-mars', 'mars-stroke', 'mars-stroke-v', 'mars-stroke-h', 'neuter', 'genderless', 'facebook-official', 'pinterest-p', 'whatsapp', 'server', 'user-plus', 'user-times', 'hotel', 'bed', 'viacoin', 'train', 'subway', 'medium', 'yc', 'y-combinator', 'optin-monster', 'opencart', 'expeditedssl', 'battery-4', 'battery', 'battery-full', 'battery-3', 'battery-three-quarters', 'battery-2', 'battery-half', 'battery-1', 'battery-quarter', 'battery-0', 'battery-empty', 'mouse-pointer', 'i-cursor', 'object-group', 'object-ungroup', 'sticky-note', 'sticky-note-o', 'cc-jcb', 'cc-diners-club', 'clone', 'balance-scale', 'hourglass-o', 'hourglass-1', 'hourglass-start', 'hourglass-2', 'hourglass-half', 'hourglass-3', 'hourglass-end', 'hourglass', 'hand-grab-o', 'hand-rock-o', 'hand-stop-o', 'hand-paper-o', 'hand-scissors-o', 'hand-lizard-o', 'hand-spock-o', 'hand-pointer-o', 'hand-peace-o', 'trademark', 'registered', 'creative-commons', 'gg', 'gg-circle', 'tripadvisor', 'odnoklassniki', 'odnoklassniki-square', 'get-pocket', 'wikipedia-w', 'safari', 'chrome', 'firefox', 'opera', 'internet-explorer', 'tv', 'television', 'contao', '500px', 'amazon', 'calendar-plus-o', 'calendar-minus-o', 'calendar-times-o', 'calendar-check-o', 'industry', 'map-pin', 'map-signs', 'map-o', 'map', 'commenting', 'commenting-o', 'houzz', 'vimeo', 'black-tie', 'fonticons', 'reddit-alien', 'edge', 'credit-card-alt', 'codiepie', 'modx', 'fort-awesome', 'usb', 'product-hunt', 'mixcloud', 'scribd', 'pause-circle', 'pause-circle-o', 'stop-circle', 'stop-circle-o', 'shopping-bag', 'shopping-basket', 'hashtag', 'bluetooth', 'bluetooth-b', 'percent', 'gitlab', 'wpbeginner', 'wpforms', 'envira', 'universal-access', 'wheelchair-alt', 'question-circle-o', 'blind', 'audio-description', 'volume-control-phone', 'braille', 'assistive-listening-systems', 'asl-interpreting', 'american-sign-language-interpreting', 'deafness', 'hard-of-hearing', 'deaf', 'glide', 'glide-g', 'signing', 'sign-language', 'low-vision', 'viadeo', 'viadeo-square', 'snapchat', 'snapchat-ghost', 'snapchat-square', 'pied-piper', 'first-order', 'yoast', 'themeisle', 'google-plus-circle', 'google-plus-official', 'fa', 'font-awesome', 'handshake-o', 'envelope-open', 'envelope-open-o', 'linode', 'address-book', 'address-book-o', 'vcard', 'address-card', 'vcard-o', 'address-card-o', 'user-circle', 'user-circle-o', 'user-o', 'id-badge', 'drivers-license', 'id-card', 'drivers-license-o', 'id-card-o', 'quora', 'free-code-camp', 'telegram', 'thermometer-4', 'thermometer', 'thermometer-full', 'thermometer-3', 'thermometer-three-quarters', 'thermometer-2', 'thermometer-half', 'thermometer-1', 'thermometer-quarter', 'thermometer-0', 'thermometer-empty', 'shower', 'bathtub', 's15', 'bath', 'podcast', 'window-maximize', 'window-minimize', 'window-restore', 'times-rectangle', 'window-close', 'times-rectangle-o', 'window-close-o', 'bandcamp', 'grav', 'etsy', 'imdb', 'ravelry', 'eercast', 'microchip', 'snowflake-o', 'superpowers', 'wpexplorer', 'meetup'];
        var settings = $.extend({}, options);
        return this.each(function () {
            element = this;
            if (!settings.buttonOnly && $(this).data("iconPicker") == undefined) {
                $this = $(this).addClass("form-control");
                $wraper = $("<div/>", {class: "input-group"});
                $this.wrap($wraper);
                $button = $("<span class=\"input-group-addon pointer\"><i class=\"glyphicon  glyphicon-picture\"></i></span>");
                $this.after($button);
                (function (ele) {
                    $button.click(function () {
                        createUI(ele);
                        showList(ele, icons);
                    });
                })($this);
                $(this).data("iconPicker", {attached: true});
            }
            function createUI($element) {
                $popup = $('<div/>', {
                    css: {
                        'top': $element.offset().top + $element.outerHeight() + 6,
                        'left': $element.offset().left,
                        'z-index': 99999
                    },
                    class: 'icon-popup'
                });
                $popup.html('<div class="ip-control"> \
						          <ul> \
						            <li><a href="javascript:;" class="btn" data-dir="-1"><span class="glyphicon  glyphicon-fast-backward"></span></a></li> \
						            <li><input type="text" class="ip-search glyphicon  glyphicon-search" placeholder="Search" /></li> \
						            <li><a href="javascript:;"  class="btn" data-dir="1"><span class="glyphicon  glyphicon-fast-forward"></span></a></li> \
						          </ul> \
						      </div> \
						     <div class="icon-list"> </div> \
					         ').appendTo("body");
                $popup.addClass('dropdown-menu').show();
                $popup.mouseenter(function () {
                    mouseOver = true;
                }).mouseleave(function () {
                    mouseOver = false;
                });
                var lastVal = "", start_index = 0, per_page = 30, end_index = start_index + per_page;
                $(".ip-control .btn", $popup).click(function (e) {
                    e.stopPropagation();
                    var dir = $(this).attr("data-dir");
                    start_index = start_index + per_page * dir;
                    start_index = start_index < 0 ? 0 : start_index;
                    if (start_index + per_page <= 790) {
                        $.each($(".icon-list>ul li"), function (i) {
                            if (i >= start_index && i < start_index + per_page) {
                                $(this).show();
                            } else {
                                $(this).hide();
                            }
                        });
                    } else {
                        start_index = 180;
                    }
                });
                $('.ip-control .ip-search', $popup).on("keyup", function (e) {
                    var val = $(this).val();
                    if (val == "") {
                        showList($element, icons);
                    } else {
                        if (lastVal != $(this).val()) {
                            lastVal = $(this).val();
                            if (lastVal == "") {
                                showList(icons);
                            } else {
                                showList($element, $(icons)
                                    .map(function (i, v) {
                                        if (v.toLowerCase().indexOf(lastVal.toLowerCase()) != -1) {
                                            return v
                                        }
                                    }).get());
                            }
                        }
                    }
                });
                $(document).mouseup(function (e) {
                    if (!$popup.is(e.target) && $popup.has(e.target).length === 0) {
                        removeInstance();
                    }
                });
            }
            function removeInstance() {
                $(".icon-popup").remove();
            }
            function showList($element, arrLis) {
                $ul = $("<ul>");
                var html = "";
                for (var i in arrLis) {
                    html += "<li><a href=\"#\" title=" + arrLis[i] + "><span class=\"fa  fa-" + arrLis[i] + "\"></span></a></li>";
                }
                $ul.append(html);
                $(".icon-list", $popup).html($ul);
                $(".icon-list li a", $popup).click(function (e) {
                    e.preventDefault();
                    var title = $(this).attr("title");
                    $element.val("fa fa-" + title);
                    removeInstance();
                });
            }
        });
    }

}(jQuery));

 使用icon-picker组件实例:

$("#add-icon").iconPicker();

 

     总结:上面说了这么多,其实最终的目的就是如果利用现有的资源去想办法提高系统的交互性。当然上面提的只是一些实现思路的分享。

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
11 收藏
0
分享
返回顶部
顶部