【问题标题】:observable Scrubber notebook convertion into vanilla JS可观察的 Scrubber 笔记本转换为香草 JS
【发布时间】:2021-11-20 16:23:49
【问题描述】:

我正在尝试将 observablehq 'Scrubber' notebook 转换为 vanilla JS。我当前的代码如下所示:

<!DOCTYPE html>
<meta charset="utf-8">
<title>Scrubber</title>
<link rel="stylesheet" type="text/css" href="./inspector.css">
<body>
    <div class="test"></div>
    <script>
dates = ["2018-12-31T23:00:00.000Z","2019-01-01T23:00:00.000Z"]
function Scrubber(container, values, 
  format = value => value,
  initial = 0,
  delay = null,
  autoplay = true,
  loop = true,
  loopDelay = null,
  alternate = false) {
  values = Array.from(values);
  const form = '<form style="font: 12px var(--sans-serif); font-variant-numeric: tabular-nums; display: flex; height: 33px; align-items: center;">\
  <button name=b type=button style="margin-right: 0.4em; width: 5em;"></button>\
  <label style="display: flex; align-items: center;">\
    <input name=i type=range min=0 max=${values.length - 1} value=${initial} step=1 style="width: 180px;">\
    <output name=o style="margin-left: 0.4em;"></output>\
  </label>\
</form>';
  let frame = null;
  let timer = null;
  let interval = null;
  let direction = 1;
  function start() {
    form.b.textContent = "Pause";
    if (delay === null) frame = requestAnimationFrame(tick);
    else interval = setInterval(tick, delay);
  }
  function stop() {
    form.b.textContent = "Play";
    if (frame !== null) cancelAnimationFrame(frame), frame = null;
    if (timer !== null) clearTimeout(timer), timer = null;
    if (interval !== null) clearInterval(interval), interval = null;
  }
  function running() {
    return frame !== null || timer !== null || interval !== null;
  }
  function tick() {
    if (form.i.valueAsNumber === (direction > 0 ? values.length - 1 : direction < 0 ? 0 : NaN)) {
      if (!loop) return stop();
      if (alternate) direction = -direction;
      if (loopDelay !== null) {
        if (frame !== null) cancelAnimationFrame(frame), frame = null;
        if (interval !== null) clearInterval(interval), interval = null;
        timer = setTimeout(() => (step(), start()), loopDelay);
        return;
      }
    }
    if (delay === null) frame = requestAnimationFrame(tick);
    step();
  }
  function step() {
    form.i.valueAsNumber = (form.i.valueAsNumber + direction + values.length) % values.length;
    form.i.dispatchEvent(new CustomEvent("input", {bubbles: true}));
  }
  

  form.i.oninput = event => {
    if (event && event.isTrusted && running()) stop();
    form.value = values[form.i.valueAsNumber];
    form.o.value = format(form.value, form.i.valueAsNumber, values);
  };
  form.b.onclick = () => {
    if (running()) return stop();
    direction = alternate && form.i.valueAsNumber === values.length - 1 ? -1 : 1;
    form.i.valueAsNumber = (form.i.valueAsNumber + direction) % values.length;
    form.i.dispatchEvent(new CustomEvent("input", {bubbles: true}));
    start();
  };
  form.i.oninput();
  if (autoplay) start();
  else stop();
  Inputs.disposal(form).then(stop);
  return form;
}  
Scrubber(".test", dates)
    </script>
</body>

但我收到以下错误:Uncaught TypeError: Cannot set properties of undefined (setting 'oninput') at Scrubber。

这似乎应该是一个新功能,但我该怎么做呢?

提前感谢您的帮助。

【问题讨论】:

    标签: javascript observable


    【解决方案1】:

    form 只是一个未定义的字符串。我在 DOM 中附加了表单字符串并访问了表单节点,也许它会帮助你。

    <!DOCTYPE html>
    <meta charset="utf-8">
    <title>Scrubber</title>
    <link rel="stylesheet" type="text/css" href="./inspector.css">
    <body>
        <div class="test"></div>
        <script>
    dates = ["2018-12-31T23:00:00.000Z","2019-01-01T23:00:00.000Z"]
    function Scrubber(container, values, 
      format = value => value,
      initial = 0,
      delay = null,
      autoplay = true,
      loop = true,
      loopDelay = null,
      alternate = false) {
      values = Array.from(values);
      const formString = '<form style="font: 12px var(--sans-serif); font-variant-numeric: tabular-nums; display: flex; height: 33px; align-items: center;">\
      <button name=b type=button style="margin-right: 0.4em; width: 5em;"></button>\
      <label style="display: flex; align-items: center;">\
        <input name=i type=range min=0 max=${values.length - 1} value=${initial} step=1 style="width: 180px;">\
        <output name=o style="margin-left: 0.4em;"></output>\
      </label>\
    </form>';
    
        document.querySelector(container).innerHTML = formString;
    
        const form = document.querySelector(container + ' form');
    
      let frame = null;
      let timer = null;
      let interval = null;
      let direction = 1;
      function start() {
        form.b.textContent = "Pause";
        if (delay === null) frame = requestAnimationFrame(tick);
        else interval = setInterval(tick, delay);
      }
      function stop() {
        form.b.textContent = "Play";
        if (frame !== null) cancelAnimationFrame(frame), frame = null;
        if (timer !== null) clearTimeout(timer), timer = null;
        if (interval !== null) clearInterval(interval), interval = null;
      }
      function running() {
        return frame !== null || timer !== null || interval !== null;
      }
      function tick() {
        if (form.i.valueAsNumber === (direction > 0 ? values.length - 1 : direction < 0 ? 0 : NaN)) {
          if (!loop) return stop();
          if (alternate) direction = -direction;
          if (loopDelay !== null) {
            if (frame !== null) cancelAnimationFrame(frame), frame = null;
            if (interval !== null) clearInterval(interval), interval = null;
            timer = setTimeout(() => (step(), start()), loopDelay);
            return;
          }
        }
        if (delay === null) frame = requestAnimationFrame(tick);
        step();
      }
      function step() {
        form.i.valueAsNumber = (form.i.valueAsNumber + direction + values.length) % values.length;
        form.i.dispatchEvent(new CustomEvent("input", {bubbles: true}));
      }
      
    
      form.i.oninput = (event) => {
        if (event && event.isTrusted && running()) stop();
        form.value = values[form.i.valueAsNumber];
        form.o.value = format(form.value, form.i.valueAsNumber, values);
      };
    
      form.b.onclick = () => {
        if (running()) return stop();
        direction = alternate && form.i.valueAsNumber === values.length - 1 ? -1 : 1;
        form.i.valueAsNumber = (form.i.valueAsNumber + direction) % values.length;
        form.i.dispatchEvent(new CustomEvent("input", {bubbles: true}));
        start();
      };
      form.i.oninput();
      if (autoplay) start();
      else stop();
      Inputs.disposal(form).then(stop);
      return form;
    }  
    Scrubber(".test", dates)
        </script>
    </body>
    

    代码还有其他问题,但原始问题已修复,滑块现在可以正常工作。

    【讨论】:

      猜你喜欢
      • 2022-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-29
      • 1970-01-01
      • 2015-05-12
      • 1970-01-01
      相关资源
      最近更新 更多