十二、虚拟 DOM 和 render() 函数(2)

news2024/11/15 15:52:54

本章概要

  • 用普通 JavaScript 代替模板功能
    • v-if 和 v-for
    • v-model
    • v-on
    • 事件和按键修饰符
    • 插槽
  • JSX
  • 实例:帖子列表

12.3 用普通 JavaScript 代替模板功能

原先在模板中可以使用的一些功能在 render() 函数中没有再提供,需要自己编写 JavaScript 代码来实现。

12.3.1 v-if 和 v-for

只要普通 JavaScript 能轻松完成的操作,Vue 的 render() 函数就没有提供专有的替代方案。例如,在使用 v-if 和 v-for 的模板中:

<ul v-if="items.length">
    <li v-for="item in items">{{ item.name }}</li>
</ul>
<p v-else>No items found.</p>

在 render() 函数中可以使用 JavaScript 的 if/else 和 map 实现相同的功能。如下:

props:['items'],
render(){
  if(this.items.length){
    return Vue.h('ul',this.items.map((item) => {
      return Vue.h('li',item.name)
    }))
  }else{
    return Vue.h('p','No items found.')
  }
}

12.3.2 v-model

在 render() 函数中没有与 v-model 指令直接对应的实现方案,不过v-model 指令在模板编译期间会被扩展为 modelValue 和 onUpdate:modelValue prop ,按照 v-model 的内在逻辑,自己实现即可,如下:

props:['modelValue'],
render(){
  return Vue.h(SomeComponent,{
  modelValue:this.modelValue,
  'onUpdate:modelValue':value => this.$emit('update:modelValue',value)
  })
}

12.3.3 v-on

必须为事件处理程序提供一个正确的 prop 名称。例如,要处理 click 事件,prop 名称应该是 onClick。代码如下:

render(){
  return Vue.h('div',{
    onClick:$event => console.log('clicked',$event.target)
  })
}

12.3.4 事件和按键修饰符

对于 .passive、.capture 和 .once 这些事件修饰符,可以使用驼峰命名法将他们连接到事件名之后。如下:

render(){
  return Vue.h('input',{
    onClickCapture:this.doThisInCapturingMode,
    onKeyupOnce:this.doThisOnce,
    onMouseoverOnceCapture:this.doThisOnceInCapturingMode
  })
}

对于其它的事件和按键修饰符,则不需要特殊的 API ,因为在处理程序中可以使用事件方法实现相同的功能,如下:
与修饰符等价的事件方法

修饰符处理函数中的等价操作
.stopevent.stopPropagation()
.preventevent.preventDefault()
.selfif(event.target!== event.currentTarget) return
按键:.enter、.13if(event.keyCode!==13) return (对于其他的按键修饰符,可将13改为其对应的按键码)
修饰符:.ctrl、.alt、.shift、.metaif(!event.ctrlKey) return (可将 ctrlKey 分别修改为 altKey、shiftKey、mateKey)

下面是一个使用所有修饰符的例子:

render(){
  return Vue.h('input',{
    onKeyUp:event => {
      // 如果触发事件的元素不是事件绑定的元素,则返回
      if(event.target !== event.currentTarget) return
      // 如果按下的不是 Enter 键(13)或没有同事按下 Shift 键,则返回
      if(!event.shiftKey || event.keyCode !== 13) return
      // 阻止事件传播
      event.stopPropagation()
      // 阻止该元素默认的 keyup 事件处理
      event.preventDefault()
      // ...
    }
  })
}

12.3.5 插槽

通过 this.slots 可以访问插槽的内容,插槽的内容是 VNode 数组。代码如下:

render(){
  // `<div><slot></slot></div>`
  return Vue.h('div',{},this.$slots.default())
}
// 访问作用域插槽
props:['message'],
render(){
  // `<div><slot :text="message"></slot></div>`
  return Vue.h('div',{},this.$slots.default({
    text:this.message
  }))
}

如果要使用 render() 函数将插槽传递给子组件,可以编写下面的代码:

render (){
  // `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>`
  return Vue.h('div',[
    Vue.h(
      Vue.resolveComponent('child'),
      {},
      // 将 slots 作为子对象传递
      // 格式为:{ name:props => VNode | Array<VNode> }
      {
        default:(props) => Vue.h('span',props.text)
      }
    )
  ])
}

12.4 JSX

