这几种封装方案哪种才是最佳实践?~

发布于 2022-09-05 04:44:26 字数 2004 浏览 51 评论 0

最初状态:

var searchMain = $('.c-search_search'), // 搜索本体
    searchBtn = $('.c-search_searchBtn'), // 取消按钮
    searchIcon = $('.weui_icon_search'); // 搜索图标
    
if (searchMain.val()) {
    searchIcon.addClass('weui_icon_search-focus');
}

searchMain.on('focus', function () {
    searchBtn.show();
    searchIcon.addClass('weui_icon_search-focus');
}).on('blur', function () {
    if (!this.value) {
        searchBtn.hide();
        searchIcon.removeClass('weui_icon_search-focus');
    }
});

1.显然重复最多的是 weui_icon_search-focus 这个类名 那么提出来存变量会不会好一些 万一要修改的话修改一处就好

var searchMain = $('.c-search_search'), // 搜索本体
    searchBtn = $('.c-search_searchBtn'), // 取消按钮
    searchIcon = $('.weui_icon_search'), // 搜索图标
    searchIconFocus = 'weui_icon_search-focus';
    
if (searchMain.val()) {
    searchIcon.addClass(searchIconFocus);
}

searchMain.on('focus', function () {
    searchBtn.show();
    searchIcon.addClass(searchIconFocus);
}).on('blur', function () {
    if (!this.value) {
        searchBtn.hide();
        searchIcon.removeClass(searchIconFocus);
    }
});

2.focus blur 这两个事件其实操作的行为差不多相同 那么需不需要封装 这样的话还可以顺便解决 weui_icon_search-focus 多处写的问题

var searchMain = $('.c-search_search'), // 搜索本体
    searchBtn = $('.c-search_searchBtn'), // 取消按钮
    searchIcon = $('.weui_icon_search'), // 搜索图标
    searchIconFocus = 'weui_icon_search-focus';
    
if (searchMain.val()) {
    searchIcon.addClass(searchIconFocus);
}

searchMain.on('focus', function () {
    fn();
}).on('blur', function () {
    if (!this.value) {
        fn(true);
    }
});

function fn(a) {
    searchBtn[ a ? 'hide' : 'show' ]();
    searchIcon[ a ? 'removeClass' : 'addClass' ]('weui_icon_search-focus');
}

但是 if (searchMain.val()) 这句判断的那个位置的操作就没办法了 我觉得它也应该和 fn 在一起吧 毕竟它和其中的一条行为是一样的 这样的话要改又要改两次了 虽然可以给 fn 加个参数让其只执行第二句 但这样做我总觉得不爽啊 如果正常执行的话还要经过那一层判断~

各位还有什么完美的解决办法不了?~

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

删除会话 2022-09-12 04:44:26

你这就有点为了封装而封装了,一个函数最好只干一件事情。

hide跟show你还可以用一个toggle封装在一起,但是普通的addClass显然就和这个功能有差别了。

你这里本来就只要一句命令就够了,非得封装在一起毫无意义。而且如果这时你又有一个类似的需求,难道你又要在你封装的函数里再加一个判断吗?

你这里封装函数的目的是增强可读性,可是盲目把类似功能都封装在一起就是南辕北辙了。

π浅易 2022-09-12 04:44:26

题主想要封装的想法非常好。只是个人感觉思路有些局限。既然要封装,为什么不直接封装一个搜索框?

通过组件化思维来思考的话,直接封装一个搜索框就是最佳实践。我的意思就是,封装一个组件,以达到复用的目的。

只需要做一些小小的优化,就可以把你的代码变得很好。

// 所有需要的变量都在options中传入即可。
function searchComponent(options) {
    var searchMain = $(options.searchMain), // 搜索本体
        searchBtn = $(options.searchBtn), // 取消按钮
        searchIcon = $(options.searchIcon); // 搜索图标
        
    if (searchMain.val()) {
        searchIcon.addClass(options.iconFocus);
    }

    searchMain.on('focus', function () {
        searchBtn.show();
        searchIcon.addClass(options.iconFocus);
    }).on('blur', function () {
        if (!this.value) {
            searchBtn.hide();
            searchIcon.removeClass(options.iconFocus);
        }
    });
}

但是肯定还有优化的空间,比如searchBtn searchIcon的获取,可以通过父元素取子元素的方式找到。这样就只用传入一个父级的class名字进来就行了。

你做的几个封装,确实是代码量太小了,真没有进一步封装的必要。但是如果逻辑稍微复杂一点,或者你希望自己的代码稍微漂亮一点的话,你还可以这样写。

因为对jquery忘得差不多了,所以用原生实现,也建议在不需要过多的考虑兼容性的前提下多多使用原生JavaScript

