1. 程式人生 > >一個簡單的輸入關鍵字添加標簽效果

一個簡單的輸入關鍵字添加標簽效果

click 多余 單元 con order http per script clear

效果

技術分享圖片

訪問:https://bxcn.github.io/keyWord/

目錄結構

技術分享圖片

參考

https://github.com/bxcn/keyWord

readme.md

一個簡單的輸入關鍵字添加標簽效果 
  
 實現功能: 
  輸入關鍵字加空格鍵添加tag標簽 
 按Backspace鍵刪除一個標簽 
 輸入關鍵字後,鼠標失去焦點添加tag標簽 
 keyWord.init方法初始化方法 
 防止輸入重復的關鍵字 
 限止最多輸入幾個關鍵字 
 
 
<style>
    .block {
        display:flex;
        flex
-direction:row; align-items:center; width:500px; height:30px; border:1px solid #ddd; padding:10px; margin:100px auto 0; } #wordTags { display:flex; flex-wrap:nowrap; } input{ width:100%; height:20px; border:none; }
</style> <div class="block"> <div id="wordTags"></div> <input id="wordInput" type="text" name="" placeholder="請輸入關鍵詞以空格結尾"> <input id="wordHiddenInput" type="hidden" name=""> </div> <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.js
"></script> <script type="text/javascript" src="aspect.js"></script> <script type="text/javascript" src="keyWord.js"></script> $(function () { var keyWord = $("#wordInput").keyWord({ panel: #wordTags, value: #wordHiddenInput, max: 3, tips: 最多只能輸入3項 }); keyWord.init(php,java,前端開發) }); 屬性說明: panel:面板的id value:隱藏字段的id max:最多輸入關鍵字個數 tips:提示語

index.html

<!DOCTYPE html>
<html>
<head>
    <title>keyWord--一個簡單的輸入關鍵字添加標簽效果</title>
    <meta charset="utf-8">
    <link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>
    <style>
        .block {
            display:flex;
            flex-direction:row;
            align-items:center;
            width:500px;
            height:30px;
            border:1px solid #ddd;
            padding:10px;
            margin:100px auto 0;
        }
        #wordTags {
            display:flex;
            flex-wrap:nowrap;
        }
        input{
            width:100%;
            height:20px;
            border:none;
        }
    </style>
</body>
<div class="block">
    <div id="wordTags"></div>
    <input id="wordInput" type="text" name="" placeholder="請輸入關鍵詞以空格結尾">
    <input id="wordHiddenInput" type="hidden" name="">
</div>
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.js"></script>
<script type="text/javascript" src="aspect.js"></script>
<script type="text/javascript" src="keyWord.js"></script>
<script type="text/javascript">

$(function () {
    var keyWord = $("#wordInput").keyWord({
        panel: #wordTags,
        value: #wordHiddenInput,
        max: 3,
        tips: 最多只能輸入3項
    });

    keyWord.init(php,php,java,前端開發)
});

</script>
</html>

index.css