这时候会发现,即使是简单的模板,在 render() 函数中编写也很复杂,而且模板中的 DOM 结构面目全非,可读性很差。当模板比较复杂,元素之间嵌套的层级较多时,在 render() 函数中一层层嵌套的 h() 函数也令人迷惑。

React 的 render() 函数使用 JSX 语法来简化模板的编写,使模板的编写变得和普通 DOM 模板一样简单。在 Vue 中,可以通过一个 Babel 插件让Vue 支持 JSX 语法,从而简化 render() 函数中的模板创建。

提示:
JSX 的全称是 JavaScript XML ,是一种 JavaScript 的语法扩展,用于描述用户界面。其格式比较像是模板语言,但事实上完全是在 JavaScript 内部实现的。

例如:对于下面 DOM 结构:

<anchored-heading :level="1">
  <span>hello</span> world
</anchored-heading>>

不使用 JSX 语法的 render() 函数实现如下:

Vue.h(Vue.resolveComponent('anchored-heading'),
      {
        level:1
      },
      {
        default:() => [Vue.h('span','hello'),'world']
      }
     )

使用 JSX 语法的 render() 函数实现如下:

import AnchoredHeading from './AnchoredHeading.vue'
const app = createApp({
  render(){
    <AnchoredHeading level={1}>
      <span>hello</span> world
    </AnchoredHeading>
  }
})
app.mount('#demo')

12.5 实例:使用 render() 函数实现帖子列表

首先是单个帖子的组件 PostListItem,如下:

// 子组件
app.component('PostListItem', {
    props: {
        post: {
            type: Object,
            required: true
        }
    },
    render() {
        return Vue.h('li', [
            Vue.h('p', [
                Vue.h('span',
                    // 这是<span>元素的内容
                    '标题:' + this.post.title + ' | 发帖人:' + this.post.author + ' | 发帖时间:' + this.post.date + ' | 点赞数:' + this.post.vote
                ),
                Vue.h('button', {
                    onClick: () => this.$emit('vote')

                }, '赞')
            ]
            )
        ]
        );
    }
});

一定要清楚 h() 函数的 3 个参数的作用,因为后面两个参数都是可选的,所以要主义区分哪部分是第二个参数传参,哪部分是第三个参数传参。
简单的区分方式就是看对象传参还是数组传参,如果是对象传参,就是第二个参数(设置元素的属性信息);如果是数组传参,就是第三个参数(设置子节点信息)。
完整代码如下:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
</head>

<body>
    <div id="app">
        <post-list></post-list>
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({})
        // 父组件
        app.component('PostList', {
            data() {
                return {
                    posts: [
                        { id: 1, title: '华为meate40怎么样', author: '张三', date: '2019-10-21 20:10:15', vote: 0 },
                        { id: 2, title: '华为meate40 pro 怎么样', author: '李四', date: '2019-10-10 09:15:11', vote: 0 },
                        { id: 3, title: '华为p40怎么样', author: '王五', date: '2020-11-11 15:22:03', vote: 0 }
                    ]
                }
            },
            methods: {
                // 自定义事件vote的事件处理器方法
                handleVote(id) {
                    this.posts.map(item => {
                        item.id === id ? { ...item, voite: ++item.vote } : item;
                    })
                }
            },
            render() {
                let postNodes = [];
                // this.posts.map取代v-for指令,循环遍历posts,
                // 构造子组件的虚拟节点
                this.posts.map(post => {
                    let node = Vue.h(Vue.resolveComponent('PostListItem'), {
                        post: post,
                        onVote: () => this.handleVote(post.id)
                    });
                    postNodes.push(node);
                })
                return Vue.h('div', [
                    Vue.h('ul', [
                        postNodes
                    ]
                    )
                ]
                );
            },
        });

        // 子组件
        app.component('PostListItem', {
            props: {
                post: {
                    type: Object,
                    required: true
                }
            },
            render() {
                return Vue.h('li', [
                    Vue.h('p', [
                        Vue.h('span',
                            // 这是<span>元素的内容
                            '标题:' + this.post.title + ' | 发帖人:' + this.post.author + ' | 发帖时间:' + this.post.date + ' | 点赞数:' + this.post.vote
                        ),
                        Vue.h('button', {
                            onClick: () => this.$emit('vote')

                        }, '赞')
                    ]
                    )
                ]
                );
            }
        });

        app.mount('#app')
    </script>
