根据依赖性显示/隐藏元素

时间:2018-10-24 12:11:03

标签: javascript html

我受这个主题Show/Hide form fields based on value of other fields的启发,不仅对部分主题进行了一些更改。 这是示例:

var ObserverPlugin = (function(){
    // here will be stored every DOM object which has
    // data-observe attr and data-name attr (data-name will be served
    //  as a key , which will store another object with a reference to the DOM object
    //  how many object does it observe)
    var observers = {},
        publishers = [];

    var _setStylesheet = (function() {
        // Create the <style> tag
        var style = document.createElement("style");
        // Add a media (and/or media query) here if you'd like!
        // style.setAttribute("media", "screen")
        // style.setAttribute("media", "only screen and (max-width : 1024px)")

        // WebKit hack :(
        style.appendChild(document.createTextNode(""));
        // Add the <style> element to the page
        document.head.appendChild(style);
        return style.sheet;
    })();

    // observer pattern & revealing module pattern
    var observer = (function(){
        var topics = {};

        var publish = function(topic, reference) {
            // if there is no topic on the publish call, well get out !
            if (!topics[topic]) {
                return false;
            }

            // self invoked funciton, which calls the function passed when
            // the topic was subscribed (if more then one function was published on the same topic
            // then call each one of them)
            (function(){
                var subscribers = topics[topic],
                    len = subscribers ? subscribers.length : 0;

                while (len--) {
                    subscribers[len].func(topic, reference);
                }
            })();
        };

        var subscribe = function(topic, func) {
            if (!topics[topic]) {
                topics[topic] = [];
            }

            topics[topic].push({
                func: func
            });
        };

        return {
            subscribe: subscribe,
            publish: publish,
            topics: topics
        }
    })();

    // creates random string, used to make data-name random for observers
    var _makeRandomString = function() {
        var text = "";
        var possible = "abcdefghijklmnopqrstuvwxyz0123456789";

        for( var i=0; i < 5; i++ ) {
            text += possible.charAt(Math.floor(Math.random() * possible.length));
        }

        return text;
    };

    // verifies if eleme existis in array, if not, returns false
    var _isInside = function( elem, array ) {
        return array.indexOf(elem) > -1;
    };

    // topic is the topic
    // reference is a reference to the DOM object clicked
    var _observerFunction = function(topic, reference) {
        var number = reference.attr('data-publish-value');
        var topics = topic.toString().split(' ');
        var length = topics.length;
        //var display;
        for( var key in observers ) {
            for( var i = 0; i < length; i +=1 ) {
                if( _isInside( topics[i], observers[key].topicsObserved ) ) {
                    // it exists
                    observers[key].sum += Number(number);
                    // 'number' is a string, so we have to convert it back to number
                }
            }
            if( observers[key].sum === 1 ) {
                // it is 0, so show that goddam DOM obj ! :))
                // again, put here 'var' for clarity
                // does not affect the code
                //display = 'block';
                _changeProperty(key,observers[key].property,1);
            }
            else {
                // it is not 0, so hide it
                //display = 'none';
                _changeProperty(key,observers[key].property,0);
            }
            //observers[key].reference.css('display', display);
        }
        // change value to -1 or 1
        if( number === '-1' ) {
            reference.attr('data-publish-value', '1');
        }
        else {
            reference.attr('data-publish-value', '-1');
        }
    };

    /*
    *   lets say we have 3 DOM objects with data-publish="1"
        and 2 DOM objects with data-publish="2"
        and one with data-observe="1 2";
        so data-observe has to be called 5 times in order for him to be shown on the page;

        each DOM object with data-publish will be added at runtime a data-value attribute
        which will be -1 or 1. each time it is clicked or changed, it changes to the opposite.
        this serves as data-observes will have a property named sum, which will be in the previous case 5
        5 gets calculated with -1, or 1 when clicked data-publish DOM object.

        So if i click first at data-publish="1" , 5 becomes 4. if i click again the same data-publish, becomes 5.

        when sum property becomes 0, the data-observe is shown.

        this function calculates how many data-publish="1" exists and so on
        (it also does the other stuff needed for publishers)
    */
    var _managePublishers = function() {
        $('[data-publish]').each(function(){
            var el = $(this);
            // adds that value data, remember it? :D
            el.attr('data-publish-value', '-1');
            // trim in case data-publish = "1 2 3" and store in an array
            var publisher = el.data('publish').toString();
            // we subscripe 'publisher' topic, but we check each string in topic
            // here is tricky. if one publishers has more than one topic inside data-publish
            // then we subscribe topic, but we check for topic's substring in publishers
            var topics = publisher.split(' ');
            if( !observer.topics[publisher] ) {
                // we subscribe data-publish topic, becouse when we click it we want to fire something, no?
                observer.subscribe( publisher, _observerFunction );
            }
            // but here in publishers we add only the substrings
            for( var key in topics ) {
                if( publishers[topics[key]] ) {
                    // the publisher exists
                    publishers[topics[key]] += 1;
                }
                else {
                    // the publisher doesn't exist
                    publishers[topics[key]] = 1;
                }
            }
        });
    };

    // gets the observers, calculates sum, caches their reference
    var _manageObservers = function() {
        $('[data-observe]').each(function(){
            var el = $(this);
            // create random data-name
            el.attr('data-observe-name', _makeRandomString());
            var datas = el.data('observe').toString().split(' '); // make an array again if we have multiple attachments
            observers[el.data('observe-name')] = (function(){
                var sum = (function(){
                    var sum2 = 0;
                    // if datas[key] is found in publishers array, add it to sum
                    for( var key in datas ) {
                        var temp = publishers[datas[key]];
                        if( temp ) {
                            sum2 += temp;
                        }
                    }
                    return sum2;
                })();
                var reference = el, topicsObserved = datas; // caching, so it is faster !

                // we need this when a user clicks data-publish, we need to see which DOM obj. are observing this.

                // i really like revealing module pattern...i got used to it
                return {
                    sum: sum,
                    reference: reference,
                    topicsObserved: topicsObserved,
                    property: $(reference).data('observe-property') //style-display[none/block],attr-disable/-,class-active/inactive
                }
            })();
        })
    };

    var _changeProperty = function(observer, property, status) {
        if(property === "style") {
            if(status === 1) {
                observers[observer].reference.css('display', 'block');
            }
            else {
                observers[observer].reference.css('display', 'none');
            }
        }
        else if(property === "attr") {
            if(status === 1) {
                $(observers[observer].reference).removeAttr('disabled');
            }
            else {
                $(observers[observer].reference).attr('disabled','disabled');
            }
        }
        else if(property === "class") {
            if(status === 1) {
                $(observers[observer].reference).removeClass('inactive');
            }
            else {
                $(observers[observer].reference).addClass('inactive');
            }
        }
    };

    var init = function() {
        _managePublishers();
        _manageObservers();
        $('[data-publish]:not(select)').on( 'click', function(){
            observer.publish( $(this).data('publish'), $(this) );
        });
        $('select[data-publish]').on('change', function(){
            var cache = $(this);
            // if in this select there is an option which has value 1(there is chance that it triggered a succesfull publish) we publish that too
            //observer.publish( cache.find('[data-value="1"]').data('publish'),  cache.find('[data-value="1"]') );
            var el = cache.find(':selected');
            observer.publish( el.data('publish'), el );
        });
        $('[data-publish]').each( function() {
            if(this.type !== 'radio' || this.type !== 'checkbox' || this.nodeName !== 'SELECT') {
                observer.publish( $(this).data('publish'), $(this) );
            }
        });

        // when observers[xx].sum is 0 it must be activated always, otherwise it is always invisible
        $.each( observers, function( key, value ) {
            if(value.topicsObserved) {
                $.each( value.topicsObserved, function( key2, value2 ) {
                    if(!publishers.hasOwnProperty(value2)) {
                        $(value.reference).css('display', 'block');
                        return;
                    }
                    if(value.property === "style") {
                        _setStylesheet.insertRule('[data-observe-name="'+key+'"] {display: none;}', _setStylesheet.rules.length);
                    }
                    else if(value.property === "attr") {
                        $(value.reference).attr('disabled','disabled');
                        _setStylesheet.insertRule('[disabled] {cursor: not-allowed;}', _setStylesheet.rules.length);
                    }
                    else if(value.property === "class") {
                        $(value.reference).addClass('inactive');
                    }
                });
            }
        });
    };

    return {
        init: init,
        publish: observer.publish,
        subscribe: observer.subscribe
    }
})();
ObserverPlugin.init();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form method="post" name="form">
    <input type="text" name="text" value="">
    <div class="wraper">
        <label><input type="radio" name="typ" value="subscribe" checked data-publish="newslist" >Subscribe</label>
        <label><input type="radio" name="typ" value="unsubscribe" data-publish="unsubscribe" >Unsubscribe</label>
    </div>
    <div class="wraper">
        <button type="submit" name="subscription" value="1" data-observe="newslist" data-observe-property="attr" >
            <span>Send</span>
        </button>
    </div>
    <div data-observe="unsubscribe" data-observe-property="style">
        <label>
            <input type="checkbox" name="confirm" value="1" data-publish="newslist">
            <span>Confirm</span>
        </label>
    </div>
</form>

jsfiddler也在https://jsfiddle.net/ogxusLja/

  1. 问题在于,radio inputs始终触发点击事件,而不仅仅是在 更改为第二个radio input
  2. 另一个问题是Confirm     复选框在加载时被隐藏。

预期行为:

  1. 选择的Unsubscribe radio将启用Send按钮并隐藏Confirm checkbox
  2. 选择的Subscribe radioConfirm checkbox将一起启用Send按钮。
  3. 选中的Subscribe radio或“确认复选框”(如果仅选中一个)Send按钮将被禁用。

0 个答案:

没有答案