Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

按钮控件封装应该提供事务处理

  如果说写一个按钮控件,也许直接基于 button 标签再加个 CSS 的 class 就写出来了。但我觉得那种程度的东西只能算是个皮肤吧?按钮其实是很复杂的存在,比如 disabled 状态之类的情况开关、按钮文字修改、点击事件的绑定方式等。有一大堆须有按钮控件提供 API 的地方。
  目前所有的按钮 API 几乎都是在模拟 DOM 原生的 button 行为。但我觉得 DOM 原生的 button 真的设计得太烂了!它就相当于一个普通的 DOM 元素,一点按钮的特性都没有。也难怪大家会使用 a 标签来代替 button 了。反正我使用按钮时经常要写一堆代码来防止重复提交并有好地告诉用户提交中的状态。这件事为什么不是由按钮直接承包呢?
<style>
button {
  border: 0;
  border-radius: 4px;
  background: #38f;
  color: #fff;
  cursor: pointer;
}
button:hover { opacity: .8; }
button.busy { opacity: .5; cursor: wait; }
</style>
<button>提交</button>
<script>
var button = document.querySelector('button');
button.addEventListener('click', function() {
  // 防止重复提交
  if(button.classList.contains('busy')) return;
  // 设为忙碌状态
  button.classList.add('busy');
  // 假如此处有个需要两秒的异步事务
  new Promise(function(resolve, reject) {
    setTimeout(resolve, 2000);
  }).then(function() {
    console.log('success');
  }, function() {
    console.log('error');
  }).then(function() {
    // 恢复按钮状态
    button.classList.remove('busy');
  });
});
</script>
  我觉得对事务执行状态的展示应该也属于按钮的职责。一个按钮点击后会处理一个异步事务,那么在这个事务完成前按钮应该陷入不可点击的状态,甚至上面的文字和样式都需要有相应的调整,直到事务执行结束后才恢复按钮。这一系列过程都应该由按钮直接提供,而不是需要手动完成。
  下面这个代码是一个简易实现,然而它已经简易到连封装都算不上了,只是一个 Demo <style>
button {
  border: 0;
  border-radius: 4px;
  background: #38f;
  color: #fff;
  cursor: pointer;
}
button:hover { opacity: .8; }
button.busy { opacity: .5; cursor: wait; }
</style>
<script>
addEventListener('click', function(event) {
  var button = event.target;
  if(button.tagName !== 'BUTTON') return;
  if(typeof button.action !== 'function') return;
  if(button.classList.contains('busy')) return;
  button.classList.add('busy');
  button.action().then(function() {
    button.classList.remove('busy');
  });
});
</script>
<button>提交</button>
<script>
var button = document.querySelector('button');
button.action = function() {
  return new Promise(function(resolve, reject) {
    setTimeout(resolve, 2000);
  });
};
</script>
  这里把在按钮上扩展了一个 action 属性,然后绑定一个返回 Promise 的函数上去。当按钮点击时将自己设置为 busy 状态,然后 action 被执行。直到 action 返回的 Promise 完成后按钮状态才还原。这样使用起来就方便地多了,而且如果支持 ES7 的话可以这么玩 button.action = async function() {
  // await something
  // and do something
};
  上面这一套只是我一拍脑子想出来的,而且只是个简易的 Demo 而已,千万别直接用。直接在原生上扩展东西就有违我的设计风格的,只是写文章的时候懒得折腾完整可用代码而已。
网名:
34.203.213.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^