</body>

</html>

渲染结果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/31884.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

docker-Cgroups的资源限制

一、Cgroup的介绍 cgroups&#xff0c;是一个非常强大的linux内核工具&#xff0c;他不仅可以限制被namespace 隔离起来的资源&#xff0c;还可以 为资源设置权重、计算使用量、操控进程启停等等。所以cgroups (Control groups) 实现了对资源的配额和度量。 cpu时间片的概念 …

atoi函数的介绍和模拟实现

今天我来介绍atoi函数和模拟实现atoi函数。 目录atoi和与其功能相似的函数的介绍atoi函数的模拟实现atoi和与其功能相似的函数的介绍 atoi函数是一个将字符串转换为整数值的函数。 由msdn查询可以得知&#xff0c;atoi函数的返回类型是int类型&#xff0c;参数类型是const ch…

用于不同功率的模块式TEC半导体致冷器超高精度温度控制装置

摘要&#xff1a;针对目前TEC半导体制冷器温控装置对高精度、模块化、可编程和远程控制等方面的技术需求&#xff0c;本文提出了一种高性价比的解决方案。解决方案的具体内容是采用模块式结构&#xff0c;以24位AD和16位DA超高精度PID控制器作为基础单元&#xff0c;采用分立模…

不调参,免训练,VisionBank AI OCR新功能升级上线!

应用背景 OCR字符识别&#xff0c;是指对部件或产品上刻印的字符进行确认、辨别、判定的检测识别。此项技术目前已广泛应用于工业自动化生产的产品质量管理环节当中&#xff0c;企业通过为机器视觉检测设备安装OCR系统&#xff0c;快速完成对产品生产日期、保质期、生产批号、…

红色荧光TAMRA alkyne 5-isomer,945928-17-6,5四甲基罗丹明-炔基

TAMRA alkyne,5-isomer反应原理&#xff1a; 红色荧光四甲基罗丹明炔烃可通过铜催化的点击反应与叠氮化合物反应。点击化学的代表反应为铜催化的叠氮-炔基Husigen环加成反应&#xff08;Copper-Catalyzed Azide–Alkyne Cycloaddition&#xff09;。点击化学的概念对化学合成领…

线性二分类——机器学习

目录 一、算法思想 二、算法原理 三、算法分析 四、源程序代码 五、运行结果及分析 六、总结 一、算法思想 &#xff08;1&#xff09;二分类:表示分类任务有两个类别&#xff0c;比如我们想识别图片中是不是狗&#xff0c;也就是说&#xff0c;训练一个分类器&#xff0c;…

如何使用云服务器搭配宝塔面板搭建Z-blog个人博客系统

之前写过使用过WordPress和Typecho搭建个人博客网站的方法&#xff0c;这篇文章将使用Z-blog搭建个人博客系统&#xff0c;Z-blog相当于WordPress而言&#xff0c;更加小巧&#xff0c;但是依然有着强大的功能&#xff0c;以及丰富的主题和插件&#xff0c;因此也值得很多用户选…

数字图像处理均衡化、规定化例题及解题思路

目录 均衡化 规定化 均衡化 前置知识&#xff1a; rk:表示灰度级 nk:表示第k个灰度级出现的个数 sk:表示用变换函数公式计算映射后的灰度级sk 变换函数公式&#xff1a; 例题&#xff1a; 1.列表写出图像直方图均衡化的过程 2.画出均衡化以后的图像 3.画出原始图像直方图…

如何给PDF解密?建议收藏这些方法

我们在传输接收文件的时候&#xff0c;经常都是以PDF格式进行的&#xff0c;因为PDF格式具有很强的稳定性。那小伙伴们平时接收的时候&#xff0c;会不会发现有些PDF文件为了保密性会进行加密&#xff0c;如果我们经常需要使用它&#xff0c;就需要不断地输入密码&#xff0c;这…

Navicat使用教程

文章目录1.连接数据库1.1 启动MySQL1.2 Navicat连接数据库1.3 操作数据库1.4 导入EXcel表内容1.5 新建查询1.连接数据库 1.1 启动MySQL 使用管理员身份打开命令提示符 net start mysql 启动服务 net stop mysql 关闭服务 1.2 Navicat连接数据库 第一步:连接数据库之前一定要…

基于ZigBee设计的物联网LED控制系统