function searchComponent(options) {
    var searchWrap = document.querySelector(options.el),
        searchWrapChildren = searchWrap.children,

        // 我这随便写的,需要根据实际情况获取
        searchMain = searchWrapChildren[0], // 搜索本体
        searchBtn = searchWrapChildren[1], // 取消按钮
        searchIcon = searchWrapChildren[2], // 搜索图标

        focus = function() {
            // 这里的隐藏与否 与 是否给给searchIcon添加焦点样式可以写在同一个clss里,由父级来控制,假定已经写在了一起,这一句就可以不要了
            // searchBtn.show();
            searchWrap.classList.add(options.iconFocus);
        },
        blur = function() {
            if (!this.value) {
                // 同上
                // searchBtn.hide();
                searchWrap.classList.remove(options.iconFocus);
            }
        };

    if (searchMain.value) {
        searchWrap.classList.add(options.iconFocus);
    }

    searchMain.addEventListener('focus', focus, false);
    searchMain.addEventListener('blur', blur, false);
}

searchComponent({ el: '.search-wrap', iconFocus: 'weui_icon_search-focus' });
清晨说晚安 2022-09-12 04:44:26

想不出有更好的办法,个人觉得变量为jquery对象可以加上$以便区分

var $searchMain = $('.c-search_search'), // 搜索本体

$searchBtn = $('.c-search_searchBtn'), // 取消按钮
$searchIcon = $('.weui_icon_search'), // 搜索图标
searchIconFocus = 'weui_icon_search-focus';

if ($searchMain.val()) {

fn(false,false);

}

$searchMain.on('focus', function () {

fn();

}).on('blur', function () {

if (!this.value) {
    fn(true);
}

});

function fn(a,mark) {

$searchIcon[ a ? 'removeClass' : 'addClass' ](searchIconFocus);
if(mark || true){
    $searchBtn[ a ? 'hide' : 'show' ]();
}

}

沫离伤花 2022-09-12 04:44:26

赞同楼上答案。

你的需求就是获取焦点时,显示一个元素,并给另一个元素添加一个类。失去焦点则相反。

那么你的实现应该是

// 通常jq对象命名前会加$,以便和dom对象区分。
$el
    .on('focus',function(){
        // TODO
    })
    .on('blur',function(){
        // TODO
    });

逻辑清楚明了,为何要做无谓的封装?

一定要考虑简化的话,应该是从显示元素并给元素添加一个类的样式上来考虑。比如我在父元素上添加一个类show。 来使用css中的子选择器完成你对元素显示隐藏样式切换的问题。

/* 父元素 */
.parent {
    
}
/* 两个子元素 */
.child1 {
    /* 默认将其隐藏 */
    display: hidden;
}
.child2 {
    /* 写入不受weui_icon_search-focus类影响的样式 */
}

.parent.show .child1 {
    /* show状态下的child1需要显示出来 */
    display: block;
}
.parent.show .child2 {
    /* show状态时 child2 样式改变 */
    /* 写入weui_icon_search-focus类下的样式 */
}

这样就只用在focus时给.parent这个元素添加show样式,blur时移除即可。

旧梦荧光笔 2022-09-12 04:44:26

虽然问题有点远 但是也是最近在学习的所以分享一下自己的见解

在一个项目里js是占大头的 简单的可以分为下面几种
1.dom操作 也就是一些dom事件 比如click

2.ajax请求

3.method 封装的方法

基本上上述三个能涵盖绝大多数的js了 就像上面仁兄所说一个函数就做一个事情 而这里可以大方向的总结来说 一个对象只做一类事情
比如

var indexPage =(function(){
    //dom相关事件
    var domEvent = {
        nextBtnClick:function(){
            $(".nextBtn").on("click",function(){
                //....
                gainAjax.gainList();
            })
        },
        ...
        init:function(){
            domEvent.nextBtnClick()
        }
    }
    //ajax请求
    var gainAjax = {
        gainList:function(){
            $.ajax(...)
        }
    }
    
    //调用一些方法
    var method = {
        toggle:function(ele){
            ele.toggle();
        }
    }
    
    //导出对象
    var o = {
        init:function(){
            domEvent.init();
        }
    }
    return o;
})()

//初始化
indexPage.init()
温柔戏命师 2022-09-12 04:44:26

我猜你是希望把修改元素class的功能集中封装到一起,然后在各个需要调用的节点去调用,伪码大概是这样:

setClass();//初始执行

searchMain.on('focus', setClass).on('blur', setClass);//用户操作触发执行

function setClass(){
    //处理各种情况
}

