Vue.js设计与实现阅读-3

这篇具有很好参考价值的文章主要介绍了Vue.js设计与实现阅读-3。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言
前面一章我们了解了,开发体验是衡量一个框架的重要指标之一。提供友好的警告信息至关重要,但是越详细的警告信息,意味着框架体积越大。为了解决这一问题,可以利用 Tree-Shaking 机制,配合构建工具预定义常量,例如 __DEV __ ,从而实现只在开发环境中打印警告信息,生产环境中清楚这些代码,达到代码体积的可控性。
Tree-Shaking 是一种清除 dead code 的机制。可以利用/* #PURE */ 来辅助构建工具进行 Tree-Shaking。
框架的错误处理做的好坏决定了用户程序的健壮性,因此需要为用户提供统一的错误处理接口,这样用户可以通过注册自定义的错误处理函数来处理异常。

1、声明式描述UI

Vue.js 模板描述

<h1 @click="handleClick">
	<span></span>
</h1>

js 对象描述上面的UI

const title = {
	tag: 'h1',
	props: {
		onClick: handleClick
	},
	children: [
		{
			tag: 'span'
		}
	]
}

如果我们想表示一个标题,根据标题级别的不同,分别采用h1~ h6 这几个标签,如果用js实现

let level = 1;
const title = {
	tag: `h${level}`
}

如果 level 的值变化,相应的标签名称也会变化。但是如果用 模板来描述,就需要一个个列举出来。

<h1 v-if="level === 1"></h1>
<h2 v-else-if="level === 2"></h2>
...
<h6 v-else-if="level === 6"></h6>

远远没有js对象灵活。使用js对象来描述 UI 的方式,其实就是虚拟DOM。Vue3中除了支持使用模板描述 UI外,还支持虚拟DOM描述 UI。例如我们手写的渲染函数就是使用虚拟 DOM 描述UI。

import {h} from 'vue';
export default {
	render() {
		return h('h1', {
			onClick: handleClick
		})
	}
}

2、渲染器

虚拟 DOM 就是用 JS 对象来描述真实的DOM结构。如何将虚拟DOM变成真实的DOM并且渲染到浏览器页面中---渲染器

渲染器的作用,把虚拟DOM渲染为真实DOM

虚拟DOM如下:

const vnode = {
	tag: 'div',
	props: {
		onClick: () => alert('hello')
	},
	children: 'click me'
}

编写一个 渲染器,将上面的虚拟 DOM 渲染成真实DOM

function renderer (vnode, container) {
	// 创建 dom 元素
	const el = document.createElement(vnode.tag);
	// 添加属性、事件到 dom 元素
	for (const key in vnode.props) {
		if (/^on/.test(key)) {
			// on 开头,事件,给元素绑定事件
			el.addEventListener(key.substr(2).toLowerCase(), vnode.props[key])
		}
	}
	// children 处理
	if (typeof vnode.children === 'string') {
		// string -- 文本
		el.appendChild(document.createTextNode(vnode.children));
	} else if (Array.isArray(vnode.children)) {
		// 数组,递归调用,渲染子节点
		vnode.children.forEach(child => renderer(child, el));
	}
	container.appendChild(el)
}

运行结果:
Vue.js设计与实现阅读-3,vue.js,前端,Vue设计与实现
上述分析器实现思路

  • 创建DOM元素,vnode.tag 为标签名
  • 给元素添加属性和事件。遍历 props 对象,如果 key 是 on 开头,说明是事件,截取字符 on 使用 toLowerCase将事件名称小写,再调用 addEventListener 绑定事件
  • 处理元素的 children。如果是字符串,创建文本节点,如果是数组,递归调用 renderer 函数渲染。

发现渲染器实现起来也很简单,主要是使用一些熟悉的 DOM 操作 API 来完成渲染工作。上面只是创建节点,渲染器的精髓在更新节点的阶段,需要精确找啊到 vnode对象的变更点,并且只更新变更的内容。

3、组件

上面了解了渲染器会将虚拟 DOM 渲染成真实的 DOM 元素。那组件呢,组件和虚拟 DOM 之前有什么关系。