1. 前言 随着LED照明越来越普及以及移动互联网技术的快速发展,人们对家居生活的网络化、智能化、节能化的需求越来越强烈,将家用电器、照明灯具等模块通过无线网络集成到控制平台,实现智能控制和智能管理,目前智能LED照明已成为IOT中重要的一部分。 本文为了绿色智慧照明…

构建企业级DNS系统(十)搭建Docker容器bind

把bind运行在docker中 伴随着应用微服务化&#xff0c;大量应用跑在了容器之中&#xff0c;为了让容器的管理更可靠、可控并为上层应用提供更好的体验&#xff0c;更快的发布&#xff0c;更灵活的调度&#xff0c;容器云应运而生。 当各种上层应用跑在了容器之中&#xff0c;大…

Linux怎么设置中文语言? centos中文乱码的解决办法

怎么设置Linux系统中文语言&#xff1f;是很多小伙伴在开始使用Linux的时候&#xff0c;都会遇到一个问题&#xff0c;就是终端输入命令回显的时候中文显示乱码。出现这个情况一般是由于没有安装中文语言包&#xff0c;或者设置的默认语言有问题导致的。今天我们就以centos为例…

千亿贴息助科研,维视智造院校实验室建设攻略来了(四)!

01千亿政策贴息助力院校设备升级 近期&#xff0c;关于高校教育信息化的利好政策密集出台。9月7日&#xff0c;国务院常务会议提出对高校、职业院校和实训基地等10大领域设备购置和更新改造新增贷款&#xff0c;实施阶段性鼓励政策&#xff0c;中央财政贴息2.5个百分点&#xf…

【跟学C++】C++STL标准模板库——算法详细整理(下)(Study18)

文章目录1、简介2、STL算法分类及常用函数2.2、变序算法&#xff08;二&#xff09;2.2.1 替换算法(2个)2.2.2 排序算法(6个)2.2.3 分区算法(4个)2.2.4 可用于排序容器的算法(3个)3、总结 【说明】 大家好&#xff0c;本专栏主要是跟学C内容&#xff0c;自己学习了这位博主【 …

SAP PS 第八节 PS 常见问题处理-来源于SAP EPPM分享

SAP PS 常见问题处理1 配置类1.1 结果分析的几类方法1.1.1 关于CO表中价值类别和值类型区别1.1.2 关于结果分析取那个计划成本的问题1.1.3 实际成本大于计划成本的报错1.1.4 结果分析一些典型配置&#xff08;闲人提供&#xff09;1.1.5 结果分析1.2 计划成本1.3 结算时&#x…

回炉重造,温故知新__css常规布局方法梳理__开发实战后的经验之谈

目录 1 基础css布局 1.1 position定位 1.2 float定位 2 开发中常用的布局 2.1 flex布局 2.2 antd栅格布局 2.3 grid网格布局 3 flex布局详解 3.1 flex布局是什么 3.2 教程文档小结 3.3 flex布局应用 4 参考资料 &#x1f44b;&#x1f3fb; 写在前面&#xff1a; 在…

【OpenEVSE 】汽车充电桩控制项目解析

【OpenEVSE 】汽车充电桩控制项目解析1. 项目介绍2. 项目硬件3. 软件原理以及流程4. 系统结构&#xff1a;ESP32RAPI APIMQTT 上的 RAPI:5. SAE J1772协议简析&#xff1a;6. 专用充电接插件7 . 源码解析&#xff1a;此项目来源于openEnergyMonitor 的 openEVSE 部分&#xff0…

A. Tokitsukaze and Strange Inequality(前缀和+桶)

Problem - 1677A - Codeforces 时津风有一个长度为n的排列组合p。回顾一下&#xff0c;长度为n的排列组合p是由n个不同的整数组成的序列p1,p2,...,pn&#xff0c;每个整数从1到n&#xff08;1≤pi≤n&#xff09;。 她想知道在这个排列组合中&#xff0c;有多少个不同的指数图…

玩转MySQL:你知道什么是表分区吗

引言 分库分表相信大家都听说过&#xff0c;但(partitioning)表分区这个概念却鲜为人知&#xff0c;MySQL在5.1版本中开始支持了表分区技术&#xff0c;同时在MySQL5.5中进行了优化&#xff0c;自从MySQL支持的绝大部分引擎都开启了表分区功能。 但到底什么是表分区技术呢&…