ng-directive自定义指令—美化单选/复选框

说明
  1. 为了保证正确显示样式,指令标签必须包含在label标签内
  2. ng-model必须绑定
  3. value与ng-value,value仅支持固定字符串值,ng-value(优先值)为绑定变量
  4. name与ng-name,name区分同一页面多组选框,执行效果同上
  5. 复选框模式请在指令标签上加上 checkbox 属性
示例(单选模式)
<label>
  <een-radio 
        ng-model="$ctrl.infoData.sex" 
        value="1"
        blur-color="#999" 
        focus-color="#e0920d" 
        style="height:2rem;width:2rem;"  >
  </een-radio> 男
</label>
示例(多选模式)
<label>
  <een-radio 
        checkbox
        ng-model="$ctrl.infoData.sex" 
        value="1"
        blur-color="#999" 
        focus-color="#e0920d" 
        style="height:2rem;width:2rem;"  >
  </een-radio> 男
</label>

注意:多选模式下,ng-model绑定的值转换成了数组

源代码
var _controller = ["$scope","$attrs","$element",function($scope,$attrs,$element){

    // radio的样式-----------
    let itrue = 'M896 0 128 0C57.6 0 0 57.6 0 128l0 768c0 70.4 57.6 128 128 128l768 0c70.4 0 128-57.6 128-128L1024 128C1024 57.6 966.4 0 896 0zM844.8 396.8l-345.6 345.6c-12.8 12.8-25.6 19.2-44.8 19.2-19.2 0-32-6.4-44.8-19.2L243.2 569.6C230.4 556.8 224 537.6 224 524.8c0-19.2 6.4-32 19.2-44.8 25.6-25.6 64-25.6 89.6 0l128 128 300.8-300.8c25.6-25.6 64-25.6 89.6 0 12.8 12.8 19.2 25.6 19.2 44.8C864 364.8 857.6 384 844.8 396.8z';
    let ifalse = 'M890.4 8 133.6 8C64.4 8 8 64.2 8 133.6l0 756.7C8 959.6 64.2 1016 133.6 1016l756.7 0c69.3 0 125.6-56.2 125.6-125.6L1015.9 133.6C1016 64.4 959.8 8 890.4 8zM953 889.6c0 35-28.3 63.4-63.4 63.4L134.4 953c-35 0-63.4-28.3-63.4-63.4L71 134.4c0-35 28.3-63.4 63.4-63.4l755.1 0c35 0 63.4 28.3 63.4 63.4L952.9 889.6z';
    // checkbox的样式--------------
    if(typeof $attrs.checkbox === "undefined"){
      itrue = 'M512 512m-292.571429 0a4 4 0 1 0 585.142857 0 4 4 0 1 0-585.142857 0ZM512 1024c-285.257143 0-512-226.742857-512-512 0-285.257143 226.742857-512 512-512s512 226.742857 512 512C1024 797.257143 797.257143 1024 512 1024zM512 73.142857C270.628571 73.142857 73.142857 270.628571 73.142857 512c0 241.371429 197.485714 438.857143 438.857143 438.857143s438.857143-197.485714 438.857143-438.857143C950.857143 270.628571 753.371429 73.142857 512 73.142857z';
      ifalse = 'M512 0C229.2 0 0 229.2 0 512c0 282.8 229.2 512 512 512 282.8 0 512-229.2 512-512C1024 229.2 794.8 0 512 0zM512 960C264.6 960 64 759.4 64 512 64 264.6 264.6 64 512 64c247.4 0 448 200.6 448 448C960 759.4 759.4 960 512 960z';
    }

    $element.html(`
    <svg check-true style="display:none;float:left;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
        <path fill="currentColor" d="${itrue}" ></path>
    </svg>
    <svg check-false style="float:left;"  viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
        <path fill="currentColor" d="${ifalse}"></path>
    </svg>
    `);

    // 选中及非选中的状态样式
    $element[0].querySelector("[check-false]").style.color = $scope.blur || "";
    $element[0].querySelector("[check-true]").style.color = $scope.focus || $scope.blur;

    // 判断指令上是否设置选项为不可选
    if($attrs.disabled == "disabled" || $attrs.disabled=="true"){
        return false;
    }

    // 设置同组选项,以name方式分组
    let rname = $attrs.name || $scope.ngName || "radio";
        $element.attr("name","erd"+rname);
    let radioDoms = document.querySelectorAll("[name=erd"+rname+"][checked]"); //默认获取同组radio元素

    // if(radioDoms && radioDoms.length>0){
    //   $scope.ngModel = $scope.value || radioDoms[0].getAttribute("value");
    // }

    let ele = $element;
    // 判断在父层是否为LABEL,并为其添加事件
    if($element.parent()[0].tagName === "LABEL"){
        ele = $element.parent();
        ele.css({
          "display":"flex",
          "align-items":"center"
        })
    }

    // 如果没有绑定指令值则不执行以下代码
    if(!$attrs.ngModel) return false;

    ele.bind("click", function(e){
      //选项不可选
      if($attrs.disabled == "disabled" || $attrs.disabled=="true"){
          return false;
      }

      // 复选
      if(typeof $attrs.checkbox !== "undefined"){
        let self = this;
        $scope.$apply(function(){
          if( $scope.ngModel instanceof Array ===false ) $scope.ngModel = [];
          let value = $scope.value||$attrs.value;

          if( self.getAttribute("checked") == "checked" ){
            self.querySelector("[check-false]").style.display = "block";
            self.querySelector("[check-true]").style.display = "none";
            self.setAttribute("checked","");
            let arr = $scope.ngModel.reduce( (arr1,arr2)=>{
              if(arr2 != value)
                return arr1.concat(arr2);
              else
                return arr1
            }, []);

            $scope.ngModel = arr;
          }else{
            self.querySelector("[check-false]").style.display = "none";
            self.querySelector("[check-true]").style.display = "block";
            self.setAttribute("checked","checked");

            $scope.ngModel.push(value);
          }
          
        })
        return false;
      }

      // 单选
      Array.from(document.querySelectorAll("[name=erd"+rname+"]"), (v,k)=>{
        v.querySelector("[check-false]").style.display = "block";
        v.querySelector("[check-true]").style.display = "none";
      })
      this.querySelector("[check-false]").style.display = "none";
      this.querySelector("[check-true]").style.display = "block";
      // 主动更新
      $scope.$apply(function(){
        $scope.ngModel = $scope.value || $attrs.value;
      })
    })
}]

angular.module("eenRadio",[])
  .directive("eenRadio",function(){
      return {
          restrict:"EA",
          replace:true,
          scope:{
            ngModel:"=",
            value:"=ngValue", //如果是ng变量请用ng-value
            ngName:"=", //如是是ng变量请用ng-name
            focus:"@focusColor",
            blur:"@blurColor",
          },
          require: 'ngModel',
          template:'<div></div>',
          controller:_controller,
      }
  })

执行效果
效果图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容