**组件是一组 DOM 元素的封装,这组 DOM 元素就是组件要渲染的内容。**定义一个函数来代表组件,函数的返回值代表组件要渲染的内容。

const MyComponent = function () {
    return {
        tag: 'div',
        props: {
            onClick: () => alert('click')
        },
        children: 'click me'
    }
}

可以看到组件的 返回值也是虚拟 DOM,代表了组件要渲染的内容,那么我们就可以使用下面的方式来描述组件。其中 tag 可以用来描述组件。

const vnode = {
	tag: MyComponent
}

修改之前的渲染函数

	// 渲染函数
    renderer(vnode, container) {
        if (typeof vnode.tag === 'string') {
            // string -- 普通标签元素
            this.mountElement(vnode, container);
        } else if (typeof vnode.tag === 'function') {
            // string -- 组件
            this.mountComponent(vnode, container);
        }
    },
    
    // 渲染标签元素
    mountElement(vnode, container) {
        // 创建 dom 元素
        const el = document.createElement(vnode.tag);
        // 添加属性、事件到 dom 元素
        for (const key in vnode.props) {
            if (/^on/.test(key)) {
                // on 开头,事件,给元素绑定事件
                el.addEventListener(key.substr(2).toLowerCase(), vnode.props[key])
            }
        }
        // children 处理
        if (typeof vnode.children === 'string') {
            // string -- 文本
            el.appendChild(document.createTextNode(vnode.children));
        } else if (Array.isArray(vnode.children)) {
            // 数组,递归调用,渲染子节点
            vnode.children.forEach(child => this.renderer(child, el));
        }
        container.appendChild(el)
    },
    
     // 渲染组件
    mountComponent(vnode, container) {
        // 调用组件函数,获取要渲染的内容
        const subTree = vnode.tag();
        this.renderer(subTree, container)
    },

4、模板的工作原理

上面我们了解了虚拟 DOM 是如何渲染成真实 DOM的,那么模板是如何工作的呢?其实是依赖于编译器。

编译器的作用是将模板编译成渲染函数。
模板如下

<div @click="handleClick">click me</div>

对编译器来说,模板相当于一个字符串,它会分析字符串并生成一个功能与之相同的渲染函数:

render() {
	return h('div', {onClick: handleClick}, 'click me')
}

在 Vue中一个.vue文件就是一个组件

<template>
    <div @click="handleClick">
        click me
    </div>
</template>

<script>
export default {
    data() {
        return {
        }
    },
    methods: {
        handleClick() {
            // do nothing
        }
    }
}
</script>

其中 < template > 标签里的内容为模板内容,编译器会把模板内容编译成渲染函数并且添加到 script 标签上,最终在浏览器里面运行的代码就是

export default {
    data() {
        return {
        }
    },
    methods: {
        handleClick() {
            // do nothing
        }
    },
    render() {
		return h('div', {onClick: handleClick}, 'click me')
	}
}

对一个组件来说,他要渲染的内容最终都是通过渲染函数产生的,渲染器再将渲染函数返回的虚拟 DOM 渲染为真实 DOM,这就是模板的工作原理,也是 Vue.js 渲染页面的过程。

5、Vue.js 是各个模块组成的有机整体

组件的实现依赖于渲染器,模板的编译依赖于编译器。编译后生成的代码是根据渲染器和虚拟 DOM的设计决定的。 因此Vue的各个模块之间是相互关联,相互制约的。
模板

<div id="foo" :class="cls"></div>

渲染函数

render() {
	return {
		tag: 'div',
		props: {
			id: 'foo',
			class: 'cls'
		}
	}
}

cls 是一个动态属性,那编译器如何知道 cls 发生了变化呢。从上面的模板 我们可以看出 id 是不会发生变化的, :class 可能会发生变化。编译器能识别出哪些是静态属性,哪些是动态属性,因此可以在生成代码的时候,标志出哪些是动态的属性。

render() {
	return {
		tag: 'div',
		props: {
			id: 'foo',
			class: 'cls'
		},
		patchFlags: 1  // 1 代表 class是动态的
	}
}

