vue v-for编译组件

10 篇文章 0 订阅
2 篇文章 0 订阅
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <div id="app"></div>
  <script type="module" src="app.js"></script>
</body>
</html>
/**
 * vite   npm init -y   npm i vite -D     vite 运行 
 */

import { createApp } from '.mvvm'
import testA from './components/testA'
import testB from './components/testB'


const app = createApp({
  components: [
    testA,
    testB
  ]
})

app.mount('#app')
/**
 * testA
 * 
 */
import { createReactive } from '../..mvvm'

const template = `
 <ul class='list'>
    <h1>{{ title }}</h1>
    {{dataTime}}
    <for data="list" tag="li" class="item">
      <span>姓名:{ name } </span>
      <span>年龄:{ age }</span>
    </for>
 </ul>
`
function testA() {
  const state = createReactive({
    title: '学生信息列表',
    dataTime: '2022-07-14 10:30',
    list: [
      { id: 1, name: '爱辉', age: '18' },
      { id: 2, name: '黄勇', age: '28' },
      { id: 3, name: '钟文', age: '20' },
    ]
  })
  return [template, state]
}

export default testA



/**
 * testB
 * 
 */
import { createReactive } from '../..mvvm'

const template = `
 <ul class='list'>
    <h1>{{ title }}</h1>
    {{dataTime}}
    <for data="list" tag="li" class="item">
      <span>Name: { name } </span>
      <span>age:{ age }</span>
    </for>
 </ul>
`
function testB() {
  const state = createReactive({
    title: '老师信息列表',
    dataTime: '2022-07-14 10:30',
    list: [
      { id: 1, name: '小红', age: '48' },
      { id: 2, name: '小名', age: '58' },
      { id: 3, name: '小李', age: '68' },
    ]
  })
  return [template, state]
}

export default testB
//mvvm.js
export { createApp } from './application'
export { createReactive } from './reactive'
//application.js
import { compileTemplate } from "./compile";

const domNodePool = []
export function createApp(options) {
  for (let option in options) {
    switch (option) {
      case 'components':
        initComponent(options[option]);
        break;
      default:
        break;
    }
  }

  return {
    mount
  }
}

function initComponent(components) {
  for (let component of components) {
    let [template, state] = component()
    console.log(template, state)
    const node = compileTemplate(template, state)
    domNodePool.push(node)
  }
}

function mount(el) {
  const app = document.querySelector(el)
  const oFrag = document.createDocumentFragment()
  domNodePool.forEach(node => {
    oFrag.appendChild(node)
  })

  app.appendChild(oFrag)
}


//compile.js
const customTags = ['if', 'for']
const reg_single_brancket = /\{(.*?)\}/g
const reg_double_brancket = /\{\{(.*?)\}\}/g

export function compileTemplate(template, data) {
  template = replaceVar(template, data, reg_double_brancket)
  const _node = document.createElement('div')
  _node.innerHTML = template
  return compileNode(_node, data)
}

function compileNode(node, data) {
  const allNodes = node.querySelectorAll('*');
  allNodes.forEach(item => {
    const tagName = item.tagName.toLowerCase()
    if (customTags.includes(tagName)) {
      replaceNode(item, tagName, data)
    }
  })
  return [...node.childNodes].find(item => item.nodeType === 1)
}

function replaceNode(node, tag, data) {
  const dataKey = node.getAttribute('data')
  const className = node.className
  const realTag = node.getAttribute('tag')
  switch (tag) {
    case 'for':
      vFor(node, data, dataKey, className, realTag);
      break;
    default:
      break;
  }
}

function vFor(node, data, dataKey, className, realTag) {
  const oFrag = document.createDocumentFragment()
  data[dataKey].forEach(item => {
    // console.log(node, data, dataKey, className, realTag)

    const el = document.createElement(realTag)
    el.className = className || ''
    el.innerHTML = replaceVar(node.innerHTML, item, reg_single_brancket)
    oFrag.appendChild(el)
  })
  node.parentNode.replaceChild(oFrag, node)
}

function replaceVar(html, data, reg) {
  return html.replace(reg, (node, key) => {
    //replace 正则后接一个函数 参数为 1.匹配到的内容2子表达式3匹配的内容在字符串中出现的位置4.字符串本身
    //$1  $2 ...todo...
    const obj = {}
    key = key.trim()
    return obj[key] = data[key]//这里为什么要赋值一份呢?
  })
}
//reactive.js
import { isObject } from './utils'
import { proxyHandler } from './proxyHandler'


export function createReactive(data) {
  return createReactiveData(data, proxyHandler)
}

function createReactiveData(data, proxyHandler) {
  if (!isObject(data)) return
  return new Proxy(data, proxyHandler)
}
//proxyHandler.js

import { createReactive } from "./reactive"
import { isObject } from "./utils"


const get = createGetter()
const set = createSetter()

function createGetter() {
  return function (target, key, receiver) {
    const res = Reflect.get(target, key, receiver)
    if (isObject(res)) {
      return createReactive(res)
    }
    return res     //此处必须return  否则会错误
  }
}
function createSetter() {
  return function (target, key, value, receiver) {
    return Reflect.set(target, key, value, receiver)
  }
}

export const proxyHandler = {
  get,
  set
}
//utils.js

export function isObject(data) {
  return typeof data === 'object' && data != null
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值