@charset "UTF-8";
@font-face { font-family: iconfont; src: url("../fonts/iconfont.eot");  /* IE9*/ src: url("../fonts/iconfont.eot?#iefix") format("embedded-opentype"), url("../fonts/iconfont.woff") format("woff"), url("../fonts/iconfont.ttf") format("truetype"), url("../fonts/iconfont.svg#iconfont") format("svg");  /* iOS 4.1- */ }
html { position: relative; min-height: 100%; -webkit-overflow-scrolling: touch; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; -webkit-tap-highlight-color: transparent; }
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, body, div, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, fieldset, legend, button, input, textarea, form, th, td { margin: 0; padding: 0; vertical-align: baseline; }
article, aside, details, figcaption, figure, footer, header, hgroup, nav, section, summary { display: block; }
audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; }
body, button, input, select, textarea { outline: none; }
h1, h2, h3, h4, h5, h6 { font-size: 100%; font-weight: normal; }
address, cite, dfn, em, var, i { font-style: normal; }
body {  line-height: 120%; font-size: 14px; color: #4d4d4d; font-family: Arial,  sans-serif;}
small { font-size: 80%; }
ul, ol { list-style: none outside none; }
a { text-decoration: none; }
a:hover { text-decoration: none; outline: 0; }
a:active { text-decoration: none; outline: 0; }
a:focus { text-decoration: none; outline: 0; }
abbr[title], acronym[title] { border-bottom: 1px dotted; cursor: help; }
q:before, q:after { content: ‘‘; }
mark { background-color: #ff0; color: #000; }
pre {  /**
    normal  默認。空白會被瀏覽器忽略。
    pre     空白會被瀏覽器保留。其行為方式類似 HTML 中的 <pre> 標簽。
    nowrap  文本不會換行,文本會在在同一行上繼續,直到遇到 <br> 標簽為止。
    pre-wrap  保留空白符序列,但是正常地進行換行。
    pre-line  合並空白符序列,但是保留換行符。
    inherit 規定應該從父元素繼承 white-space 屬性的值。
    */
white-space: pre-wrap; word-wrap: break-word; }
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
sup { top: -0.5em; }
sub { bottom: -0.25em; }
legend { display: none; border: 0; padding: 0; white-space: normal; }
fieldset, iframe { border: 0 none; }
img { border: 0 none; vertical-align: middle; -ms-interpolation-mode: bicubic; }
button, input, select, textarea { font-family: inherit; font-size: 100%; vertical-align: baseline; }
button, input[type="button"], input[type="reset"], input[type="submit"] { -webkit-appearance: button;  /* 改正iOS設備中“input”類型表單樣式不可用的問題 */ cursor: pointer;  /* 增強光標樣式在input表單和其他表單的可用性和一致性 */ }
button[disabled], html input[disabled] { cursor: default;  /* 為禁用表單重設定默認光標樣式 */ }
button::-moz-focus-inner, button::-moz-focus-outer, input::-moz-focus-inner, input::-moz-focus-outer { border: 0 none; padding: 0; margin: 0; }
input[type="checkbox"], input[type="radio"] { box-sizing: border-box;  /* 調整IE 8/9中尺寸屬性設置為“內容框”的盒子模型 */ padding: 0;  /* 去除IE 8/9中的多余的外邊距留白部分 */ }
input[type="search"] { -webkit-appearance: textfield;  /* 兼容Safari 5 and Chrome上 “searchfield” 上設置 “appearance”屬性 */  /* 兼容Safari 5 and Chrome上 “border-box” 上設置 “box-sizing”屬性 */
box-sizing: content-box; }
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none;  /* 去除OS X系統上Safari 5和Chrome中容器內邊距和搜索取消按鈕屬性 */ }
input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill { -webkit-box-shadow: 0 0 0 1000px white inset; }
textarea { overflow: auto; vertical-align: top; resize: vertical; }
table {  /* 刪除表格單元格之間的間距。 */
border-collapse: collapse; border-spacing: 0; }
strong { font-weight: normal; }
img { vertical-align: middle; }
.clearfix { zoom: 1; clear: both; height: 0; overflow: hidden; width: 100%; display: block; }
.clearfix:before, .clearfix:after { content: ""; display: block; height: 0; overflow: hidden; visibility: hidden; }
.fl { float: left; }
.fr { float: right; }
.mauto { float: inherit !important; margin-left: auto; margin-right: auto; }
fieldset { border: none; }
input::-webkit-input-placeholder { color: #bfbfbf; }
input:-ms-input-placeholder { color: #bfbfbf; }
input:-moz-placeholder { color: #bfbfbf; }
input::-moz-placeholder { color: #bfbfbf; }

/* 刪除選中標簽 */
.tag-checked-name {
    display:inline-block;
    position:relative;
    height: 24px;
    border-radius: 1px;
    color:#4abee0;
    font-size:12px;
    line-height:24px;
    padding:0 20px 0 8px;
    background-color: #f7fdff;
    border: solid 1px #4abee0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    margin-right:5px;
}
.tag-checked-name:first-of-type {
    margin-left: 0px;
}
.tag-checked-name em {
   display:block;
    position:absolute;
    top:5px;
    right:5px;
    width:13px;
    height: 13px;
    cursor:pointer;
    transform: rotate(45deg);
}
.tag-checked-name em:after {
    display:block;
    position:absolute;
    content:‘‘;
    top:6px;
    width:13px;
    height:1px;
    background:#4abee0;
}
.tag-checked-name em:before {
    display:block;
    position:absolute;
    content:‘‘;
    top:0px;
    left:5px;
    width:1px;
    height: 13px;
    background:#4abee0;
}

aspect.js

/**
 * @file aspect
 * @fork https://github.com/ecomfe/saber-lang/blob/master/src/function/aspect.js
 */
(function () {

    /**
     * Aspect
     *
     * @inner
     * @type {Object}
     */
    var Aspect = {};

    /**
     * before AOP
     *
     * @private
     * @param {string} method 欲AOP的目標方法名
     * @param {Function} fn AOP處理函數
     * @param {*} context `fn`調用時的上下文
     * @return {Object} 目標對象
     */
    Aspect.before = function (method, fn, context) {
        return aspectTo(this, before, method, fn, context);
    };

    /**
     * after AOP
     *
     * @private
     * @param {string} method 欲AOP的目標方法名
     * @param {Function} fn AOP處理函數
     * @param {*} context `fn`調用時的上下文
     * @return {Object} 目標對象
     */
    Aspect.after = function (method, fn, context) {
        return aspectTo(this, after, method, fn, context);
    };


    /**
     * 對`目標對象`的`指定方法`進行`AOP`包裝
     *
     * @inner
     * @param {Object} target 目標對象
     * @param {string} type AOP方式,可取值 `before` | `after`
     * @param {string} method 欲AOP的目標對象的方法名
     * @param {Function} fn AOP處理函數
     * @param {*} context `fn`調用時的上下文
     * @return {Object} 目標對象
     */
    function aspectTo(target, type, method, fn, context) {
        var oriMethod = target[method];

        if (oriMethod) {
            if (type === before) {
                target[method] = function () {
                    // abort support
                    if (fn.apply(context || fn, arguments) !== false) {
                        oriMethod.apply(this, arguments);
                    }
                };
            }
            else if (type === after) {
                target[method] = function () {
                    oriMethod.apply(this, arguments);
                    fn.apply(context || fn, arguments);
                };
            }
        }

        return target;
    }


    /**
     * Aspect
     *
     * @exports Aspect
     * @type {Object}
     */
    var exports = {};

    /**
     * 將 `Aspect` 混入到目標對象
     *
     * @public
     * @param {Object} obj 目標對象
     * @return {Object} 混入 `Aspect` 後的目標對象
     */
    exports.mixin = function (obj) {
        // 省略了 hasOwnProperty 校驗
        /* eslint-disable guard-for-in */
        for (var method in Aspect) {
            obj[method] = Aspect[method];
        }
        /* eslint-enable guard-for-in */
        return obj;
    };

    window.AOP =  exports;

})();

keyWord.js

/**
 * 定義一個列表數據結構
 * 作用:添加元素、刪除元素、清除所有元素,將數據中的元素組裝成對象返回一個數據
 * 只針對數據處理
 * @constructor
 */
function List() {
  this.dataStore = new Array();
  this.listSize = 0;
  this.pos = 0;
}
List.prototype = {
  constructor: List,
  append: function(name) {
    this.dataStore[this.listSize++] = name;
  },
  cusPos: function() {
    return this.pos;
  },
  front: function() {
    this.pos = 0;
  },
  end: function() {
    this.pos = this.listSize - 1;
  },
  length: function() {
    return this.listSize;
  },
  prev: function() {
    if (this.pos > 0) {
      --this.pos;
    }
  },
  next: function() {
    if (this.pos < this.listSize) {
      ++this.pos;
    }
  },
  find: function(name) {
    var index = -1;
    this.dataStore.forEach(function(data, i, array) {
      if (data == name) {
        index = i;
      }
    });
    return index;
  },
  remove: function(name) {

    var index = this.find(name);
    if (index > -1) {
      this.dataStore.splice(index, 1);
      --this.listSize;
      return true;
    }

    return false;


  },
  getElement: function() {
    return this.dataStore[this.pos];
  },
  clear: function() {
    delete this.dataStore;
    this.dataStore = [];
    this.pos = this.listSize = 0;
  }
}

/**
 * 定義一個用來對列表操作的對象
 * 對列表的一個包裝
 * @param options
 */
var doKeyWord = function(options) {

  var settings = options;

  var list = new List();

  return AOP.mixin({
    init: function(arr) {
      var that = this;
      // 初始化
      if (typeof arr == "string") {
        arr = arr == ‘‘ ? [] : arr.split(,);
      }
      if (typeof arr == undefined) {
        arr = [];
      }
      // 清空數據
      list.clear();
      // 便利添加數據中
      arr.forEach(function(data, i, array) {
        that.add(data);
      })
    },
    render: function() {
      // 渲染效果

      var valueArr = [],
        html = [],
        name;

      for (list.front(); list.cusPos() < list.length(); list.next()) {
        name = list.getElement();
        valueArr.push(name);
        html.push(<div class="tag-checked-name"> + name.substr(0, 10) + <em data-word-tag-close=" + name + "></em></div>)
      }

      $(settings.panel).html(html.join(‘‘));
      $(settings.value).val(valueArr.join(,));

    },
    add: function(name) {
      name = $.trim(name);
      if (name == ‘‘) {
        return false;
      }
      // 添加數據
      if (list.find(name) > -1) {
        return false;
      }
      list.append(name);
    },
    remove: function(name) {
      list.remove(name);
    },
    clear: function() {
      list.clear();
    },
    front: function() {
      return list.front();
    },
    end: function() {
      return list.end()
    },
    getElement: function() {
      return list.getElement();
    },
    length: function() {
      return list.length();
    }
  });
}

$(function() {

  $.fn.keyWord = function(options) {

    var keyWord = doKeyWord(options);

    // 對添加的數據進行檢查
    function doCheck() {
      if (options.max < keyWord.length() + 1) {
        alert(options.tips);
        return false;
      }

      return true;
    }


    var render = keyWord.render;

    // 添加前檢查
    keyWord.before(add, doCheck);
    // 初始化後渲染效果
    keyWord.after(init, render);
    // 添加後渲染效果
    keyWord.after(add, render);
    // 刪除後渲染效果
    keyWord.after(remove, render);

    var that = $(this);
    // 刪除元素
    $(document).on(click, [data-word-tag-close], function() {
      var name = $(this).data(word-tag-close);
      // 過濾掉不刪除的
      keyWord.remove(name);
    });
    /**
     * Backspace刪除 對應的鍵盤編碼
     * e.keyCode == 8 :Backspace鍵
     */
    that.keydown(function(e) {
      var that = $(this);
      var val = $.trim(that.val());
      if (val == "" && e.keyCode == 8) {
        keyWord.end();
        keyWord.remove(keyWord.getElement());
      }
    });

    // 添加數據
    function doAdd(name) {
      name = $.trim(that.val());
      that.val(‘‘);
      if (name == ‘‘) {
        return;
      }
      keyWord.add(name);
    }

    /**
     * 判斷有輸入空格嗎
     * e.keyCode == 32 空格鍵
     */
    that.keyup(function(e) {
      var that = $(this);
      var isSpaceKey = /\s+$/gi.test(that.val());
      // 是空格鍵輸入了一個空格字符
      if (e.keyCode == 32 && isSpaceKey) {
        doAdd(that.val())
      }
    });
    // 鼠標失去焦點
    that.blur(function(e) {
      doAdd(that.val())
    });

    this.init = function(arr) {
      keyWord.init(arr);
    }
    return this;

  }
});

一個簡單的輸入關鍵字添加標簽效果