组件就是一组 DOM 元素的封装,本质就是一个对象
(mounted函数中打印一下组件即可看到打印的是一个对象)
如何利用javascript对象来描述一个组件?
- const MyComponent = {
- render() {
- return {
- tag: 'div',
- props: {
- onClick: () => alert('hello')
- },
- children: 'click Me'
- }
- }
- }
-
- const vnode = {
- tag: MyComponent
- }
如何修改渲染器的内容?渲染函数时写的只是针对虚拟节点不是针对组件(即传入一个对象)
虚拟节点为字符串时:手写Vue渲染器render函数-CSDN博客
重点:和普通字符串tag不同的时,判断vnode.tag是一个组件时,通过组件的render函数获取组件对象的虚拟节点
- <div id="app">div>
- <script>
- // 手写render函数组件对象渲染到页面
- /*重点:
- 使用vnode.tag作为创建的dom标签el(判断vnode.tag是一个组件时,通过组件的render函数获取组件对象的虚拟节点)
- */
-
- /**
- * @vnode 虚拟 DOM 对象
- * @container 一个真实 DOM 元素,作为挂载点,渲染器会把虚拟 DOM 渲染到该挂载点
- */
- function render(vnode, container) {
-
- // 通过判断vode的tag为对象则为组件渲染
- if(typeof vnode.tag === "string"){
- mount(vnode, container);
- }else if(typeof vnode.tag === "object"){
- let comVnode = vnode.tag.render();
- mount(comVnode, container);
- }else{
- // ...其他操作
- }
- }
-
- // tag为字符串时的渲染函数
- function mount(vnode, container) {
- // 使用vnode.tag作为创建的dom标签el
- let el = document.createElement(vnode.tag);
-
- // 遍历vnode.props,将属性 事件添加到DOM上(事件即给元素添加监听事件;)
- for (let key in vnode.props) {
- // 判断如果为事件则将其设置到el中
- if ((/^(on)/).test(key)) {
- el.addEventListener(key.substr(2).toLowerCase(), vnode.props[key]);
- }
- }
-
- // 处理 children(字符串和数组)
- if (typeof vnode.children === "string") {
- el.appendChild(document.createTextNode(vnode.children));
- } else if (Array.isArray(vnode.children)) { //是数组进行遍历并递归调用render方法
- vnode.children.forEach(child => {
- render(child, el);
- });
- }
-
- // 将元素添加到挂载节点container下
- container.appendChild(el);
- }
-
-
- // render函数测试
- const container = document.getElementById('app')
- // 仿组件结构(可以通过render方法获取组件的虚拟节点对象数据)
- const MyComponent = {
- render() {
- return {
- tag: 'div',
- props: {},
- children: [
- {
- tag: 'p',
- props: {},
- children: '我是一个p标签'
- },
- {
- tag: 'button',
- props: {
- onClick: () => alert('hi vue')
- },
- children: '按钮'
- }
- ]
- }
- }
- }
-
- const vnode = {
- tag: MyComponent
- }
- render(vnode, container)