tvSysBtnBind.v2.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. (function (arr) {
  2. //remove();//兼容
  3. arr.forEach(function (item) {
  4. if (item.hasOwnProperty('remove')) {
  5. return;
  6. }
  7. Object.defineProperty(item, 'remove', {
  8. configurable: true,
  9. enumerable: true,
  10. writable: true,
  11. value: function remove() {
  12. this.parentNode.removeChild(this);
  13. }
  14. });
  15. });
  16. })([Element.prototype, CharacterData.prototype, DocumentType.prototype]);
  17. if (!("classList" in document.documentElement)) {
  18. Object.defineProperty(HTMLElement.prototype, 'classList', {
  19. get: function () {
  20. var self = this;
  21. function update(fn) {
  22. return function (value) {
  23. var classes = self.className.split(/\s+/g),
  24. index = classes.indexOf(value);
  25. fn(classes, index, value);
  26. self.className = classes.join(" ");
  27. }
  28. }
  29. return {
  30. add: update(function (classes, index, value) {
  31. if (!~index) classes.push(value);
  32. }),
  33. remove: update(function (classes, index) {
  34. if (~index) classes.splice(index, 1);
  35. }),
  36. toggle: update(function (classes, index, value) {
  37. if (~index)
  38. classes.splice(index, 1);
  39. else
  40. classes.push(value);
  41. }),
  42. contains: function (value) {
  43. return !!~self.className.split(/\s+/g).indexOf(value);
  44. },
  45. item: function (i) {
  46. return self.className.split(/\s+/g)[i] || null;
  47. }
  48. };
  49. }
  50. });
  51. }
  52. function fireKeyEvent(el, evtType, keyCode) {
  53. var doc = el.ownerDocument,
  54. win = doc.defaultView || doc.parentWindow,
  55. evtObj;
  56. if (doc.createEvent) {
  57. if (win.KeyEvent) {
  58. evtObj = doc.createEvent('KeyEvents');
  59. evtObj.initKeyEvent(evtType, true, true, win, false, false, false, false, keyCode, 0);
  60. } else {
  61. evtObj = doc.createEvent('UIEvents');
  62. Object.defineProperty(evtObj, 'keyCode', {
  63. get: function () {
  64. return this.keyCodeVal;
  65. }
  66. });
  67. Object.defineProperty(evtObj, 'which', {
  68. get: function () {
  69. return this.keyCodeVal;
  70. }
  71. });
  72. evtObj.initUIEvent(evtType, true, true, win, 1);
  73. evtObj.keyCodeVal = keyCode;
  74. if (evtObj.keyCode !== keyCode) {
  75. console.log("keyCode " + evtObj.keyCode + " 和 (" + evtObj.which + ") 不匹配");
  76. }
  77. }
  78. el.dispatchEvent(evtObj);
  79. } else if (doc.createEventObject) {
  80. evtObj = doc.createEventObject();
  81. evtObj.keyCode = keyCode;
  82. el.fireEvent('on' + evtType, evtObj);
  83. }
  84. }
  85. //classList兼容
  86. (function (window) {
  87. var tvSysBtnBind = function (init) {
  88. var _this = this,
  89. _self = self;
  90. var id = init.id ? init.id : null,
  91. keyRemoveDefault = init.keyRemoveDefault ? true : false,
  92. currentIndex = init.currentIndex ? parseInt(init.currentIndex): 0,
  93. btnLeft = init.btnLeft ? init.btnLeft : 37,
  94. btnUp = init.btnUp ? init.btnUp : 38,
  95. btnRight = init.btnRight ? init.btnRight : 39,
  96. btnDown = init.btnDown ? init.btnDown : 40,
  97. btnEnter = init.btnEnter ? init.btnEnter : 13,
  98. history = init.history ? init.history : true,
  99. currentClass = init.currentClass ? init.currentClass : "current",
  100. doc = id?document.getElementById(id):document.body,
  101. effect = init.effect ? init.effect : "slide1",
  102. element = new Array(),
  103. rules = Object.prototype.toString.call(init.rules) == '[object Object]' ? init.rules : null,
  104. direction = "y";
  105. _this.className = init.className ? init.className : "hotbutton";
  106. this.event = {};
  107. var _tempElem;
  108. this.currentIndex = parseInt(currentIndex);
  109. this.defaultIndex = parseInt(currentIndex);
  110. this.historyFocus={};
  111. if(!window.focusobj)window.focusobj=document.createElement("span");
  112. (typeof init.onLoad) == "function" ? init.onLoad: init.onLoad = function () {};
  113. this.onLoad = function () {
  114. _this.reLoad();
  115. this.sourceClassName = _this.className;
  116. this.sourceLength = element.length;
  117. //element[currentIndex].classList.add(currentClass);
  118. _this.prev = element[currentIndex];
  119. _this.prevIndex = currentIndex;
  120. _this.current = element[currentIndex];
  121. _this.currentIndex = currentIndex;
  122. _this.target = doc;
  123. init.onLoad.call(_this);
  124. focusobj.innerHTML='<div class="cssbk"><b class="lt"></b><b class="t"></b><b class="rt"></b><b class="r"></b><b class="rb"></b><b class="b"></b><b class="lb"></b> <b class="l"></b></div>';
  125. focusobj.classList.add("focusobj");
  126. focusobj.classList.add("current");
  127. this.target.appendChild(focusobj);
  128. }
  129. this.reSetClass = function (item, index) {
  130. //新组别 用于弹窗 不同组热键 API
  131. if(history) //记录开关
  132. _this.historyFocus[_this.className]=_this.currentIndex;//记录上一组焦点
  133. index = index ? index : 0;
  134. _this.prev.classList.remove(currentClass);
  135. _this.className = item;
  136. _this.prevIndex= _this.currentIndex=_this.historyFocus[item]?_this.historyFocus[item]:index;
  137. _this.reLoad();
  138. }
  139. self.readFn=function(){
  140. if((typeof init.onEnterPress) == "function"){
  141. init.onEnterPress
  142. }else{
  143. init.onEnterPress = function () {}
  144. }
  145. if((typeof init.onPress) == "function"){
  146. init.onPress
  147. }else{
  148. init.onPress = function () {}
  149. }
  150. }
  151. this.reLoad = function () {
  152. self.readFn();
  153. if (doc != null) {
  154. element = doc.getElementsByClassName(_this.className);
  155. this.hotbtn = element;
  156. }
  157. if (element.length <= 0) return false;
  158. if (_this.currentIndex || _this.currentIndex == 0) {
  159. _this.currentIndex = parseInt(_this.currentIndex);
  160. } else {
  161. _this.currentIndex = parseInt(init.currentIndex);
  162. }
  163. if (isload >= 2 && _this.sourceClass == _this.className && _this.sourceLength != element.length && !isSet) {
  164. //页面加载到接口加载不进行计算 重置class也不计算 手动设置焦点不算
  165. // 如果元素数量发生过变化 将进行换算当前元素 重新算元素索引
  166. //修复同组的元素变化的问题
  167. if (_this.prev.classList.contains(_this.className)&&_this.sourceLength > element.length) {
  168. //当元素减少
  169. _this.currentIndex = _this.currentIndex - (_this.sourceLength - element.length);
  170. _this.prevIndex = _this.prevIndex - (_this.sourceLength - element.length);
  171. _this.sourceLength = element.length;
  172. } else if (_this.prev.classList.contains(_this.className)&&_this.sourceLength < element.length) {
  173. //当元素增加
  174. _this.currentIndex = _this.currentIndex + (element.length - _this.sourceLength);
  175. _this.prevIndex = _this.prevIndex + (element.length - _this.sourceLength);
  176. _this.sourceLength = element.length;
  177. }
  178. }
  179. isSet = false;
  180. _this.prev = element[_this.currentIndex];
  181. _this.prevIndex = _this.currentIndex;
  182. _this.current = element[_this.currentIndex];
  183. _this.currentIndex = _this.currentIndex;
  184. _self.classDo(_this.currentIndex);
  185. for (var i = 0; i < this.hotbtn.length; i++) {
  186. this.hotbtn[i].setAttribute("data-id", i);
  187. }
  188. }
  189. function keydefault(e) {
  190. try{
  191. if (keyRemoveDefault) window.event ? window.event.returnValue = false : e.preventDefault();
  192. }catch(e){
  193. //不支持浏览器按键的时候会报错
  194. }
  195. }
  196. var isSet = false;
  197. this.setCurrentIndex = function (index) {
  198. isSet = true;
  199. index = parseInt(index);
  200. _this.currentIndex = index;
  201. _this.current = element[index];
  202. }
  203. this.viewScrollY = function (y) {
  204. if(y<0)y=0;
  205. _this.current.parentNode.style.top=-y+"px";
  206. _this.current.parentNode.style.left=0+"px";
  207. //view.scrollTop = view.scrollTop + y+(y*0.1);
  208. }
  209. this.viewScrollX = function (x) {
  210. if(x<0)x=0;
  211. _this.current.parentNode.style.left=-x+"px";
  212. _this.current.parentNode.style.top=0+"px";
  213. //view.scrollLeft = view.scrollLeft + x+(x*0.1);
  214. }
  215. this.onPress = function (e) {
  216. init.onPress.call(_this);
  217. }
  218. this.onEnterPress = function () {
  219. init.onEnterPress.call(_this);
  220. }
  221. self.getScrollTop = function () {
  222. var scrollTop = 0;
  223. if (document.documentElement && document.documentElement.scrollTop) {
  224. scrollTop = document.documentElement.scrollTop;
  225. } else if (document.body) {
  226. scrollTop = document.body.scrollTop;
  227. }
  228. return scrollTop;
  229. }
  230. this.scroll = function () {
  231. var view=_this.current.parentNode.parentNode;
  232. var direction = view.getAttribute("data-scroll-direction");
  233. if(!direction) return;
  234. view.style.position="relative";
  235. _this.current.parentNode.style.position="absolute";
  236. if(direction=="x"){
  237. _this.current.parentNode.style.width= (_this.hotbtn.length*_this.current.clientWidth*2)+"px";
  238. if ( _this.current.getBoundingClientRect().left-view.getBoundingClientRect().left-_this.current.getBoundingClientRect().width<0) {
  239. _this.viewScrollX(_this.current.getBoundingClientRect().left-view.getBoundingClientRect().left );
  240. }
  241. if(_this.current.getBoundingClientRect().left-view.getBoundingClientRect().left+_this.current.getBoundingClientRect().width>view.getBoundingClientRect().width){
  242. _this.viewScrollX(_this.current.getBoundingClientRect().left-(view.getBoundingClientRect().left)-_this.current.getBoundingClientRect().width);
  243. }
  244. }
  245. if(direction=="y"){
  246. if ( _this.current.getBoundingClientRect().top-view.getBoundingClientRect().top-_this.current.getBoundingClientRect().height<0) {
  247. _this.viewScrollY(_this.current.getBoundingClientRect().top-view.getBoundingClientRect().top );
  248. }
  249. if(_this.current.getBoundingClientRect().top-view.getBoundingClientRect().top+_this.current.getBoundingClientRect().height>view.getBoundingClientRect().height){
  250. _this.viewScrollY(_this.current.getBoundingClientRect().top-view.getBoundingClientRect().top-_this.current.getBoundingClientRect().height);
  251. }
  252. }
  253. }
  254. var isload = 0;
  255. self.classDo = function (index) {
  256. isload = isload + 1;
  257. if (isload == 2) {
  258. _this.sourceLength = element.length;
  259. }
  260. if(element[index])
  261. element[index].classList.add(currentClass);
  262. else return;
  263. //如果元素不存在 不进行渲染 待重载
  264. for (var i = 0; i < element.length; i++) {
  265. if (i!=index&&element[i].classList.contains(currentClass)) {
  266. element[i].classList.remove(currentClass);
  267. }
  268. }
  269. _this.scroll();//渲染的之前先复位
  270. var effect= element[index].getAttribute("data-effect");
  271. if(effect){
  272. focusobj.setAttribute("style"," position: fixed; z-index: 19;width:"+(element[index].getBoundingClientRect().width)+"px ;height:"+(element[index].getBoundingClientRect().height)+"px; left:"+element[index].getBoundingClientRect().left+"px;top:"+element[index].getBoundingClientRect().top+"px;");
  273. focusobj.setAttribute("class","focusobj current "+effect);
  274. } else {
  275. focusobj.setAttribute("class","hide ");
  276. focusobj.setAttribute("style","");
  277. }
  278. }
  279. self.EventUtil = {
  280. add: function (obj, callback) {
  281. if (typeof (obj.onkeypress) == "null") {
  282. obj.onkeypress = function (e) {
  283. callback && callback(e)
  284. }
  285. } else {
  286. obj.onkeydown = function (e) {
  287. callback && callback(e)
  288. }
  289. }
  290. }
  291. }
  292. EventUtil.add(document, function (e) {
  293. _self.onPressdo(e);
  294. });
  295. self.overIndex=function(){
  296. //防止超出
  297. if (_this.currentIndex >= element.length - 1) {
  298. _this.currentIndex = element.length - 1;
  299. }
  300. if (_this.currentIndex < 0) {
  301. _this.currentIndex = 0;
  302. }
  303. }
  304. self.isNumber = function(val){
  305. var regPos = /^\d+(\.\d+)?$/; //非负浮点数
  306. var regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; //负浮点数
  307. if(regPos.test(val) || regNeg.test(val)){
  308. return true;
  309. }else{
  310. return false;
  311. }
  312. }
  313. self.ruleFn=function(index,direction){
  314. if(rules && typeof rules[_this.className] == "object" &&typeof rules[_this.className]["line"] !="undefined" )
  315. {
  316. var line = rules[_this.className]["line"];
  317. }else{
  318. var line=_this.hotbtn.length;
  319. }
  320. line=parseInt(line);
  321. if (rules && typeof rules[_this.className] == "object" && typeof rules[_this.className][_this.currentIndex]!="undefined"&& typeof rules[_this.className][_this.currentIndex][index]!="undefined") {
  322. var objRules = rules[_this.className][_this.currentIndex];
  323. if(self.isNumber(objRules[index])){
  324. _this.currentIndex = parseInt(_this.currentIndex) + parseInt(objRules[index]);
  325. }else if(Array.isArray(objRules[index])){
  326. //_this.currentIndex = _this.currentIndex + parseInt(objRules[index][1]);
  327. _this.reSetClass(objRules[index][0], objRules[index][1]);
  328. }else if(typeof rules[_this.className]["line"] !="undefined"){
  329. _this.currentIndex = _this.currentIndex + line;
  330. }
  331. } else {
  332. var jump = element[_this.currentIndex].getAttribute("data-"+direction);
  333. jump=parseInt(jump);
  334. var obj = rules[_this.className];
  335. if(direction=="up"){
  336. if(_this.currentIndex>line-1) //上边沿
  337. _this.currentIndex= jump?_this.currentIndex-jump:_this.currentIndex-line;
  338. else if(obj&&typeof obj["up"]!="undefined" ) _this.reSetClass(obj[direction][0], obj["up"][1]);
  339. }else if(direction=="left"){
  340. if((_this.currentIndex)%line!=0) //左边
  341. _this.currentIndex= jump?_this.currentIndex-jump:_this.currentIndex-1;
  342. else if(obj&&typeof obj["left"]!="undefined" ) _this.reSetClass(obj["left"][0], obj["left"][1]);
  343. }else if(direction=="right"){
  344. if((_this.currentIndex+1)%line!=0) //右边
  345. _this.currentIndex= jump?_this.currentIndex+jump:_this.currentIndex+1;
  346. else if(obj&&typeof obj["right"]!="undefined" ) _this.reSetClass(obj["right"][0], obj["right"][1]);
  347. }else if(direction=="down"){
  348. if(_this.hotbtn.length-line>_this.currentIndex) //下边沿
  349. _this.currentIndex= jump?_this.currentIndex+jump:_this.currentIndex+line;
  350. else if(obj&&typeof obj["down"]!="undefined" ) _this.reSetClass(obj["down"][0], obj["down"][1]);
  351. }
  352. }
  353. }
  354. self.rule = function () {
  355. self.overIndex();
  356. if (_this.event.keyCode == btnLeft) {
  357. self.ruleFn(0,"left");
  358. } else if (_this.event.keyCode == btnRight) {
  359. self.ruleFn(2,"right");
  360. } else if (_this.event.keyCode == btnUp) {
  361. self.ruleFn(1,"up");
  362. } else if (_this.event.keyCode == btnDown) {
  363. self.ruleFn(3,"down");
  364. }
  365. self.overIndex();
  366. }
  367. self.onPressdo = function (e) {
  368. _this.event = e;
  369. _this.currentIndex = _this.currentIndex >= element.length - 1 ? element.length - 1 : _this.currentIndex;
  370. _this.prev = element[_this.currentIndex];
  371. _this.prevIndex = _this.currentIndex;
  372. self.rule();
  373. _this.current = element[_this.currentIndex];
  374. _this.currentIndex = _this.currentIndex;
  375. _this.className = _this.className;
  376. if(init.rules[_this.className]&&(typeof init.rules[_this.className]["onPress"]) == "function")
  377. init.rules[_this.className]["onPress"].call(_this);
  378. else _this.onPress.call(_this);
  379. if (e.keyCode == btnEnter){
  380. if(init.rules[_this.className]&&(typeof init.rules[_this.className]["onEnterPress"]) == "function")
  381. init.rules[_this.className]["onEnterPress"].call(_this);
  382. else _this.onEnterPress.call(_this);
  383. }
  384. _self.classDo(_this.currentIndex);
  385. keydefault(e);
  386. }
  387. this.onLoad();//插件加载时
  388. }
  389. window.tvSysBtnBind = tvSysBtnBind;
  390. })(window)