我挺喜欢这种做法的,但具体到你这个例子不太合适,因为setClass()这个函数无论什么时候执行,里面的判断条件都得走一圈,而且有的判断还涉及DOM取值,代码量是减少了,但性能下降了;另一个问题是这个集中处理函数的可读性势必会降低,但具体到你这个例子我觉得无所谓,毕竟也没多少行。

我个人认为,如果封装的结果只是开发者舒服了但影响了程序执行效率,那这就是一个失败的封装,所以我建议你只做到你自己给出的第一段优化代码就可以了,真正能让这件事做的更省心的是Vue这种东西。

鹿港小镇 2022-09-12 04:44:26

封装的目的大致有以下几个:1. 复用;2. 解耦;3.可维护。就楼主这样的写法,随着项目的深入,代码会爆表的,封装或重构都应该根据当前项目的业务和代码情况而定。以经手过的一个前端项目中的 dom 操作举例,其最终代码的样子如下:

var option = {
  el:'your-selector',
  bindType: 'your-bind-type'
  dataSource: data,
  ...other property
};
$ctrlBindHelper(option).bindData();

其中 $ctrlBindHelper 是一个全局策略工厂(工厂和策略模式的混合)类,其中工厂模式提供一个单一的外部接口,策略模式提供不同的dom绑定算法,就最外层的用户而言只需要构造一个option,然后调用一次工厂接口bindData()就完事。

  1. 复用:$ctrlBindHelper 保证了全项目中大多数(除一些特殊控件外)的控件绑定不用写第二遍

  2. 解耦:dom 的绑定方式是由 bindType 动态决定,就$ctrlBindHelper 内部而言,不同的bindType 对应的是独立算法策略,互不干涉

  3. 可维护性:看看代码的干净程度就知道了

------------------------我是分隔线------------------------------------

评论区无法回复,下面就评论里楼主提到的问题做一些解释。

以上代码中 option 不是一个全局变量(上面是为了演示就直接var出来了),是构造函数参数。
数据源是通过 option 动态传入,dom 绑定的实现在 $ctrlBindHelper 中完成。例如,要对list 和 select 进行绑定可以做如下操作:(这里仅仅是以 list 和 select 为例,具体项目中肯定不只这两个)


<ul id='ls'></ul>
<select id='sel'></select>

/**
* 以下js伪码演示 id 为 lsA 的 ul绑定数据,并为其子元素绑定点击事件
*/
var listSource = [1,2,3,4];
var callBak = function(e){
    //when li/option element clicked do
};

/**
* option 为构造函数参数 (不是全局变量)
*/
var optionA = {
    el:'#ls',
    bindType:'listBind', //动态选择绑定策略
    dataSource: listSource,
    selFunc: callBak 
};


var optionB = {
    el:'#sel',
    bindType:'selectBind', //动态选择绑定策略
    dataSource: listSource,
    selFunc: callBak 
}

$ctrlBindHelper([optionA,optionB]).bindAll(); //完成绑定 

假设,现在项目中另外一个list 或者 select 需要绑定数据,用户需要做的只是传入指定格式的option,然后调一次 bindData()方法,就可以产生一个项目中统一的select 或者list,至于怎么绑定的用户不需要知道,也不需要再去手写一次绑定过程。这样也就实现了对 select 和 list 的绑定过程的封装和复用。

事务逻辑的处理方式和位置,需要根据项目和代码的实际情况来定,没法一概而论(这里的伪码是采用的传入回调函数的方式,可能在其他地方并不适用)。因地制宜即可。

不知道以上解释是否足够详尽,欢迎探讨拍砖

江湖正好 2022-09-12 04:44:26

我赞同 依韵_宵音 的答案,样式变化应由 css 控制
我的代码大致如 雅X共赏 的结构

看你的代码,我想需求应该是这样:

  • focus | 有值: search 激活

  • blur & 无值: search 取消激活

var searchMain = $('.c-search_search'), // 搜索本体
    searchBtn = $('.c-search_searchBtn'), // 取消按钮
    searchIcon = $('.weui_icon_search'); // 搜索图标

updateSearchState();   
searchMain.on({
    focus: updateSearchState,
    blur:  updateSearchState
});

function updateSearchState(e){
     var isFocus = e && e.type == "focus",
         isValue = searchMain.val;
         
    isFocus || isValue()
        ? searchIcon.addClass('weui_icon_search-focus'),
        : searchIcon.removeClass('weui_icon_search-focus');
        
    isFocus
        ? searchBtn.show()
        : searchBtn.hide();
        
    return;
}

active 可以操作搜索框父元素,增加/移除 class ,以使用 css 控制其样式


不清楚你 searchBtn 最开始是否是显示的,如果是显示的,那么不需要再单独判断。如果不是显示的,那么按照你原来的代码,假设 input 一开始有值,先 focus 再 blur 之后按钮显示出来后不会消失,这很奇怪。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文