eva-engine / 2021questions

12 stars 1 forks source link

2020-02-13 实现以下功能 #8

Open fanmingfei opened 4 years ago

fanmingfei commented 4 years ago

题目: html

<div id="people"></div>
<div id="language"></div>

javascript

//  在此处增加代码
function People() {
  const [name, setName] = useState('LiLei')
  const [old, setOld] = useState(1)
  let i = 1
  setInterval(()=>{
    i++
    console.log(i)
    setOld(i)
  }, 1000)

  return tmpl`<div>My name is ${name}, I\'m ${old} years old.</div>`;  
}

function Language() {
  const [language, setLanguage] = useState('Toy')

  setTimeout(()=>{
    setLanguage('HTML')
  }, 2000)
  setTimeout(()=>{
    setLanguage('CSS')
  }, 4000)
  setTimeout(()=>{
    setLanguage('JavaScript')
  }, 6000)

  return tmpl`<div>I love ${language}</div>`
}

render(document.querySelector('#people'), People)
render(document.querySelector('#language'), Language)

在 javascript 最上面增加代码,实现以下效果。

效果图:

xiaosen7 commented 4 years ago

html

<div id="people"></div>
<div id="language"></div>

js

const renderList = [];

        const firstMemoized = { value: null, next: null };
        let currentMemoized = firstMemoized;

        function reRender(memoized) {
            currentMemoized = firstMemoized
            renderList.forEach(r => r());
        }

        function render(container, component) {
            renderList.push(() => container.innerHTML = component());
            container.innerHTML = component();
        }

        function tmpl(iterators, ...params) {
            return iterators.reduce((a, b, index) => a + params[index - 1] + b)
        }

        const setTimeout = (...args) => {
            const memoized = currentMemoized.next ? currentMemoized.next : (window.setTimeout(...args), currentMemoized.next = { value: undefined, next: null });
            currentMemoized = currentMemoized.next;
        }
        const setInterval = (...args) => {
            const memoized = currentMemoized.next ? currentMemoized.next : (window.setInterval(...args), currentMemoized.next = { value: undefined, next: null });
            currentMemoized = currentMemoized.next;
        }

        function useState(initialValue) {

            const memoized = currentMemoized.next ? currentMemoized.next : currentMemoized.next = { value: initialValue, next: null };
            currentMemoized = currentMemoized.next;
            const setState = newValue => (memoized.value = newValue) && reRender();
            return [
                memoized.value,
                setState
            ]
        }

        function People() {
            const [name, setName] = useState('LiLei')
            const [old, setOld] = useState(1)
            let i = 1
            setInterval(() => {
                i++
                console.log(i)
                setOld(i)
            }, 1000)

            return tmpl`<div>My name is ${name}, I\'m ${old} years old.</div>`;
        }

        function Language() {
            const [language, setLanguage] = useState('Toy')

            setTimeout(() => {
                setLanguage('HTML')
            }, 2000)
            setTimeout(() => {
                setLanguage('CSS')
            }, 4000)
            setTimeout(() => {
                setLanguage('JavaScript')
            }, 6000)

            return tmpl`<div>I love ${language}</div>`
        }

        render(document.querySelector('#people'), People)
        render(document.querySelector('#language'), Language)
LiZhaji commented 4 years ago
    const {render, useState, tmpl} = outer()

    function outer() {
      const cache = {}
      let curComponent
      const render = (node, component) => {
        curComponent = component.name
        const tpl = component()
        cache[component.name] = () => node.innerHTML = parse(tpl)
        node.innerHTML = parse(tpl)
      }

      const useState = initValue => {
        const component = curComponent

        const data = {value: initValue}
        const setData = newValue => {
          data.value = newValue
          cache[component]()
        }
        return [data, setData]
      }

      const parse = tpl =>  {
        const [strings, ...varis] = tpl
        return strings.reduce((res, item, i) => {
          res = res.concat(item, varis.slice(i, i+1)[0]?.value)
          return res
        },[]).join('')
      }

      const tmpl = (...p) => p

      return {render, useState, tmpl}
    }

    function People() {
      const [name, setName] = useState('LiLei')
      const [old, setOld] = useState(1)
      let i = 1
      setInterval(()=>{
        i++
        setOld(i)
      }, 1000)

      return tmpl`<div>My name is ${name}, I\'m ${old} years old.</div>`;  
    }

    function Language() {
      const [language, setLanguage] = useState('Toy')

      setTimeout(()=>{
        setLanguage('HTML')
      }, 2000)
      setTimeout(()=>{
        setLanguage('CSS')
      }, 4000)
      setTimeout(()=>{
        setLanguage('JavaScript')
      }, 6000)

      return tmpl`<div>I love ${language}</div>`
    }

    render(document.querySelector('#people'), People)
    render(document.querySelector('#language'), Language)
fanmingfei commented 4 years ago
const makeHook = (hooks) => {
  let currentComponent

  let fns = {}
  for(let fnName in hooks) {
    fns[fnName] = (...args)=> hooks[fnName](currentComponent)(...args)
  }

  return {
    setComponent(Component) {
      currentComponent = Component
    },
    hooks: fns
  }
}

function createEvent () {
  const map = new Map()
  return (Component) => {
    if (map.has(Component)) return map.get(Component)
    const events = new Map()
    const obj = {
      on(name, fn) {
        if (!events.has(name)) events.set(name, [])
        events.get(name).push(fn)
      },
      emit(name, ...args) {
        console.log(name, ...args)
        if (!events.get(name)) return false
        for (let fn of events.get(name)) {
          fn instanceof Function && fn(...args);
        }
      }
    }
    map.set(Component, obj)
    return obj
  }
}

const makeEvent = createEvent()

const current = {}

const hooks = makeHook({
  useState: Component => initialValue => {
    let value = {value: initialValue}
    const setValue = (newValue)=> {
      console.log(newValue)
      value.value = newValue
      makeEvent(Component).emit('stateChange', value)
    }

    return [value, setValue]
  },
  useStateChange: Component => (callback) => {
    makeEvent(Component).on('stateChange', (value)=>callback(value))
  },

})

function makeHTML (tmpl) {
  const html = [...tmpl[0]].reduce((str, curr, i)=>{
    let {value} = tmpl[i] || {value: ''}
    return str += value + curr
  })
  return html
}

const { useState, useStateChange } = hooks.hooks

function render(dom, Component) {
  hooks.setComponent(Component)
  const tmpl = Component()
  useStateChange(()=>{
    dom.innerHTML = makeHTML(tmpl)
  })
  dom.innerHTML = makeHTML(tmpl)

}

const tmpl = (...arg)=>arg

function People() {
  const [name, setName] = useState('LiLei')
  const [old, setOld] = useState(1)
  let i = 1
  setInterval(()=>{
    i++
    setOld(i)
  }, 1000)

  return tmpl`<div>My name is ${name}, I\'m ${old} years old.</div>`;  
}

function Language() {
  const [language, setLanguage] = useState('Toy')

  setTimeout(()=>{
    setLanguage('HTML')
  }, 2000)
  setTimeout(()=>{
    setLanguage('CSS')
  }, 4000)
  setTimeout(()=>{
    setLanguage('JavaScript')
  }, 6000)

  return tmpl`<div>I love ${language}</div>`
}

render(document.querySelector('#people'), People)
render(document.querySelector('#language'), Language)