在虚拟 DOM 中多了一个 patchFlags 属性标志 class 的类型是动态还是静态,这样渲染器可以根据这个标志,知道有什么属性会发生变化。文章来源地址https://www.toymoban.com/news/detail-786968.html

到了这里,关于Vue.js设计与实现阅读-3的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 毕业设计So Easy:SpringBoot+Vue图书阅读和管理系统(前端+后端+小程序端)

    目录 1、项目概述 2、开发环境 3、前后端配置部署 4、小程序端配置部署 5、项目效果演示 5.1、后端管理平台 5.2、前端阅读平台 5.3、小程序社区平台 很多计算机专业大学生经常和我交流:毕业设计没思路、不会做、论文不会写、太难了...... 针对这些问题,决定分享一些软、

    2024年02月11日
    浏览(32)
  • 基于vue的小说阅读网/基于springboot的小说网站/阅读网站的设计与实现

    随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,各行各业相继进入信息管理时代, 小说阅读网 就是信息时代变革中的产物之一。 任何系统都

    2024年02月11日
    浏览(30)
  • vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法

    由于vue为单页面项目,通过控制组件局部渲染,main.js是整个项目唯一的入口,整个项目都在一个index.html外壳中。 若项目过大,会造成单页面负载过重;同时,多页面利于模块独立部署。 如果项目中不同的页面需要不同的main.js和App.vue这样就需要配置多个入口了。 要单独将页

    2024年01月22日
    浏览(79)
  • 前端js react vue怎么实现在线预览doc文档

    先说结论: 目前在纯前端层面没有很好的方案,基本都需要服务端的介入。 优点 :简单易用,无需配置 缺点 :文档需要支持外网访问,且文档会是公开可见的,所以对于一些内部敏感的文档来说,这个显然是不可行的。 需要后端介入配合 onlyoffice地址 这个也要先在服务器

    2024年02月15日
    浏览(62)
  • Vue.js设计与实现

    1.1 命令式和声明式 从范式上看,视图层框架分为命令式和声明式。 命令式: 一大特点是: 关注过程 声明式: 一大特点是: 关注结果 1.2 性能与可维护性 声明式代码的性能不优于命令式代码的性能 框架本身就是封装了命令式代码才实现了面向用户的声明式 声明式 代码的

    2024年02月08日
    浏览(22)
  • 基于Java+Vue+uniapp微信小程序小说阅读系统设计和实现

    博主介绍 : ✌ 全网粉丝30W+,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行交流合作 ✌ 主要内容: SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、P

    2024年01月19日
    浏览(47)
  • vue+face-api.js实现前端人脸识别功能

    近期做了一个前端vue实现人脸识别的功能,主要功能逻辑包含:人脸识别,人脸验证,唤起摄像头视频流之后从三个事件(用户点头、摇头、眨眼睛)中随机选中两个事件,待两个事件通过判断后人脸静止不动3秒钟后截取视频流生成图片,上传到阿里或者腾讯oss,通过oss返回

    2024年02月05日
    浏览(30)
  • 《Vue.js 设计与实现》—— 02 框架设计核心要素

    框架设计并非仅仅实现功能那么简单,里面有很多学问。例如: 框架应该给用户提供哪些构建产物?产物的模块格式如何? 当用户没有以预期的方式使用框架时,是否应该打印合适的警告信息从而提供更好的开发体验,让用户快速定位问题? 开发版本和生产版本的构建有何

    2024年02月03日
    浏览(36)
  • Vue前端 更具router.js 中的meta的roles实现路由卫士,实现权限判断。

    参考了之篇文章 1、我在登陆时获取到登录用户的角色名roles,并存入sessionStorage中,具体是在login页面实现,还是在menu页面实现都可以。在menu页面实现,可以显得登陆快一些。 2、编写router.js,注意,一个用户可能有多个角色。 这里有个bug 我们的roles存在sessionStorage中,关闭

    2024年02月13日
    浏览(36)
  • 基于Java+Vue+uniapp微信小程序微信阅读网站平台设计和实现

    博主介绍 : ✌ 全网粉丝30W+,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ 🍅 文末获取源码联系 🍅 👇🏻 精彩专栏 推荐订阅 👇🏻 不然下次找不到哟 2022-2024年

    2024年02月06日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包