我受这个主题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/
radio inputs
始终触发点击事件,而不仅仅是在
更改为第二个radio input
。 Confirm
复选框在加载时被隐藏。预期行为:
Unsubscribe radio
将启用Send
按钮并隐藏Confirm checkbox
。Subscribe radio
和Confirm checkbox
将一起启用Send
按钮。Subscribe radio
或“确认复选框”(如果仅选中一个)Send
按钮将被禁用。