五星评分功能插件的原理及代码实现 您所在的位置:网站首页 jquery星级评分实验原理 五星评分功能插件的原理及代码实现

五星评分功能插件的原理及代码实现

2023-11-12 17:08| 来源: 网络整理| 查看: 265

stars.png 星级评分功能插件的实现原理:

原理分析 HTML{ ul.rating#rating>li.rating-item*5 }

CSS { 两张背景图片(点亮的星星/灰色的星星) }

JS行为 {

遍历所有的星星,在循环中去点亮指定位置的星星,熄灭剩余星星 mouseover事件:{ 鼠标移入的时候mouseover(遍历所有的星星颗数){ click事件: 点亮指定星星 } } mouseout事件:{ 鼠标离开的时候mouseoout(遍历所有的星星颗数){ 熄灭剩余星星 } }

}

代码实现: var num =2, //初始化默认点亮星星颗数 $rating = $('#rating'), $item = $rating.find(".rating-item"); //点亮星星 var lightOn = function (num) { $item.each(function (index) { if(index < num) { $(this).css('background-position', '-46px -10px'); //亮星星 }else { $(this).css('background-position', '-10px -10px'); //灰星星 } }); }; lightOn(num); //初始化函数 //事件绑定 $item.on('mouseover', function () {//鼠标移入时 lightOn($(this).index() + 1); //点亮当前指定的星星颗数 }).on('click', function () {//点击鼠标 num = $(this).index() + 1; //获取当前星星的索引值 }); $rating.on('mouseout', function () {//鼠标移出时 要在父容器上绑定mouseout lightOn(num); //因为上一步里num值已经改变 }); 但是,以上这段代码有问题: 1. 暴露的全局变量太多,不利于代码拓展

解决办法1:独立命名空间。 解决办法2: 立即执行的匿名函数的写法(function(){})(), 使得我们的变量变成局部作用域。

2. 事件绑定的写法是为每一颗星星都绑定了每一次事件,这样会造成事件浪费。 3. 事件无法复用。 针对以上发现的问题,对JS代码进行改进: body, ul , li { margin: 0; padding: 0; } li { list-style: none; } .rating { width: 130px; height: 26px; margin: 100px auto; } .rating-item { float: left; width: 26px; height: 26px; background: url("img/css_sprites.png") no-repeat; cursor: pointer; } var rating = (function () { //点亮星星 var lightOn = function ($item, num) { $item.each(function (index) { if(index < num) { $(this).css('background-position', '-46px -10px'); //亮星星 }else { $(this).css('background-position', '-10px -10px'); //灰星星 } }); }; //让函数可复用 var init = function (el, num) { var $rating = $(el), //可复用:将这里变成通过外界传递进来的参数 $item = $rating.find(".rating-item"); lightOn($item, num); //初始化函数 //事件委托 $rating.on('mouseover', '.rating-item', function () {//鼠标移入时 lightOn($item, $(this).index() + 1); //点亮当前指定的星星颗数 }).on('click', '.rating-item', function () {//点击鼠标 num = $(this).index() + 1; //获取当前星星的索引值 }).on('mouseout', function () {//鼠标移出时 lightOn($item, num); //因为上一步里num值已经改变 }); }; //生成 jQuery 插件 $.fn.extend({ rating: function (num) { return this.each(function () { init(this, num); }) } }); return {//返回一个对象 init: init //对象de方法 }; })(); //复用 rating.init('#rating1', 1); rating.init('#rating2', 3); //调用jQuery 插件 $('#rating').rating(2); 以为到此就算圆满的话,那就太幼稚了,试想一下,一两个月后,产品经理会告诉你:"我们需要增加新功能,比如用户可以选中半颗星...."。 好吧,那只能继续改改改...... 这里就有引出一个设计模式,那就是【开放封闭原则】:即对拓展是开放的,而对修改是封闭的:

改写JS:

var rating = (function () { //点亮整颗星 var LightEntire = function (el, options) { this.$el = $(el); this.$item = this. $el.find('.rating-item'); this.opts = options; }; LightEntire.prototype.init = function () { this.lightOn(this.opts.num); if (!this.opts.readOnly){ this.bindEvent(); } }; LightEntire.prototype.lightOn = function (num) { num = parseInt(num); this.$item.each(function (index) { if (index < num) { $(this).css('background-position', '-46px -10px'); //亮星星 } else { $(this).css('background-position', '-10px -10px'); //灰星星 } }); }; LightEntire.prototype.bindEvent = function () { var self = this, itemLength = self.$item.length; self.$el.on('mouseover', '.rating-item', function () { var num = $(this).index() + 1; self.lightOn(num); (typeof self.opts.select === 'function') && self.opts.select.call(self.opts.num, itemLength); //判断/改变this指向 //触发事件 self.$el.trigger('select', [self.opts.num, itemLength]); }).on('click', '.rating-item', function () { self.opts.num = $(this).index() + 1; (typeof self.opts.chosen === 'function') && self.opts.chosen.call(self.opts.num, itemLength); //判断/改变this指向 //触发事件 self.$el.trigger('chosen', [self.opts.num, itemLength]); }).on('mouseout', function () { self.lightOn(self.opts.num); }); }; //默认参数 var defaults = { num: 0, readOnly: false, select: function () { }, chosen: function () { } }; //初始化 var init = function (el, options) { options = $.extend({}, defaults, options); new LightEntire(el, options).init(); }; return { init: init }; })(); rating.init('#rating', { num: 1, select: function (num, total) { console.log(this); console.log(num + '/' + total); //打印当前第几颗/总共多少颗星 } }); $('#rating').on('select', function (e, num , total) { console.log(num + '/' + total); }).on('chosen', function (e, num , total) { console.log(num + '/' + total); }) 代码拓展:点亮半颗星功能

原理分析: 利用mousemove e.pageX $().offset().left e.pageX - $().offset().left $().width()/2

var rating = (function () { //点亮整颗星 var LightEntire = function (el, options) { this.$el = $(el); this.$item = this. $el.find('.rating-item'); this.opts = options; }; LightEntire.prototype.init = function () { this.lightOn(this.opts.num); if (!this.opts.readOnly){ this.bindEvent(); } }; LightEntire.prototype.lightOn = function (num) { num = parseInt(num); this.$item.each(function (index) { if (index < num) { $(this).css('background-position', '-46px -10px'); //亮星星 } else { $(this).css('background-position', '-10px -10px'); //灰星星 } }); }; LightEntire.prototype.bindEvent = function () { var self = this, itemLength = self.$item.length; self.$el.on('mouseover', '.rating-item', function () { var num = $(this).index() + 1; self.lightOn(num); (typeof self.opts.select === 'function') && self.opts.select.call(self.opts.num, itemLength); //判断/改变this指向 //触发事件 self.$el.trigger('select', [self.opts.num, itemLength]); }).on('click', '.rating-item', function () { self.opts.num = $(this).index() + 1; (typeof self.opts.chosen === 'function') && self.opts.chosen.call(self.opts.num, itemLength); //判断/改变this指向 //触发事件 self.$el.trigger('chosen', [self.opts.num, itemLength]); }).on('mouseout', function () { self.lightOn(self.opts.num); }); }; //点亮半颗星星 var LightHalf = function (el, options) { this.$el = $(el); this.$item = this. $el.find('.rating-item'); this.opts = options; this.add = 1; }; LightHalf.prototype.init = function () { this.lightOn(this.opts.num); if (!this.opts.readOnly){ this.bindEvent(); } }; LightHalf.prototype.lightOn = function (num) { var count = parseInt(num), isHalf = count !== num; //判断是不是小数 this.$item.each(function (index) { if (index < count) { $(this).css('background-position', '-46px -10px'); //亮星星 } else { $(this).css('background-position', '-10px -10px'); //灰星星 } }); if(isHalf) { this.$item.eq(count).css('background-position', '-10px -46px'); } }; LightHalf.prototype.bindEvent = function () { var self = this, itemLength = self.$item.length; self.$el.on('mousemove', '.rating-item', function (e) { var $this = $(this), num = 0; if (e.pageX - $this.offset().left < $this.width() / 2) {//判断是否半颗星 self.add = 0.5; } else {//整颗星 self.add = 1; } num = $this.index() + self.add; self.lightOn(num); (typeof self.opts.select === 'function') && self.opts.select.call(self.opts.num, itemLength); //判断/改变this指向 //触发事件 self.$el.trigger('select', [self.opts.num, itemLength]); }).on('click', '.rating-item', function () { self.opts.num = $(this).index() + self.add; (typeof self.opts.chosen === 'function') && self.opts.chosen.call(self.opts.num, itemLength); //判断/改变this指向 //触发事件 self.$el.trigger('chosen', [self.opts.num, itemLength]); }).on('mouseout', function () { self.lightOn(self.opts.num); }); }; //默认参数 var defaults = { mode: 'LightEntire', num: 0, readOnly: false, select: function () {}, chosen: function () {} }; var mode = { 'LightEntire': LightEntire, 'LightHalf': LightHalf }; //初始化 var init = function (el, options) { options = $.extend({}, defaults, options); if (!mode[options.mode]){ options.mode = 'LightEntire'; }; // new LightEntire(el, options).init(); // new LightHalf(el, options).init(); new mode[options.mode](el, options).init(); }; return { init: init }; })(); rating.init('#rating', { mode: 'LightHalf', num: 2.5, select: function (num, total) { console.log(this); console.log(num + '/' + total); //打印当前第几颗/总共多少颗星 } }); 最后,抽象出父类: var rating = (function () { //继承 var extend = function (subClass, superClass) { var F = function () {}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; }; //抽象父类 var Light = function (el, options) { this.$el = $(el); this.$item = this. $el.find('.rating-item'); this.opts = options; this.add = 1; this.selectEvent = 'mouseover'; }; Light.prototype.init = function () { this.lightOn(this.opts.num); if (!this.opts.readOnly){ this.bindEvent(); } }; Light.prototype.lightOn = function (num) { num = parseInt(num); this.$item.each(function (index) { if (index < num) { $(this).css('background-position', '-46px -10px'); //亮星星 } else { $(this).css('background-position', '-10px -10px'); //灰星星 } }); }; Light.prototype.bindEvent = function () { var self = this, itemLength = self.$item.length; self.$el.on(self.selectEvent, '.rating-item', function (e) { var $this = $(this), num = 0; self.select(e, $this); num = $(this).index() + self.add; self.lightOn(num); (typeof self.opts.select === 'function') && self.opts.select.call(self.opts.num, itemLength); //判断/改变this指向 //触发事件 self.$el.trigger('select', [self.opts.num, itemLength]); }).on('click', '.rating-item', function () { self.opts.num = $(this).index() + self.add; (typeof self.opts.chosen === 'function') && self.opts.chosen.call(self.opts.num, itemLength); //判断/改变this指向 //触发事件 self.$el.trigger('chosen', [self.opts.num, itemLength]); }).on('mouseout', function () { self.lightOn(self.opts.num); }); }; Light.prototype.select = function () { throw new Error('子类必须重写方法'); }; //点亮整颗星 var LightEntire = function (el, options) { Light.call(this, el, options); this.selectEvent = 'mouseover'; }; extend(LightEntire, Light); LightEntire.prototype.lightOn = function (num) { Light.prototype.lightOn.call(this, num); }; LightEntire.prototype.select = function () { self.add = 1; }; //点亮半颗星星 var LightHalf = function (el, options) { Light.call(this, el, options); this.selectEvent = 'mousemove'; }; extend(LightHalf, Light); LightHalf.prototype.lightOn = function (num) { var count = parseInt(num), isHalf = count !== num; //判断是不是小数 Light.prototype.lightOn.call(this, count); if(isHalf) { this.$item.eq(count).css('background-position', '-10px -46px'); } }; LightHalf.prototype.select = function (e, $this) { if (e.pageX - $this.offset().left < $this.width() / 2) {//判断是否半颗星--> this.add = 0.5; } else {//整颗星 this.add = 1; } } //默认参数 var defaults = { mode: 'LightEntire', num: 0, readOnly: false, select: function () {}, chosen: function () {} }; var mode = { 'LightEntire': LightEntire, 'LightHalf': LightHalf }; //初始化 var init = function (el, options) { options = $.extend({}, defaults, options); if (!mode[options.mode]){ options.mode = 'LightEntire'; }; // new LightEntire(el, options).init(); // new LightHalf(el, options).init(); new mode[options.mode](el, options).init(); }; return { init: init }; })(); rating.init('#rating', { mode: 'LightHalf', num: 2.5, select: function (num, total) { console.log(this); console.log(num + '/' + total); //打印当前第几颗/总共多少颗星 } }); 然鹅,问题又来了,正常情况下,用户点选好星星后,选中结果就会发送出去,用户就不能再继续点选其他剩余几颗星星的, 所以,以上代码依然不够满足业务场景,继续修改: var rating = (function () { //继承 var extend = function (subClass, superClass) { var F = function () {}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; }; //抽象父类 var Light = function (el, options) { this.$el = $(el); this.$item = this. $el.find('.rating-item'); this.opts = options; this.add = 1; this.selectEvent = 'mouseover'; }; Light.prototype.init = function () { this.lightOn(this.opts.num); if (!this.opts.readOnly){ this.bindEvent(); } }; Light.prototype.lightOn = function (num) { num = parseInt(num); this.$item.each(function (index) { if (index < num) { $(this).css('background-position', '-46px -10px'); //亮星星 } else { $(this).css('background-position', '-10px -10px'); //灰星星 } }); }; Light.prototype.bindEvent = function () { var self = this, itemLength = self.$item.length; self.$el.on(self.selectEvent, '.rating-item', function (e) { var $this = $(this), num = 0; self.select(e, $this); num = $(this).index() + self.add; self.lightOn(num); (typeof self.opts.select === 'function') && self.opts.select.call(self.opts.num, itemLength); //判断/改变this指向 //触发事件 self.$el.trigger('select', [self.opts.num, itemLength]); }).on('click', '.rating-item', function () { self.opts.num = $(this).index() + self.add; (typeof self.opts.chosen === 'function') && self.opts.chosen.call(self.opts.num, itemLength); //判断/改变this指向 //触发事件 self.$el.trigger('chosen', [self.opts.num, itemLength]); }).on('mouseout', function () { self.lightOn(self.opts.num); }); }; Light.prototype.select = function () { throw new Error('子类必须重写方法'); }; Light.prototype.unbindEvent = function () { this.$el.off(); }; //点亮整颗星 var LightEntire = function (el, options) { Light.call(this, el, options); this.selectEvent = 'mouseover'; }; extend(LightEntire, Light); LightEntire.prototype.lightOn = function (num) { Light.prototype.lightOn.call(this, num); }; LightEntire.prototype.select = function () { self.add = 1; }; //点亮半颗星星 var LightHalf = function (el, options) { Light.call(this, el, options); this.selectEvent = 'mousemove'; }; extend(LightHalf, Light); LightHalf.prototype.lightOn = function (num) { var count = parseInt(num), isHalf = count !== num; //判断是不是小数 Light.prototype.lightOn.call(this, count); if(isHalf) { this.$item.eq(count).css('background-position', '-10px -46px'); } }; LightHalf.prototype.select = function (e, $this) { if (e.pageX - $this.offset().left < $this.width() / 2) {//判断是否半颗星--> this.add = 0.5; } else {//整颗星 this.add = 1; } } //默认参数 var defaults = { mode: 'LightEntire', num: 0, readOnly: false, select: function () {}, chosen: function () {} }; var mode = { 'LightEntire': LightEntire, 'LightHalf': LightHalf }; //初始化 var init = function (el, option) {//option 可支持字符串 var $el = $(el), rating = $el.data('rating'), options = $.extend({}, defaults, typeof option === 'object' && option); if (!mode[options.mode]){ options.mode = 'LightEntire'; }; // new LightEntire(el, options).init(); // new LightHalf(el, options).init(); if(!rating) { $el.data('rating', (rating = new mode[options.mode](el, options))); rating.init(); } if(typeof option === 'string')rating[option](); }; //jQuery 插件 $.fn.extend({ rating: function (option) { return this.each(function () { init(this, option); }); } }); return { init: init }; })(); //用jQ的方式调用 $('#rating').rating({ mode: 'LightEntire', num: 2 }); $('#rating1').rating({ mode: 'LightHalf', num: 3.5 }).on('chosen', function () { $('#rating1').rating('unbindEvent'); }); // rating.init('#rating', { // mode: 'LightHalf', // num: 2.5, // // select: function (num, total) { // // console.log(this); // // console.log(num + '/' + total); //打印当前第几颗/总共多少颗星 // // }, // chosen: function () { // rating.init('#rating', 'unbindEvent'); // } // });

点击查看预览效果



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有