diff --git a/src/mip-258-form-btn/README.md b/src/mip-258-form-btn/README.md new file mode 100644 index 000000000..6548b6cd8 --- /dev/null +++ b/src/mip-258-form-btn/README.md @@ -0,0 +1,45 @@ +# mip-258-form-btn ajax请求 + +ajax请求 + +标题|内容 +----|---- +类型|通用 +支持布局|N/S +## 示例 + +### 基本使用 + +```html + + + + + + + +``` +### url + +说明:必须是 HTTP(S) 或 // 开头的地址 +必选项: 是 + +### method + +说明:请求方法 +必选项: 是 + +### redirect + +说明:必须是 HTTP(S) 或 // 开头的地址 +必选项: 否 + +### reload + +说明:boolean值 默认false, 请求成功后是否页面刷新 +必选项: 否 + + + + + diff --git a/src/mip-258-form-btn/mip-258-form-btn.js b/src/mip-258-form-btn/mip-258-form-btn.js new file mode 100644 index 000000000..139a74bd3 --- /dev/null +++ b/src/mip-258-form-btn/mip-258-form-btn.js @@ -0,0 +1,50 @@ + +/** + * @file mip-ajax-button 组件 + * + * @author chen + * @time 2018.8.21 + */ +define(function (require) { + var customElement = require('customElement').create(); + var $ = require('zepto'); + customElement.prototype.build = function () { + var element = this.element; + var url = $(element).attr('url'); + var method = $(element).attr('method'); + var button = $(element).find('button'); + var reload = $(element).attr('reload'); + var redirect = $(element).attr('redirect'); + var input = $(element).find('input'); + var formData = new FormData(); + $.each(input, function (index, item) { + var filed = $(item).attr('name'); + var val = $.trim($(item).val()); + formData.append(filed, val); + }); + button.click(function () { + ajaxBox(); + }); + + // tijiao + function ajaxBox() { + fetch(url, {method: method, mode: 'cors', body: formData}).then(function (res) { + res.json().then(function (data) { + if (data.status === 1) { + $(element).find('span.success').text(data.msg).show(); + if (redirect) { + window.top.location.href = redirect; + } + if (reload === 'true') { + window.top.location.reload(); + } + } else { + $(element).find('span.error').text(data.msg).show(); + } + }); + }).catch(function (e) { + }); + } + }; + return customElement; +}); diff --git a/src/mip-258-form-btn/package.json b/src/mip-258-form-btn/package.json new file mode 100644 index 000000000..99a1851f7 --- /dev/null +++ b/src/mip-258-form-btn/package.json @@ -0,0 +1,12 @@ +{ + "name": "mip-258-form-btn", + "version": "1.0.0", + "description":"按钮ajax请求。", + "author": { + "name": "chen", + "email": "chenweilin@258c.com" + }, + "engines": { + "mip": ">=1.0.0" + } +} \ No newline at end of file diff --git a/src/mip-258-form1/README.md b/src/mip-258-form1/README.md new file mode 100644 index 000000000..7e084d40a --- /dev/null +++ b/src/mip-258-form1/README.md @@ -0,0 +1,113 @@ +# mip-258-form1 + +mip-258-form1 表单组件 + +标题|内容 +----|---- +类型|通用 +支持布局|fixed +所需脚本|https://c.mipcdn.com/static/v1/mip-258-form1/mip-258-form1.js + +## 示例 +### 基本使用 + +```html + + +
获取验证码
+
59秒后重新获取
+
请输入正确的电话
+ +
年龄不能为空
+
+ +
+
+ +
+
+ +
+ +
+``` +## 属性 + +### method + +说明:表单提交方法 +必选项:是 + +### controlId + +说明:需要控制的id +必选项:否 + +### from + +说明:来自那张表单 +必选项:否 + +### url + +说明:必须是 HTTP(S) 或 // 开头的地址 +必选项: 是 + +### validatetarget + +说明: 验证提示对应 tag,用于对应错误时的提示显示元素的查找 +必选项:否 + +### validatetype + +说明:验证类型, 用于支持简单的验证。目前提供 `email`, `phone`, `idcar`, `custom`。当为 `custom` 时则需要填写 `validatereg` +必选项:否 + +### validatereg + +说明: 自定义验证,补充站长个性化的验证规则。如果 `validatetype` 为 `custom` 时需填写相应验证规则 +必选项:否 + +### fetch-url + +说明: 有此属性则可以开启异步请求数据逻辑,组件会并根据数据返回状态来按`submit-success`,`submit-error`块中的模板刷新局部信息。 +需要注意的几个点: + +- 方法支持。 +- 请求结果请返回 JSON 对象。 +- 数据状态只有在成功(2xx)的时候触发 `submit-success` 的逻辑,其他的均触发 `submit-error` 逻辑。 + +必选项:否 + +### pid + +说明: 用来绑定产品id +必选项: 否 + +### cid + +说明: 用来绑定公司id +必选项: 否 + +- 方法支持。 +- 请求结果请返回 JSON 对象。 +- 数据状态只有在成功(2xx)的时候触发 `submit-success` 的逻辑,其他的均触发 `submit-error` 逻辑。 + +必选项:否 + +### on + +说明: 添加事件清空表单 +必选项: 否 + + +## 注意事项 + +1. 表单提交方法如果为 `post`,应使用 HTTPS 地址。避免 MIP-Cache HTTPS 环境提交到 HTTP,导致浏览器报错。 +2. 使用 fetch 功能时,请求使用 cors 时不能配置为 *。 \ No newline at end of file diff --git a/src/mip-258-form1/mip-258-form1-fn.js b/src/mip-258-form1/mip-258-form1-fn.js new file mode 100644 index 000000000..297267c44 --- /dev/null +++ b/src/mip-258-form1/mip-258-form1-fn.js @@ -0,0 +1,342 @@ +/** + * @file mip-form-fn.js + * @description mip-form函数 + * @author miper + */ + +define(function (require) { + var templates = require('templates'); + var util = require('util'); + var viewer = require('viewer'); + var $ = require('zepto'); + var windowInIframe = viewer.isIframed; + var evt; + var REGS = { + EMAIL: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/, + PHONE: /^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/, + IDCAR: /^\d{15}|\d{18}$/ + }; + return { + + /** + * 处理fetch请求逻辑 + * + * @param {string} url 请求url + */ + fetchUrl: function (url) { + var me = this; + util.css([me.successEle, me.failEle, me.errorEle], {display: 'none'}); + var fetchData = { + method: me.method, + credentials: 'include' + }; + if (me.method === 'POST') { + var formD = me.ele.querySelector('form'); + var data = $(formD).serializeArray(); + if (formD) { + fetchData = util.fn.extend({}, fetchData, { + body: new FormData(formD) + }); + } + } + + // 数据请求处理 + fetch(url, fetchData).then(function (res) { + if (res.ok) { + res.json().then(function (data) { + if (data.status === 1) { + util.css(me.successEle, {display: 'block'}); + me.renderTpl(me.successEle, {successinfo: data.info}); + me.submitSuccessHandle(); + } + if (data.status === -1) { + util.css(me.failEle, {display: 'block'}); + me.renderTpl(me.failEle, {failinfo: data.info}); + me.submitFailHandle(); + } + }).catch(function (err) { + me.fetchReject(err); + }); + } + else { + me.submitErrorHandle(); + me.fetchReject({}); + } + }).catch(function (err) { + me.submitErrorHandle(); + me.fetchReject(err); + }); + }, + + /** + * fetch出错逻辑处理 + * + * @param {Object} err 错误对象 + */ + fetchReject: function (err) { + var me = this; + util.css(me.errorEle, {display: 'block'}); + me.renderTpl(me.errorEle, err); + }, + + /** + * fetch成功动作处理 + * + * @param {Object} dom 结构 + */ + action: function (dom) { + var from = $(dom).attr('from'); + var actionDom = $(dom).attr('controlId'); + if (from === 'comment') { + setTimeout(function () { + window.top.location.href = window.location.href; + }, 2000); + } + $(actionDom).addClass('mip-active'); + }, + + /** + * 处理模板渲染 + * + * @param {HTMLElement} ele 模板父节点 + * @param {Object} data 模板渲染数据 + */ + renderTpl: function (ele, data) { + var me = this; + templates.render(ele, data).then(function (html) { + var tempTarget = me.tempHTML(ele); + tempTarget.innerHTML = html; + }); + }, + + /** + * 处理模板渲染 + * + * @param {HTMLElement} ele 渲染后模板父节点 + * @return {HTMLElement} target 新建DOM节点 + */ + tempHTML: function (ele) { + ele = ele || document; + var target = ele.querySelector('[mip-mustache-rendered]'); + if (!target) { + target = util.dom.create('
'); + ele.appendChild(target); + } + return target; + }, + + /** + * createDom 创建 form 节点 + * + * @param {HTMLElement} element 组件节点 + */ + createDom: function (element) { + var me = this; + var url = element.getAttribute('url'); + var target = element.getAttribute('target'); + var form = document.createElement('form'); + var method = (element.getAttribute('method') || 'GET').toUpperCase(); + form.action = url; + form.method = method; + target = target ? target : '_blank'; + form.target = viewer.isIframed && target !== '_blank' ? '_top' : target; + element.appendChild(form); + util.dom.insert(form, element.children); + + // 按钮提交 + var curEles = element.querySelectorAll('form'); + Array.prototype.forEach.call(curEles, function (item) { + item.addEventListener('submit', function (event) { + event.preventDefault(); + evt = event; + me.onSubmit(element, event); + }); + }); + + // 部分浏览器回车不触发submit, + element.addEventListener('keydown', function (event) { + if (event.keyCode === 13) { + + // 为了使余下浏览器不多次触发submit, 使用prevent + evt = event; + event.preventDefault(); + me.onSubmit(this); + } + }, false); + }, + + /** + * 事件通信 + * + * @description 在 input focus 或 blur 时向iframe外层文档发送数据,iframe外层文档返回设置预览头部为 absolute + * @param {Object} event 事件对象 + */ + sendFormMessage: function (event) { + if (windowInIframe) { + // mip_video_jump 为写在外层的承接方法 + viewer.sendMessage('input-' + event, {}); + } + }, + + /** + * 事件发送处理 + * + * @description 给 input 绑定事件,向 SF 发送数据,为了解决 ios 的 UC 浏览器在iframe外层文档悬浮头部 fixed 位置混乱问题 + * @param {HTMLElement} element mip 组件标签 + */ + initMessageEvents: function (element) { + var me = this; + var inputAll = element.querySelectorAll('input'); + Array.prototype.forEach.call(inputAll, function (item, index) { + item.addEventListener('focus', function () { + me.sendFormMessage('focus'); + }, false); + + item.addEventListener('blur', function () { + me.sendFormMessage('blur'); + }, false); + }); + }, + + /** + * 文案格式验证 + * + * @param {string} type 验证类型 + * @param {string} value 需要验证的文案 + * @return {boolean} 是否符合自定义校验 + */ + verification: function (type, value) { + return (type === 'must') ? !(value === '') : REGS[type.toUpperCase()].test(value); + }, + + /** + * 点击提交按钮事件处理函数 + * + * @param {HTMLElement} element form节点 + */ + onSubmit: function (element) { + var me = this; + var preventSubmit = false; + var inputs = element.querySelectorAll('input, textarea, select'); + var url = element.getAttribute('url') || ''; + var getUrl = url.toLowerCase(); + var isHttp = getUrl.match('http://'); + var valueJson = ''; + var hasFetch = element.getAttribute('fetch-url') || ''; + me.method = (element.getAttribute('method') || 'GET').toUpperCase(); + var isGet = me.method === 'GET'; + + this.ele = element; + this.successEle = element.querySelector('[submit-success]'); + this.failEle = element.querySelector('[submit-fail]'); + this.errorEle = element.querySelector('[submit-error]'); + // 执行提交句柄 + me.submitHandle(); + // 校验输入内容是否合法 + Array.prototype.forEach.call(inputs, function (item) { + var type = item.getAttribute('validatetype'); + var target = item.getAttribute('validatetarget'); + var regval = item.getAttribute('validatereg'); + var value = item.value; + var reg; + + if (item.type === 'submit') { + return; + } + else if (item.type === 'checkbox' || item.type === 'radio') { + value = item.checked ? item.value : ''; + } + + valueJson += '&' + item.name + '=' + value; + if (type) { + if (regval) { + reg = value === '' ? false : (new RegExp(regval)).test(value); + } + else { + reg = me.verification(type, value); + } + util.css(element.querySelectorAll('div[target="' + target + '"]'), + {display: (!reg ? 'block' : 'none')}); + preventSubmit = !reg ? true : preventSubmit; + } + }); + + if (preventSubmit) { + return; + } + + // 在iframe下使用mibm-jumplink,跳转显示手百框。 http-GET请求交给外层跳转 + if (window.parent !== window && isHttp && isGet) { + var messageUrl = ''; + if (getUrl.match('\\?')) { + // eg. getUrl == 'http://www.mipengine.org?we=123' + messageUrl = getUrl + valueJson; + } + else { + // eg. getUrl == 'http://www.mipengine.org' + valueJson = valueJson.substring(1); + messageUrl = getUrl + '?' + valueJson; + } + var message = { + event: 'mibm-jumplink', + data: { + url: messageUrl + } + }; + window.parent.postMessage(message, '*'); + } + else if (hasFetch.trim()) { + me.fetchUrl(hasFetch); + } + else { + // https请求 或 post请求 或 非iframe下不做处理 + element.getElementsByTagName('form')[0].submit(); + } + }, + + /** + * 提交时的事件 + * + * @param {HTMLElement} element form节点 + */ + submitHandle: function () { + viewer.eventAction.execute('submit', evt.target, evt); + }, + + /** + * 提交成功调用的在html on里使用的事件 + * + * @param {HTMLElement} element form节点 + */ + submitSuccessHandle: function () { + if (!evt) { + return; + } + viewer.eventAction.execute('submitSuccess', evt.target, evt); + }, + + /** + * 提交成功调用的在html on里使用的事件 + * + * @param {HTMLElement} element form节点 + */ + submitFailHandle: function () { + if (!evt) { + return; + } + viewer.eventAction.execute('submitFail', evt.target, evt); + }, + + /** + * 提交失败调用的在html on里使用的事件 + * + * @param {HTMLElement} element form节点 + */ + submitErrorHandle: function () { + if (!evt) { + return; + } + viewer.eventAction.execute('submitError', evt.target, evt); + } + }; +}); diff --git a/src/mip-258-form1/mip-258-form1.css b/src/mip-258-form1/mip-258-form1.css new file mode 100644 index 000000000..7e461c5ea --- /dev/null +++ b/src/mip-258-form1/mip-258-form1.css @@ -0,0 +1 @@ +mip-258-form1{position:relative}mip-258-form1 .btnCode{display:block;padding:10px;color:#fff}mip-258-form1 #mip-form-cross{position:absolute;display:block;padding:6px;width:20px;height:20px;right:0;background:url(//m.baidu.com/static/search/clear.png) no-repeat center;z-index:100;background-size:100% 100%;background-origin:content-box;-webkit-tap-highlight-color:rgba(0,0,0,.4);tap-highlight-color:rgba(0,0,0,.4)}mip-258-form1 input,mip-258-form1 textarea,mip-258-form1 select{border:1px solid #f1f1f1;padding:6px;display:block;box-sizing:border-box;-webkit-box-sizing:border-box;resize:none;font-size:16px}mip-258-form1 input[type=text],mip-258-form1 input[type=input],mip-258-form1 input[type=datetime],mip-258-form1 input[type=email],mip-258-form1 input[type=number],mip-258-form1 input[type=tel],mip-258-form1 input[type=url]{padding-right:30px}mip-258-form1 form{position:relative}mip-258-form1 input[type=radio]{display:inline}mip-258-form1 label{display:block}mip-258-form1 .error{display:none;color:#ec1f5c;font-size:12px;text-align:left;line-height:22px;padding:0 10% 0 3%}mip-258-form1 .error[mip-mustache-rendered]{display:block}mip-258-form1 input[type=submit]{border:1px solid #f1f1f1;border-radius:5px;color:#333;background:#d8d7d7}mip-258-form1 [submit-success],mip-258-form1 [submit-error]{display:none} \ No newline at end of file diff --git a/src/mip-258-form1/mip-258-form1.js b/src/mip-258-form1/mip-258-form1.js new file mode 100644 index 000000000..14cc1fc1c --- /dev/null +++ b/src/mip-258-form1/mip-258-form1.js @@ -0,0 +1,82 @@ +/** + * @file mip-258-form 组件 + * @author + */ + +define(function (require) { + var customElement = require('customElement').create(); + var form = require('./mip-258-form1-fn'); + var $ = require('zepto'); + + customElement.prototype.build = function () { + var element = this.element; + var url = $(element).attr('fetch-url'); + + + // 获取验证码事件 + + $(element).find('.btnCode').click(function () { + var url = $(this).attr('btn-url'); + var mobile = $(element).find('.inquiryMobile').val(); + getInquiryMobileCode(mobile, 60, url); + }); + + function getInquiryMobileCode(mobile, second, url) { + if (mobile === '' || isNaN(mobile)) { + alert('请输入手机号码'); + return false; + } + else if (mobile.length !== 11) { + alert('请输入正确的手机号码'); + return false; + } + $(element).find('.btnCode').hide(); + if (second <= 1) { + $(element).find('.waitInquiry').html(59); + $(element).find('.getInquiryCode').show(); + $(element).find('.waitInquiryCode').addClass('hide'); + $(element).find('.btnCode').show(); + return true; + } + + if (second >= 60) { + $.ajax({ + type: 'POST', + url: url, + data: 'mobile=' + mobile, + async: true, + success: function (data) { + alert(data.info); + }, + headers: { + 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') + } + }); + $(element).find('.getInquiryCode').hide(); + $(element).find('.waitInquiryCode').removeClass('hide'); + } + second--; + $(element).find('.waitInquiry').html(second); + setTimeout(function () { + getInquiryMobileCode(mobile, second); + }, 1000); + } + form.createDom(element); + form.initMessageEvents(element); + }; + customElement.prototype.firstInviewCallback = function () { + this.addEventAction('reload', function (event, str) { + // 页面刷新操作 + str = str ? 500 : parseInt(str, 10); + setTimeout(function () { + window.top.location.reload(); + }, str); + }); + + this.addEventAction('reset', function (event, str) { + // 页面刷新操作 + event.target.reset(); + }); + }; + return customElement; +}); diff --git a/src/mip-258-form1/mip-258-form1.less b/src/mip-258-form1/mip-258-form1.less new file mode 100644 index 000000000..6d1aa0f97 --- /dev/null +++ b/src/mip-258-form1/mip-258-form1.less @@ -0,0 +1,74 @@ +mip-258-form1 { + position: relative; + .btnCode { + display: block; + padding: 10px; + color: #fff; + } + #mip-form-cross { + position: absolute; + display: block; + padding: 6px; + width: 20px; + height: 20px; + right: 0; + background: url('//m.baidu.com/static/search/clear.png') no-repeat center; + z-index: 100; + background-size: 100% 100%; + background-origin: content-box; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0.4); + tap-highlight-color: rgba(0, 0, 0, 0.4) + } + input, + textarea, + select { + border: 1px solid #f1f1f1; + padding: 6px; + display: block; + box-sizing: border-box; + -webkit-box-sizing: border-box; + resize: none; + font-size: 16px; + } + input[type='text'], + input[type='input'], + input[type='datetime'], + input[type='email'], + input[type='number'], + input[type='tel'], + input[type='url'] { + padding-right: 30px; + } + form { + position: relative; + } + input[type='radio'] { + display: inline + } + label { + display: block + } + .error { + display: none; + color: #ec1f5c; + font-size: 12px; + text-align: left; + line-height: 22px; + padding: 0 10% 0 3% + } + .error[mip-mustache-rendered] { + display: block; + } + input[type='submit'] { + border: 1px solid #f1f1f1; + border-radius: 5px; + color: #333; + background: #d8d7d7; + } + [submit-success], + [submit-fail], + [submit-error] { + display: none; + } +} + diff --git a/src/mip-258-form1/package.json b/src/mip-258-form1/package.json new file mode 100644 index 000000000..4862ab68c --- /dev/null +++ b/src/mip-258-form1/package.json @@ -0,0 +1,14 @@ +{ + "name": "mip-258-form1", + "version": "1.0.0", + "description": "258表单提交", + "contributors": [ + { + "name": "teemor", + "email": "232957726@qq.com" + } + ], + "engines": { + "mip": ">=1.1.0" + } +} diff --git a/src/mip-258-tool/README.md b/src/mip-258-tool/README.md new file mode 100644 index 000000000..d6ad7bac0 --- /dev/null +++ b/src/mip-258-tool/README.md @@ -0,0 +1,31 @@ +# mip-258-tool + +ajax请求 + +标题|内容 +----|---- +类型|通用 +支持布局|N/S +## 示例 + +### 基本使用 + +```html + + +``` +### on + +说明:goback事件对应window.history.back()事件 +reload(100)事件对应window.reload()事件,传入毫秒数,用于刷新等待 +alert()事件对应window.alert()事件 +redirect('url,time_wait') 对应window.location.href事件 +必选项: 否 + + + + + + + + diff --git a/src/mip-258-tool/mip-258-tool.js b/src/mip-258-tool/mip-258-tool.js new file mode 100644 index 000000000..f60f3930d --- /dev/null +++ b/src/mip-258-tool/mip-258-tool.js @@ -0,0 +1,52 @@ + +/** + * @file mip-ajax-button 组件 + * + * @author chen + * @time 2018.8.21 + */ +define(function (require) { + var customElement = require('customElement').create(); + + customElement.prototype.build = function () { + + }; + + customElement.prototype.firstInviewCallback = function (event, str) { + + // 添加页面刷新事件 + this.addEventAction('reload', function (event, str) { + str = str ? 500 : parseInt(str, 10); + setTimeout(function () { + window.top.location.reload(); + }, str); + }); + + // 添加alert提示事件 + this.addEventAction('alert', function (event, str) { + window.top.alert(str); + }); + + // 添加后退事件 + this.addEventAction('goback', function (event, str) { + if (window.top.history.length === 0) { + window.top.location.href = str; + } + window.top.history.back(); + }); + + // 添加重定向事件 + this.addEventAction('redirect', function (event, url) { + var params = url.split(','); + url = params[0]; + var timeWait = params[1] ? Number.parseInt(params[1], 10) : 0; + + if (url) { + setTimeout(function () { + window.top.location.href = url; + }, timeWait); + } + }); + }; + return customElement; +}); diff --git a/src/mip-258-tool/package.json b/src/mip-258-tool/package.json new file mode 100644 index 000000000..e7424602d --- /dev/null +++ b/src/mip-258-tool/package.json @@ -0,0 +1,12 @@ +{ + "name": "mip-258-tool", + "version": "1.0.0", + "description":"简单的js事件工具。", + "author": { + "name": "chen", + "email": "chenweilin@258c.com" + }, + "engines": { + "mip": ">=1.0.0" + } +} \ No newline at end of file diff --git a/src/mip-code-button/README.md b/src/mip-code-button/README.md new file mode 100644 index 000000000..9f665e509 --- /dev/null +++ b/src/mip-code-button/README.md @@ -0,0 +1,47 @@ +# mip-code-button + +标题|内容 +----|---- +类型|通用 +支持布局|N/S +## 示例 + +### 基本使用 + +```html + +
+ +
秒后重新获取
+
+
+``` +### url + +说明: 必须是 HTTP(S) 或 // 开头的地址 +必选项: 是 + +### fetch-button + +说明:提交触发选择器属性 +必选项: 是 + +### time-count +说明: 时间倒计时选择器属性 +必选项: 是 +注意: 时间数值必须包裹在firstElementChild里面 + +### timeout +说明 : 倒计时超时时间 +默认值: 60 +必选项: 否 + +### fail-info-id +说明 : 获取失败错误信息提示元素 +必选项: 否 + + + + + + diff --git a/src/mip-code-button/mip-code-button-fn.js b/src/mip-code-button/mip-code-button-fn.js new file mode 100644 index 000000000..a4b190aa8 --- /dev/null +++ b/src/mip-code-button/mip-code-button-fn.js @@ -0,0 +1,297 @@ +/** + * @file mip-code-button.js + * @description mip-form函数 + * @author chen + */ + +define(function (require) { + var templates = require('templates'); + var util = require('util'); + var viewer = require('viewer'); + var evt; + return { + + /** + * 处理fetch请求逻辑 + * + * @param {string} url 请求url + */ + fetchUrl: function (url) { + var me = this; + var data = new FormData(); + + for (var index in me.fetchData) { + if (me.fetchData.hasOwnProperty(index)) { + data.append(index, me.fetchData[index]); + } + } + // 获取CSRF-TOKEN + var tokenDom = document.querySelector('meta[name="csrf-token"]'); + if (tokenDom) { + var token = tokenDom.getAttribute('content'); + } + + var options = { + method: 'POST', + credentials: 'include', + body: data, + // 使用Accept,用来判断异步 + headers: new Headers({ + 'Accept': 'application/json', + 'X-Requested-With': 'XMLHttpRequest', + 'X-CSRF-TOKEN': token ? token : '' + }) + }; + // 判断域名,是否跨域.测试使用 + var localhost = location.host; + if (url.indexOf(localhost) === -1) { + options.mode = 'cors'; + options.credentials = 'omit'; + } + + // 数据请求处理 + fetch(url, options).then(function (res) { + if (res.ok) { + return res.json(); + } + }).then(function (response) { + var status = parseInt(response.status, 10); + if (status === 1) { + + me.successHandle(); + } else { + // 处理错误提示 + me.showFailInfo(response.info); + me.failHandle(); + } + + }).catch(function (err) { + + me.errorHandle(); + // me.fetchReject(err); + }); + }, + hideFailInfo: function () { + if (this.failInfoId) { + var failInfoEl = document.getElementById(this.failInfoId); + if (failInfoEl) { + util.css(failInfoEl, {display: 'none'}); + } + } + }, + showFailInfo: function (info) { + if (this.failInfoId) { + var failInfoEl = document.getElementById(this.failInfoId); + if (failInfoEl) { + failInfoEl.innerHTML = info; + util.css(failInfoEl, {display: 'block'}); + } + } + }, + setFetchData: function (key, val) { + if (!this.fetchData) { + this.fetchData = {}; + } + this.fetchData[key] = val; + }, + + /** + * fetch出错逻辑处理 + * + * @param {Object} err 错误对象 + */ + fetchReject: function (err) { + var me = this; + util.css(me.errorEle, {display: 'block'}); + me.renderTpl(me.errorEle, err); + }, + + /** + * 处理模板渲染 + * + * @param {HTMLElement} ele 模板父节点 + * @param {Object} data 模板渲染数据 + */ + renderTpl: function (ele, data) { + var me = this; + templates.render(ele, data).then(function (html) { + var tempTarget = me.tempHTML(ele); + tempTarget.innerHTML = html; + }); + }, + + /** + * 处理模板渲染 + * + * @param {HTMLElement} ele 渲染后模板父节点 + * @return {HTMLElement} target 新建DOM节点 + */ + + tempHTML: function (ele) { + ele = ele || document; + var target = ele.querySelector('[mip-mustache-rendered]'); + if (!target) { + target = util.dom.create('
'); + ele.appendChild(target); + } + return target; + }, + + /** + * createDom 创建 form 节点 + * + * @param {HTMLElement} element 组件节点 + */ + createDom: function (element) { + var me = this; + me.fetchData = {}; + me.url = element.getAttribute('url'); + + me.method = (element.getAttribute('method') || 'GET').toUpperCase(); + + me.failInfoId = element.getAttribute('fail-info-id'); + me.hideFailInfo(); + var submitBtn = element.querySelector('[fetch-button]'); + // 添加点击事件监听 + submitBtn.addEventListener('click', function (event) { + evt = event; + me.onSubmit(element); + }); + }, + + + /** + * 点击提交按钮事件处理函数 + * + * @param {HTMLElement} element form节点 + */ + onSubmit: function (element) { + var me = this; + me.hideFailInfo(); + // 定时器已存在不允许再次触发点击 + if (me.timer) { + return; + } + var url = element.getAttribute('url') || ''; + if (!url) { + return; + } + + var mobile = this.fetchData.mobile; + var reg = mobile && (/^1[3578]\d{9}$/.test(mobile)); + // 手机验证通过 + if (!reg) { + me.invalidHandle('mobile'); + return; + } + else { + me.validHandle('mobile'); + } + + // 获取时间限制 + var timeout = element.getAttribute('timeout') || 60; + // 开始计时 + me.timeEle = element.querySelector('[time-count]'); + me.submitBtn = element.querySelector('[fetch-button]'); + + // 设置初始值,然后再show + me.timeEle.firstElementChild.innerHTML = timeout; + util.css(me.submitBtn, {display: 'none'}); + util.css(me.timeEle, {display: 'block'}); + + me.timer = setInterval(function () { + me.timeEle.firstElementChild.innerHTML = timeout--; + if (timeout <= 0) { + me.clearTimer(); + } + }, 1000); + + this.ele = element; + + // 执行数据请求 + this.fetchUrl(url); + }, + + /** + * 清除定时器 + * + * @param {HTMLElement} element form节点 + */ + clearTimer: function () { + + if (this.timer) { + clearInterval(this.timer); + util.css(this.submitBtn, {display: 'block'}); + util.css(this.timeEle, {display: 'none'}); + this.timer = null; + } + }, + + /** + * 输出表单错误信息 + * @param {HTMLElement} element form节点 + */ + invalidHandle: function () { + console.log('mobile字段格式不正确'); + viewer.eventAction.execute('invalid', evt.target, evt); + }, + + /** + * 隐藏表单错误信息 + * @param {HTMLElement} element form节点 + */ + validHandle: function () { + console.log('mobile字段格式验证通过'); + viewer.eventAction.execute('valid', evt.target, evt); + }, + + + /** + * 提交时的事件 + * + * @param {HTMLElement} element form节点 + */ + submitHandle: function () { + viewer.eventAction.execute('submit', evt.target, evt); + }, + + /** + * 提交成功调用的在html on里使用的事件 + * + * @param {HTMLElement} element form节点 + */ + successHandle: function () { + if (!evt) { + return; + } + viewer.eventAction.execute('success', evt.target, evt); + }, + + /** + * 提交成功,但处理结果为失败,调用的在html on里使用的事件 + * + * @param {HTMLElement} element form节点 + */ + failHandle: function () { + + if (!evt) { + return; + } + this.clearTimer(); + viewer.eventAction.execute('fail', evt.target, evt); + }, + + + /** + * 提交失败调用的在html on里使用的事件 + * + * @param {HTMLElement} element form节点 + */ + errorHandle: function () { + if (!evt) { + return; + } + viewer.eventAction.execute('error', evt.target, evt); + } + }; +}); diff --git a/src/mip-code-button/mip-code-button.js b/src/mip-code-button/mip-code-button.js new file mode 100644 index 000000000..f851a046d --- /dev/null +++ b/src/mip-code-button/mip-code-button.js @@ -0,0 +1,27 @@ +/** + * @file mip-code-button 组件 + * + * @author chen + * @time 2018.8.28 + */ + +define(function (require) { + var customElement = require('customElement').create(); + var initJs = require('./mip-code-button-fn'); + customElement.prototype.build = function () { + var element = this.element; + // 初始化 + initJs.createDom(element); + }; + + // 缩进不能用tab,就这么喜欢标新立异? + customElement.prototype.firstInviewCallback = function () { + // 添加绑定手机号事件 + this.addEventAction('bind', function (event, str) { + if (event.target.tagName === 'INPUT') { + initJs.setFetchData(str, event.target.value.trim()); + } + }); + }; + return customElement; +}); diff --git a/src/mip-code-button/mip-code-button.less b/src/mip-code-button/mip-code-button.less new file mode 100644 index 000000000..565700003 --- /dev/null +++ b/src/mip-code-button/mip-code-button.less @@ -0,0 +1,11 @@ +mip-code-button { + position: relative; + .btnCode { + display: block; + padding: 10px; + color: #fff; + } + [time-count] { + display: none; + } +} \ No newline at end of file diff --git a/src/mip-code-button/package.json b/src/mip-code-button/package.json new file mode 100644 index 000000000..9e2f78455 --- /dev/null +++ b/src/mip-code-button/package.json @@ -0,0 +1,12 @@ +{ + "name": "mip-code-button", + "version": "1.0.0", + "description":"验证码获取。", + "author": { + "name": "chen", + "email": "chenweilin@258c.com" + }, + "engines": { + "mip": ">=1.0.0" + } +} \ No newline at end of file diff --git a/src/mip-product-form/README.md b/src/mip-product-form/README.md new file mode 100644 index 000000000..b8ed6339d --- /dev/null +++ b/src/mip-product-form/README.md @@ -0,0 +1,70 @@ +# mip-product-form + +fetch请求 + +标题|内容 +----|---- +类型|通用 +支持布局|N/S +## 示例 + +### 基本使用 + +```html + + + + +
+ +
+ +
+``` +### url + +说明:必须是 HTTP(S) 或 // 开头的地址 +必选项: 是 + +### method +说明:请求方法 ,默认post +必选项: 无 + +### on + +说明:可以被触发的事件 +必选项: 否 +服务端返回的数据格式 : +{ + status: 1, + msg: '', + data: [], +} +status -1 代表服务器响应成功,但处理结果为失败。可以触发使用fail事件 +status 1 代表服务器响应成功,处理结果为成功。可以触发使用success事件 +若服务器异常,则触发error事件 + + + + + + diff --git a/src/mip-product-form/mip-product-form-fn.js b/src/mip-product-form/mip-product-form-fn.js new file mode 100644 index 000000000..e5f104cbb --- /dev/null +++ b/src/mip-product-form/mip-product-form-fn.js @@ -0,0 +1,337 @@ +/** + * @file mip-form-fn.js + * @description mip-form函数 + * @author chen + */ + +define(function (require) { + var templates = require('templates'); + var util = require('util'); + var viewer = require('viewer'); + var windowInIframe = viewer.isIframed; + var evt; + var REGS = { + EMAIL: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/, + PHONE: /^1\d{10}$/, + IDCAR: /^\d{15}|\d{18}$/ + }; + + return { + + /** + * 处理fetch请求逻辑 + * + * @param {string} url 请求url + */ + fetchUrl: function (url) { + var me = this; + util.css([me.successEle, me.failElem, me.errorEle], {display: 'none'}); + var formD = me.ele.querySelector('form'); + var data = new FormData(formD); + var options = { + method: 'POST', + body: data, + credentials: 'include', + // 使用Accept,用来判断异步 + headers: { + 'Accept': 'application/json' + } + }; + // 判断域名,是否跨域.测试使用 + var localhost = location.host; + if (url.indexOf(localhost) === -1) { + options.mode = 'cors'; + options.credentials = 'omit'; + } + // 数据请求处理 + fetch(url, options).then(function (res) { + if (res.ok) { + return res.json(); + } + }).then(function (response) { + + if (response.status === 1) { + me.successHandle(); + } + if (response.status === -1) { + util.css(me.failEle, {display: 'block'}); + me.renderTpl(me.failEle, {failinfo: response.info}); + me.failHandle(); + } + // 表单验证不通过 + if (response.status === -2) { + + me.invalidHandle(); + } + }).catch(function (err) { + + me.errorHandle(); + me.fetchReject(err); + }); + }, + + /** + * trim 字符串前后空格 + * @param {string} str 需要trim的字符串 + * @return {string} 过滤完成的字符串 + */ + trim: function (str) { + return str.replace(/(^\s*)|(\s*$)/g, ''); + }, + + /** + * fetch出错逻辑处理 + * + * @param {Object} err 错误对象 + */ + fetchReject: function (err) { + var me = this; + util.css(me.errorEle, {display: 'block'}); + me.renderTpl(me.errorEle, err); + }, + + /** + * 处理模板渲染 + * + * @param {HTMLElement} ele 模板父节点 + * @param {Object} data 模板渲染数据 + */ + renderTpl: function (ele, data) { + var me = this; + templates.render(ele, data).then(function (html) { + var tempTarget = me.tempHTML(ele); + tempTarget.innerHTML = html; + }); + }, + + /** + * 处理模板渲染 + * + * @param {HTMLElement} ele 渲染后模板父节点 + * @return {HTMLElement} target 新建DOM节点 + */ + + tempHTML: function (ele) { + ele = ele || document; + var target = ele.querySelector('[mip-mustache-rendered]'); + if (!target) { + target = util.dom.create('
'); + ele.appendChild(target); + } + return target; + }, + + /** + * createDom 创建 form 节点 + * + * @param {HTMLElement} element 组件节点 + */ + createDom: function (element) { + var me = this; + var url = element.getAttribute('url'); + var target = element.getAttribute('target'); + var form = document.createElement('form'); + var method = (element.getAttribute('method') || 'GET').toUpperCase(); + form.action = url; + form.method = method; + target = target ? target : '_blank'; + form.target = viewer.isIframed && target !== '_blank' ? '_top' : target; + element.appendChild(form); + util.dom.insert(form, element.children); + + // 按钮提交 + var curEles = element.querySelectorAll('form'); + Array.prototype.forEach.call(curEles, function (item) { + item.addEventListener('submit', function (event) { + event.preventDefault(); + evt = event; + me.onSubmit(element, event); + }); + }); + + // 部分浏览器回车不触发submit, + element.addEventListener('keydown', function (event) { + if (event.keyCode === 13) { + // 为了使余下浏览器不多次触发submit, 使用prevent + evt = event; + event.preventDefault(); + me.onSubmit(this); + } + }, false); + }, + + /** + * 事件通信 + * + * @description 在 input focus 或 blur 时向iframe外层文档发送数据,iframe外层文档返回设置预览头部为 absolute + * @param {Object} event 事件对象 + */ + sendFormMessage: function (event) { + if (windowInIframe) { + // mip_video_jump 为写在外层的承接方法 + viewer.sendMessage('input-' + event, {}); + } + }, + + /** + * 事件发送处理 + * + * @description 给 input 绑定事件,向 SF 发送数据,为了解决 ios 的 UC 浏览器在iframe外层文档悬浮头部 fixed 位置混乱问题 + * @param {HTMLElement} element mip 组件标签 + */ + initMessageEvents: function (element) { + var me = this; + var inputAll = element.querySelectorAll('input'); + Array.prototype.forEach.call(inputAll, function (item, index) { + item.addEventListener('focus', function () { + me.sendFormMessage('focus'); + }, false); + + item.addEventListener('blur', function () { + me.sendFormMessage('blur'); + }, false); + }); + }, + + /** + * 文案格式验证 + * + * @param {string} type 验证类型 + * @param {string} value 需要验证的文案 + * @return {boolean} 是否符合自定义校验 + */ + verification: function (type, value) { + return (type === 'must') ? !(value === '') : REGS[type.toUpperCase()].test(value); + }, + + /** + * 点击提交按钮事件处理函数 + * + * @param {HTMLElement} element form节点 + */ + onSubmit: function (element) { + var me = this; + var preventSubmit = false; + var inputs = element.querySelectorAll('input, textarea, select'); + var url = element.getAttribute('url') || ''; + var getUrl = url.toLowerCase(); + var isHttp = getUrl.match('http://'); + var valueJson = ''; + var hasFetch = element.getAttribute('fetch-url') || ''; + me.method = (element.getAttribute('method') || 'GET').toUpperCase(); + var isGet = me.method === 'GET'; + this.ele = element; + this.successEle = element.querySelector('[submit-success]'); + this.failEle = element.querySelector('[submit-fail]'); + this.errorEle = element.querySelector('[submit-error]'); + // 执行提交句柄 + me.submitHandle(); + // 校验输入内容是否合法 + Array.prototype.forEach.call(inputs, function (item) { + var type = item.getAttribute('validatetype'); + var target = item.getAttribute('validatetarget'); + var regval = item.getAttribute('validatereg'); + var value = item.value; + var reg; + + if (item.type === 'submit') { + return; + } + else if (item.type === 'checkbox' || item.type === 'radio') { + value = item.checked ? item.value : ''; + } + + valueJson += '&' + item.name + '=' + value; + if (type) { + if (regval) { + reg = value === '' ? false : (new RegExp(regval)).test(value); + } + else { + reg = me.verification(type, value); + } + util.css(element.querySelectorAll('div[target="' + target + '"]'), + {display: (!reg ? 'block' : 'none')}); + preventSubmit = !reg ? true : preventSubmit; + } + }); + + if (preventSubmit) { + return; + } + + // 在iframe下使用mibm-jumplink,跳转显示手百框。 http-GET请求交给外层跳转 + if (window.parent !== window && isHttp && isGet) { + var messageUrl = ''; + if (getUrl.match('\\?')) { + // eg. getUrl == 'http://www.mipengine.org?we=123' + messageUrl = getUrl + valueJson; + } + else { + // eg. getUrl == 'http://www.mipengine.org' + valueJson = valueJson.substring(1); + messageUrl = getUrl + '?' + valueJson; + } + var message = { + event: 'mibm-jumplink', + data: { + url: messageUrl + } + }; + window.parent.postMessage(message, '*'); + } + else if (hasFetch.trim()) { + me.fetchUrl(hasFetch); + } + else { + // https请求 或 post请求 或 非iframe下不做处理 + element.getElementsByTagName('form')[0].submit(); + } + }, + + /** + * 提交时的事件 + * + * @param {HTMLElement} element form节点 + */ + submitHandle: function () { + viewer.eventAction.execute('submit', evt.target, evt); + }, + + /** + * 提交成功调用的在html on里使用的事件 + * + * @param {HTMLElement} element form节点 + */ + successHandle: function () { + if (!evt) { + return; + } + viewer.eventAction.execute('success', evt.target, evt); + }, + + /** + * 提交成功,但处理结果为失败,调用的在html on里使用的事件 + * + * @param {HTMLElement} element form节点 + */ + failHandle: function () { + if (!evt) { + return; + } + viewer.eventAction.execute('fail', evt.target, evt); + }, + + + /** + * 提交失败调用的在html on里使用的事件 + * + * @param {HTMLElement} element form节点 + */ + errorHandle: function () { + if (!evt) { + return; + } + viewer.eventAction.execute('error', evt.target, evt); + } + }; +}); diff --git a/src/mip-product-form/mip-product-form.js b/src/mip-product-form/mip-product-form.js new file mode 100644 index 000000000..61da498ed --- /dev/null +++ b/src/mip-product-form/mip-product-form.js @@ -0,0 +1,33 @@ + +/** + * @file mip-button-form 组件 + * + * @author chen + * @time 2018.8.21 + */ +define(function (require) { + var customElement = require('customElement').create(); + var form = require('./mip-product-form-fn'); + customElement.prototype.build = function () { + var element = this.element; + form.createDom(element); + + + form.initMessageEvents(element); + }; + customElement.prototype.firstInviewCallback = function () { + this.addEventAction('reload', function (event, str) { + // 页面刷新操作 + str = str ? 500 : parseInt(str, 10); + setTimeout(function () { + window.top.location.reload(); + }, str); + }); + + this.addEventAction('reset', function (event, str) { + // 页面刷新操作 + event.target.reset(); + }); + }; + return customElement; +}); diff --git a/src/mip-product-form/mip-product-form.less b/src/mip-product-form/mip-product-form.less new file mode 100644 index 000000000..651ea2662 --- /dev/null +++ b/src/mip-product-form/mip-product-form.less @@ -0,0 +1,69 @@ +mip-product-form { + position: relative; + #mip-form-cross { + position: absolute; + display: block; + padding: 6px; + width: 20px; + height: 20px; + right: 0; + background: url(//m.baidu.com/static/search/clear.png) no-repeat center; + z-index: 100; + background-size: 100% 100%; + background-origin: content-box; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0.4); + tap-highlight-color: rgba(0, 0, 0, 0.4) + } + input, + textarea, + select { + border: 1px solid #f1f1f1; + padding: 6px; + display: block; + box-sizing: border-box; + -webkit-box-sizing: border-box; + resize: none; + font-size: 16px; + } + input[type='text'], + input[type='input'], + input[type='datetime'], + input[type='email'], + input[type='number'], + input[type='tel'], + input[type='url'] { + padding-right: 30px; + + } + form { + position: relative; + } + input[type='radio'] { + display: inline + } + label { + display: block + } + div { + display: none; + color: #ec1f5c; + font-size: 12px; + text-align: left; + padding: 0 10% 0 3% + } + div[mip-mustache-rendered] { + display: block; + } + input[type='submit'] { + border: 1px solid #f1f1f1; + border-radius: 5px; + color: #333; + background-color: #d8d7d7 + } + [submit-success], + [submit-fail], + [submit-error] { + display: none; + } +} + diff --git a/src/mip-product-form/package.json b/src/mip-product-form/package.json new file mode 100644 index 000000000..bb4bd453b --- /dev/null +++ b/src/mip-product-form/package.json @@ -0,0 +1,12 @@ +{ + "name": "mip-product-form", + "version": "1.0.2", + "description":"自定义表单", + "author": { + "name": "chen", + "email": "chenweilin@258.com" + }, + "engines": { + "mip": ">=1.0.0" + } +} \ No newline at end of file diff --git a/src/mip-youbao-form/README.md b/src/mip-youbao-form/README.md new file mode 100644 index 000000000..470b78239 --- /dev/null +++ b/src/mip-youbao-form/README.md @@ -0,0 +1,98 @@ +# mip-youbao-form + +mip-youbao-form 表单组件 + +标题|内容 +----|---- +类型|通用 +支持布局|fixed +所需脚本|https://c.mipcdn.com/static/v1/mip-youbao-form/mip-youbao-form.js + +## 示例 +### 基本使用 + +```html + + +
请输入正确的电话
+ +
年龄不能为空
+ + +
请选择性别
+
+ +
+
+ +
+
+ +
+ +
+``` +## 属性 + +### method + +说明:表单提交方法 +必选项:是 + +### from + +说明:来自那张表单 +必选项:否 + +### url + +说明:必须是 HTTP(S) 或 // 开头的地址 +必选项: 是 + +### validatetarget + +说明: 验证提示对应 tag,用于对应错误时的提示显示元素的查找 +必选项:否 + +### validatetype + +说明:验证类型, 用于支持简单的验证。目前提供 `email`, `phone`, `idcar`, `custom`。当为 `custom` 时则需要填写 `validatereg` +必选项:否 + +### validatereg + +说明: 自定义验证,补充站长个性化的验证规则。如果 `validatetype` 为 `custom` 时需填写相应验证规则 +必选项:否 + +### fetch-url + +说明: 有此属性则可以开启异步请求数据逻辑,组件会并根据数据返回状态来按`submit-success`,`submit-error`块中的模板刷新局部信息。 +需要注意的几个点: + +- 方法支持。 +- 请求结果请返回 JSON 对象。 +- 数据状态只有在成功(2xx)的时候触发 `submit-success` 的逻辑,其他的均触发 `submit-error` 逻辑。 + +必选项:否 + + +### on + +说明: 添加事件清空表单 +参数使用: reload事件,传入数值控制页面刷新等待事件, reset表单数据重置事件 invalidTag(target)目标对象字段验证不通过 validTag(target)目标对象字段验证通过 +必选项: 否 + + +## 注意事项 + +1. 表单提交方法如果为 `post`,应使用 HTTPS 地址。避免 MIP-Cache HTTPS 环境提交到 HTTP,导致浏览器报错。 +2. 使用 fetch 功能时,请求使用 cors 时不能配置为 *。 \ No newline at end of file diff --git a/src/mip-youbao-form/mip-youbao-form-fn.js b/src/mip-youbao-form/mip-youbao-form-fn.js new file mode 100644 index 000000000..ab41329c7 --- /dev/null +++ b/src/mip-youbao-form/mip-youbao-form-fn.js @@ -0,0 +1,388 @@ +/** + * @file mip-form-fn.js + * @description mip-form函数 + * @author miper + */ + +define(function (require) { + var templates = require('templates'); + var util = require('util'); + var viewer = require('viewer'); + var windowInIframe = viewer.isIframed; + var evt; + var formEle; + var REGS = { + EMAIL: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/, + PHONE: /^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/, + IDCAR: /^\d{15}|\d{18}$/ + }; + return { + + /** + * 处理fetch请求逻辑 + * + * @param {string} url 请求url + */ + fetchUrl: function (url) { + var me = this; + util.css([me.successEle, me.failEle, me.errorEle], {display: 'none'}); + + // 获取CSRF-TOKEN + var tokenDom = document.querySelector('meta[name="csrf-token"]'); + if (tokenDom) { + var token = tokenDom.getAttribute('content'); + } + + var fetchData = { + method: me.method, + credentials: 'include', + headers: new Headers({ + 'X-Requested-With': 'XMLHttpRequest', + 'Accept': 'application/json', + 'X-CSRF-TOKEN': token ? token : '' + }) + }; + if (me.method === 'POST') { + var formD = me.ele.querySelector('form'); + if (formD) { + fetchData = util.fn.extend({}, fetchData, { + body: new FormData(formD) + }); + } + } + + // 数据请求处理 + fetch(url, fetchData).then(function (res) { + if (res.ok) { + res.json().then(function (data) { + if (data.status === 1) { + util.css(me.successEle, {display: 'block'}); + me.renderTpl(me.successEle, {successinfo: data.info}); + me.submitSuccessHandle(); + } + if (data.status === -1) { + util.css(me.failEle, {display: 'block'}); + me.renderTpl(me.failEle, {failinfo: data.info}); + me.submitFailHandle(); + } + }).catch(function (err) { + me.fetchReject(err); + }); + } + else { + me.submitErrorHandle(); + me.fetchReject({}); + } + }).catch(function (err) { + me.submitErrorHandle(); + me.fetchReject(err); + }); + }, + + /** + * fetch出错逻辑处理 + * + * @param {Object} err 错误对象 + */ + fetchReject: function (err) { + var me = this; + util.css(me.errorEle, {display: 'block'}); + me.renderTpl(me.errorEle, err); + }, + + /** + * 处理模板渲染 + * + * @param {HTMLElement} ele 模板父节点 + * @param {Object} data 模板渲染数据 + */ + renderTpl: function (ele, data) { + var me = this; + templates.render(ele, data).then(function (html) { + var tempTarget = me.tempHTML(ele); + tempTarget.innerHTML = html; + }); + }, + + /** + * 处理模板渲染 + * + * @param {HTMLElement} ele 渲染后模板父节点 + * @return {HTMLElement} target 新建DOM节点 + */ + tempHTML: function (ele) { + ele = ele || document; + var target = ele.querySelector('[mip-mustache-rendered]'); + if (!target) { + target = util.dom.create('
'); + ele.appendChild(target); + } + return target; + }, + + /** + * createDom 创建 form 节点 + * + * @param {HTMLElement} element 组件节点 + */ + createDom: function (element) { + formEle = element; + var me = this; + var url = element.getAttribute('url'); + var target = element.getAttribute('target'); + var form = document.createElement('form'); + var method = (element.getAttribute('method') || 'GET').toUpperCase(); + form.action = url; + form.method = method; + target = target ? target : '_blank'; + form.target = viewer.isIframed && target !== '_blank' ? '_top' : target; + element.appendChild(form); + util.dom.insert(form, element.children); + + // 按钮提交 + var curEles = element.querySelectorAll('form'); + Array.prototype.forEach.call(curEles, function (item) { + item.addEventListener('submit', function (event) { + event.preventDefault(); + evt = event; + me.onSubmit(element, event); + }); + }); + + // 部分浏览器回车不触发submit, + element.addEventListener('keydown', function (event) { + if (event.keyCode === 13) { + + // 为了使余下浏览器不多次触发submit, 使用prevent + evt = event; + event.preventDefault(); + me.onSubmit(this); + } + }, false); + }, + + /** + * 事件通信 + * + * @description 在 input focus 或 blur 时向iframe外层文档发送数据,iframe外层文档返回设置预览头部为 absolute + * @param {Object} event 事件对象 + */ + sendFormMessage: function (event) { + if (windowInIframe) { + // mip_video_jump 为写在外层的承接方法 + viewer.sendMessage('input-' + event, {}); + } + }, + + /** + * 事件发送处理 + * + * @description 给 input 绑定事件,向 SF 发送数据,为了解决 ios 的 UC 浏览器在iframe外层文档悬浮头部 fixed 位置混乱问题 + * @param {HTMLElement} element mip 组件标签 + */ + initMessageEvents: function (element) { + var me = this; + var inputAll = element.querySelectorAll('input'); + Array.prototype.forEach.call(inputAll, function (item, index) { + item.addEventListener('focus', function () { + me.sendFormMessage('focus'); + }, false); + + item.addEventListener('blur', function () { + me.sendFormMessage('blur'); + }, false); + }); + }, + + /** + * 文案格式验证 + * + * @param {string} type 验证类型 + * @param {string} value 需要验证的文案 + * @param {HTMLElement} target dom元素 + * @return {boolean} 是否符合自定义校验 + */ + verification: function (type, value, target) { + if (target.type === 'radio' || target.type === 'checkbox') { + var selector = 'input[type="' + target.type + '"][name="' + target.name + '"]'; + var sameEle = this.ele.querySelectorAll(selector); + var checked = false; + for (var i in sameEle) { + if (sameEle[i].checked) { + checked = true; + } + } + return checked; + } + return (type === 'must') ? !(value === '') : REGS[type.toUpperCase()].test(value); + }, + + /** + * 点击提交按钮事件处理函数 + * + * @param {HTMLElement} element form节点 + */ + onSubmit: function (element) { + var me = this; + var preventSubmit = false; + var inputs = element.querySelectorAll('input, textarea, select'); + var url = element.getAttribute('url') || ''; + var getUrl = url.toLowerCase(); + var isHttp = getUrl.match('http://'); + var valueJson = ''; + var hasFetch = element.getAttribute('fetch-url') || ''; + me.method = (element.getAttribute('method') || 'GET').toUpperCase(); + var isGet = me.method === 'GET'; + + this.ele = element; + this.successEle = element.querySelector('[submit-success]'); + this.failEle = element.querySelector('[submit-fail]'); + this.errorEle = element.querySelector('[submit-error]'); + // 执行提交句柄 + me.submitHandle(); + // 校验输入内容是否合法 + Array.prototype.forEach.call(inputs, function (item) { + var type = item.getAttribute('validatetype'); + var target = item.getAttribute('validatetarget'); + var regval = item.getAttribute('validatereg'); + var value = item.value; + var reg; + + if (item.type === 'submit') { + return; + } + else if (item.type === 'checkbox' || item.type === 'radio') { + value = item.checked ? item.value : ''; + } + + valueJson += '&' + item.name + '=' + value; + if (type) { + if (regval) { + reg = value === '' ? false : (new RegExp(regval)).test(value); + } + else { + reg = me.verification(type, value, item); + } + + // 显示表单错误信息 + if (reg) { + me.validHandle(target); + } + else { + me.invalidHandle(target); + } + + preventSubmit = !reg ? true : preventSubmit; + } + }); + + if (preventSubmit) { + return; + } + + // 在iframe下使用mibm-jumplink,跳转显示手百框。 http-GET请求交给外层跳转 + if (window.parent !== window && isHttp && isGet) { + var messageUrl = ''; + if (getUrl.match('\\?')) { + // eg. getUrl == 'http://www.mipengine.org?we=123' + messageUrl = getUrl + valueJson; + } + else { + // eg. getUrl == 'http://www.mipengine.org' + valueJson = valueJson.substring(1); + messageUrl = getUrl + '?' + valueJson; + } + var message = { + event: 'mibm-jumplink', + data: { + url: messageUrl + } + }; + window.parent.postMessage(message, '*'); + } + else if (hasFetch.trim()) { + me.fetchUrl(hasFetch); + } + else { + // https请求 或 post请求 或 非iframe下不做处理 + element.getElementsByTagName('form')[0].submit(); + } + }, + + /** + * 显示对应字段的错误信息 + * + * @param {string} target 表单验证目标 + * @return {void} 无返回值 + */ + invalidHandle: function (target) { + var targetEle = formEle.querySelectorAll('div[target="' + target + '"]'); + if (!targetEle) { + console.log('验证对象target不存在'); + return; + } + util.css(targetEle, {display: 'block'}); + }, + + /** + * 显示对应字段的错误信息 + * + * @param {string} target 表单验证目标 + * @return {void} 无返回值 + */ + validHandle: function (target) { + var targetEle = formEle.querySelectorAll('div[target="' + target + '"]'); + if (!targetEle) { + console.log('验证对象target不存在'); + return; + } + util.css(targetEle, {display: 'none'}); + }, + + + /** + * 提交时的事件 + * + * @param {HTMLElement} element form节点 + */ + submitHandle: function () { + viewer.eventAction.execute('submit', evt.target, evt); + }, + + /** + * 提交成功调用的在html on里使用的事件 + * + * @param {HTMLElement} element form节点 + */ + submitSuccessHandle: function () { + if (!evt) { + return; + } + viewer.eventAction.execute('submitSuccess', evt.target, evt); + }, + + /** + * 提交成功调用的在html on里使用的事件 + * + * @param {HTMLElement} element form节点 + */ + submitFailHandle: function () { + if (!evt) { + return; + } + viewer.eventAction.execute('submitFail', evt.target, evt); + }, + + /** + * 提交失败调用的在html on里使用的事件 + * + * @param {HTMLElement} element form节点 + */ + submitErrorHandle: function () { + if (!evt) { + return; + } + viewer.eventAction.execute('submitError', evt.target, evt); + } + }; +}); diff --git a/src/mip-youbao-form/mip-youbao-form.css b/src/mip-youbao-form/mip-youbao-form.css new file mode 100644 index 000000000..af2d33710 --- /dev/null +++ b/src/mip-youbao-form/mip-youbao-form.css @@ -0,0 +1 @@ +mip-youbao-form{position:relative}mip-youbao-form .btnCode{display:block;padding:10px;color:#fff}mip-youbao-form #mip-form-cross{position:absolute;display:block;padding:6px;width:20px;height:20px;right:0;background:url(//m.baidu.com/static/search/clear.png) no-repeat center;z-index:100;background-size:100% 100%;background-origin:content-box;-webkit-tap-highlight-color:rgba(0,0,0,.4);tap-highlight-color:rgba(0,0,0,.4)}mip-youbao-form input,mip-youbao-form textarea,mip-youbao-form select{border:1px solid #f1f1f1;padding:6px;display:block;box-sizing:border-box;-webkit-box-sizing:border-box;resize:none;font-size:16px}mip-youbao-form input[type=text],mip-youbao-form input[type=input],mip-youbao-form input[type=datetime],mip-youbao-form input[type=email],mip-youbao-form input[type=number],mip-youbao-form input[type=tel],mip-youbao-form input[type=url]{padding-right:30px}mip-youbao-form form{position:relative}mip-youbao-form input[type=radio]{display:inline}mip-youbao-form label{display:block}mip-youbao-form .error{display:none;color:#ec1f5c;font-size:12px;text-align:left;line-height:22px;padding:0 10% 0 3%}mip-youbao-form .error[mip-mustache-rendered]{display:block}mip-youbao-form input[type=submit]{border:1px solid #f1f1f1;border-radius:5px;color:#333;background:#d8d7d7}mip-youbao-form [submit-success],mip-youbao-form [submit-error]{display:none} \ No newline at end of file diff --git a/src/mip-youbao-form/mip-youbao-form.js b/src/mip-youbao-form/mip-youbao-form.js new file mode 100644 index 000000000..556985e25 --- /dev/null +++ b/src/mip-youbao-form/mip-youbao-form.js @@ -0,0 +1,41 @@ +/** + * @file mip-258-form 组件 + * @author + */ + +define(function (require) { + var customElement = require('customElement').create(); + var form = require('./mip-youbao-form-fn'); + + customElement.prototype.build = function () { + var element = this.element; + form.createDom(element); + form.initMessageEvents(element); + }; + customElement.prototype.firstInviewCallback = function () { + + // 页面刷新事件 + this.addEventAction('reload', function (event, str) { + str = str ? 500 : parseInt(str, 10); + setTimeout(function () { + window.top.location.reload(); + }, str); + }); + + // 表单数据重置事件 + this.addEventAction('reset', function (event, str) { + event.target.reset(); + }); + + // 验证错误事件 + this.addEventAction('invalidTag', function (event, target) { + form.invalidHandle(target); + }); + + // mip?尼玛B,我34行哪里多空格了,艹。5min写东西,10min调格式 + this.addEventAction('validTag', function (event, target) { + form.validHandle(target); + }); + }; + return customElement; +}); diff --git a/src/mip-youbao-form/mip-youbao-form.less b/src/mip-youbao-form/mip-youbao-form.less new file mode 100644 index 000000000..b6062239d --- /dev/null +++ b/src/mip-youbao-form/mip-youbao-form.less @@ -0,0 +1,74 @@ +mip-youbao-form { + position: relative; + .btnCode { + display: block; + padding: 10px; + color: #fff; + } + #mip-form-cross { + position: absolute; + display: block; + padding: 6px; + width: 20px; + height: 20px; + right: 0; + background: url('//m.baidu.com/static/search/clear.png') no-repeat center; + z-index: 100; + background-size: 100% 100%; + background-origin: content-box; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0.4); + tap-highlight-color: rgba(0, 0, 0, 0.4) + } + input, + textarea, + select { + border: 1px solid #f1f1f1; + padding: 6px; + display: block; + box-sizing: border-box; + -webkit-box-sizing: border-box; + resize: none; + font-size: 16px; + } + input[type='text'], + input[type='input'], + input[type='datetime'], + input[type='email'], + input[type='number'], + input[type='tel'], + input[type='url'] { + padding-right: 30px; + } + form { + position: relative; + } + input[type='radio'] { + display: inline + } + label { + display: block + } + .error { + display: none; + color: #ec1f5c; + font-size: 12px; + text-align: left; + line-height: 22px; + padding: 0 10% 0 3% + } + .error[mip-mustache-rendered] { + display: block; + } + input[type='submit'] { + border: 1px solid #f1f1f1; + border-radius: 5px; + color: #333; + background: #d8d7d7; + } + [submit-success], + [submit-fail], + [submit-error] { + display: none; + } +} + diff --git a/src/mip-youbao-form/package.json b/src/mip-youbao-form/package.json new file mode 100644 index 000000000..c59be345d --- /dev/null +++ b/src/mip-youbao-form/package.json @@ -0,0 +1,14 @@ +{ + "name": "mip-youbao-form", + "version": "1.0.0", + "description": "youbao表单提交", + "contributors": [ + { + "name": "teemor", + "email": "232957726@qq.com" + } + ], + "engines": { + "mip": ">=1.1.0" + } +}