搜索
首页web前端Vue.js聊聊Vue怎么通过JSX动态渲染组件
聊聊Vue怎么通过JSX动态渲染组件Dec 05, 2022 pm 06:52 PM
vue组件vue3jsx

Vue怎么通过JSX动态渲染组件?下面本篇文章给大家介绍一下Vue高效通过JSX动态渲染组件的方法,希望对大家有所帮助!

聊聊Vue怎么通过JSX动态渲染组件

一、明确需求

如何渲染动态组件呢?【相关推荐:vuejs视频教程

有一组数组结构如下:

const arr = [ 
  { tag: 'van-field' },  // 输入框
  { tag: 'van-cell' },   // 弹出层
  { tag: 'van-stepper' } // 步进器
]

想通过循环arr,拿到tag渲染对应的组件。

2.png

下面我们分析如何写才是最优。

二、进行分析

2.1 v-if走天下

我们可以写一个v-for去循环arr数组,然后通过v-if去判断tag,渲染对应的组件类型。

这样子写不是不可以,只不过扩展性不好,每次加一个标签,模板就要再加一个v-if。

我相信很多人起初都是这样写。

但这不是我们优雅人该写的代码。

2.2 动态渲染组件标签

我们能不能根据tag的标签来渲染出真正的标签。

关键是循环内,怎么根据遍历的tag去渲染出真正的组件。

<van-cell  v-for="(cell, cellKey) in arr" :key="cellKey" >
      <!-- 动态渲染  -->
</van-cell>

有请今天的主角JSX上场。

6.jpeg

2.3 JSX动态渲染组件

父组件


  
  


const arr = [ 
  { tag: &#39;van-field&#39; },  // 输入框
  { tag: &#39;van-cell&#39; },   // 弹出层
  { tag: &#39;van-stepper&#39; } // 步进器
]

子组件RendTag.vue

<script>
const AssemblyRend = {
  name: "assembly-rend",
  props: ["cell"],
  data() {
    return {
      input: "",
    };
  },
  methods: {
    onClick() {
      this.$emit("changeTag", this.input);
    },
  },
  computed:{
    itemVal:{
      get(){
        return this.cell.value
      },
      set(v){
        this.cell.value = v
      }
    }
  },
  render() {
    const { cell } = this; // 解构
    const assembly = cell.tag;  // 这里就是我们动态渲染组件的核心 

    return (
        <assembly
          v-model={this.itemVal}
          placeholder={cell.placeholder}
          min={cell.min}
          onClick={this.onClick}
        >
        </assembly>
      );
  },
};

export default {
  name: "RendTag",
  props: {
    cell: {
        type: Object,
        default:()=>{
            return {
                {
                    "title": "能否输入",
                    placeholder: &#39;请输入姓名&#39;,
                    "value": "name",
                    "tag": "van-switch",
                }
            }
        }
    },
  },
  methods: {
    changeTag(val) {},
  },
  render() {
    const { cell } = this; // 解构
    return (
      <div class="rendTag-content">
        <AssemblyRend
          cell={cell}
          onChangeTag={this.changeTag}
        ></AssemblyRend>
      </div>
    );
  },
};
</script>

我们利用JSX的render可以写JavaScript返回组件,来实现我们动态渲染标签。

render相当于我们vue中的模板。

于是渲染出的效果如下:根据tag渲染成真正的组件

2.png

我们用普通的组件,无法像JSX一样渲染成我们想要的组件。

这里的v-model用计算属性的坑,我推荐看一遍:实战v-model如何绑定多循环表达式(内含原理)

其实这两篇是有一定的挂钩的,只不过我在这里拆开了需求。

主要也是方便朋友们阅读理解。

三、vue中如何使用JSX

借着该需求,我们恶补一下JSX。

3.1 是什么?

JSX 是一种 Javascript 的语法扩展,JSX = Javascript + XML,即在 Javascript 里面写 XML,因为 JSX 的这个特性,所以他即具备了 Javascript 的灵活性,同时又兼具 html 的语义化和直观性。

活度强的部分组件可以用JSX来代替(比如以上需求);
整个工程没有必要都使用JSX。

3.2 基本用法

3.2.1 函数式组件

我们在组件中,也可以嵌入ButtonCounter组件。

const ButtonCounter = {
  name: "button-counter",
  props: ["count"],
  methods: {
    onClick() {
      this.$emit("changeNum", this.count + 1);
    }
  },
  render() {
    return <button onClick={this.onClick}>数量:{this.count}</button>;
  }
};

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {
      count: 0
    };
  },
  methods: {
    // 改变button按钮数量
    changeNum(val) {
      this.count = val;
    }
  },
  render() {
    const { count } = this; // 解构
    return (
      <div class="hello-world-content">
        <ButtonCounter style={{ marginTop: "20px" }} count={count} onChangeNum={this.changeNum}></ButtonCounter>
      </div>
    );
  }
};

3.2.2 普通属性、行内样式、动态class与style

可以看到,其实和vue的模板写法基本一致,只不过要注意的是花括号;

在vue的模板是要写两对花括号,而在JSX只需要写一对

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {
      count: 0,
      text: "Hello World!",
      msgClass: "msg-class",
      isGreen: true
    };
  },
  render() {
    const { count, text } = this; // 解构
    return (
      <div class="hello-world-content">
        <p class={this.msg ? this.msgClass : ""}>动态绑定class</p>
        <p style={this.isGreen ? "color: green" : ""}>动态绑定style</p>
      </div>
    );
  }
};

3.jpg

3.2.3 常用指令

v-html、v-if、v-for、v-model常用指令在JSX中无法使用,需要使用其他方式来实现。

v-html

在JSX中,如果要设置DOM的innerHTML,需要用到domProps

组件使用:

<HelloWorld 
   msg="<div class=&#39;custom-div&#39;>这是自定义的DOM</div>"> 
</HelloWorld>

组件代码:

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {};
  },
  methods: {},
  render() {
    return <div domPropsInnerHTML={this.msg}></div>;
  }
};

渲染DOM结果:

4.jpg

v-for

使用map来实现:

render() {
  const list = [1,2,3]
  return( 
    <div>
      { list.map(item => <button>按钮{item}</button>) }
    </div>
  )
}

v-if

简单示例:用三元

render() {
    const bool = false;
    return <div>{bool ? <button>按钮1</button> : <button>按钮2</button>}</div>;
}

复杂示例:直接用JS

render() {
  let num = 3
  if(num === 1){ return( <button>按钮1</button> ) }
  if(num === 2){ return( <button>按钮2</button> ) }
  if(num === 3){ return( <button>按钮3</button> ) }
}

v-model

直接使用:0d06ce051be0af97339836c08344cd6d

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {
      value: "abc"
    };
  },
  watch: {
    value(val) {
      console.log("this.model内容:" + val);
    }
  },
  methods: {},
  render() {
    return (
      <div>
        <input v-model={this.value} placeholder="普通文本" />
      </div>
    );
  }
};

3.2.4 监听事件、事件修饰符

监听事件

监听事件想到用 onChange, onClick等。

需要注意的是,传参数不能使用 onClick={this.handleClick(params)},这样子会每次 render的时候都会自动执行一次方法。

应该使用bind,或者箭头函数来传参。

组件示例代码:

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {};
  },
  methods: {
    handleClick(val) {
      alert(val);
    }
  },
  render() {
    return (
      <div>
        <button type="button" onClick={this.handleClick.bind(this, 11)}>
          方式一
        </button>
        <button type="button" onClick={() => this.handleClick(22)}>
          方式二
        </button>
      </div>
    );
  }
};

用监听事件来实现v-model:

methods: {
    input(e) {
      this.value = e.target.value;
    }
  },
  render() {
    return (
      <div>
        <input type="text" value={this.value} onInput={this.input} />
      </div>
    );
  }

也可以调整为:

<input 
  type="text" 
  value={this.value} 
  onInput={(e) => (this.vaue = e.target.value)} 
/>

还可以使用对象的方式去监听事件:解构事件

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {
      value: ""
    };
  },
  watch: {
    value(val) {
      console.log("this.model的内容:" + val);
    }
  },
  methods: {
    handleInput(e) {
      this.value = e.target.value;
    },
    handleFocus(e) {
      console.log(e.target);
    }
  },
  render() {
    return (
      <div>
        <input type="text" value={this.value} {...{ on: { input: this.handleInput, focus: this.handleFocus } }} />
      </div>
    );
  }
};

nativeOn仅对于组件,用于监听原生事件,也可以使用对象的方式去监听事件:

{...{nativeOn:{click: this.handleClick}}}

事件修饰符

和指令一样,除了个别的之外,大部分的事件修饰符都无法在JSX中使用。

  • .stop : 阻止事件冒泡,在JSX中使用event.stopPropagation()来代替
  • .prevent:阻止默认行为,在JSX中使用event.preventDefault() 来代替
  • .self:只当事件是从侦听器绑定的元素本身触发时才触发回调,使用下面的条件判断进行代替
if (event.target !== event.currentTarget){
  return
}

.enter与keyCode: 在特定键触发时才触发回调

if(event.keyCode === 13) {
  // 执行逻辑
}

除了上面这些修饰符之外,尤大大对于.once,.capture,.passive,.capture.once做了优化,简化代码:

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  methods: {
    handleClick(e) {
      console.log("click事件:" + e.target);
    },
    handleInput(e) {
      console.log("input事件:" + e.target);
    },
    handleMouseDown(e) {
      console.log("mousedown事件:" + e.target);
    },
    handleMouseUp(e) {
      console.log("mouseup事件" + e.target);
    }
  },
  render() {
    return (
      <div
        {...{
          on: {
            // 相当于 :click.capture
            "!click": this.handleClick,
            // 相当于 :input.once
            "~input": this.handleInput,
            // 相当于 :mousedown.passive
            "&mousedown": this.handleMouseDown,
            // 相当于 :mouseup.capture.once
            "~!mouseup": this.handleMouseUp
          }
        }}
      >
        点击模块
      </div>
    );
  }
};

3.3 插槽

3.3.1 普通插槽与具名插槽

父传子。

示例:

<HelloWorld>
    <template slot="default">默认内容</template>
    <template slot="footer">
      <el-button type="primary">确定</el-button>
      <el-button>取消</el-button>
    </template>
</HelloWorld>

HelloWorld组件代码:this.$slots

export default {
  name: "HelloWorld",
  render() {
    return (
      <div>
        <div class="default">{this.$slots.default}</div>
        <div class="footer">{this.$slots.footer}</div>
      </div>
    );
  }
};

3.3.2 作用域插槽

子传父。

示例:

<HelloWorld>
    <template v-slot:content="{ name, age }">
      <div>姓名:{{ name }}</div>
      <div>年龄:{{ age }}</div>
    </template>
</HelloWorld>

HelloWorld组件代码:this.$scopedSlots

export default {
  name: "HelloWorld",
  render() {
    return (
      <div>
        <div class="content">{this.$scopedSlots.content({ name: "张三", age: 20 })}</div>
      </div>
    );
  }
};

子组件通过{this.$scopedSlots.content({ name: "张三", age: 20 })}指定插槽的名称为content,并将含有name,age属性的对象数据传递给父组件,父组件就可以在插槽内容中使用子组件传递来的数据。

看到v-html用innerHTML;v-for用map;.stop用event.stopPropagation()
你有什么感想?
这不就是我们JavaScript方法的操作吗。
所以JSX就是Javascript + XML。

5.jpg

后记

我以前一直觉得Vue中没必要用JSX吧,用模板Template足以了。

但经过这个需求,我想JSX在处理动态渲染组件还是蛮占有优势的?。

日后面试官问我JSX在Vue的有什么应用场景,我想我可以把这个需求说一说。

(学习视频分享:web前端开发编程基础视频

以上是聊聊Vue怎么通过JSX动态渲染组件的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:掘金社区。如有侵权,请联系admin@php.cn删除
VUE3开发基础:使用extends继承组件VUE3开发基础:使用extends继承组件Jun 16, 2023 am 08:58 AM

Vue是目前最流行的前端框架之一,而VUE3则是Vue框架的最新版本,相较于VUE2,VUE3具备了更高的性能和更出色的开发体验,成为了众多开发者的首选。在VUE3中,使用extends继承组件是一个非常实用的开发方式,本文将为大家介绍如何使用extends继承组件。extends是什么?在Vue中,extends是一个非常实用的属性,它可以用于子组件继承父

如何使用 Vue 实现日历组件?如何使用 Vue 实现日历组件?Jun 25, 2023 pm 01:28 PM

Vue是一款非常流行的前端框架,它提供了很多工具和功能,如组件化、数据绑定、事件处理等,能够帮助开发者构建出高效、灵活和易维护的Web应用程序。在这篇文章中,我来介绍如何使用Vue实现一个日历组件。1、需求分析首先,我们需要分析一下这个日历组件的需求。一个基本的日历应该具备以下功能:展示当前月份的日历页面;支持切换到前一月或下一月;支持点击某一天,

聊聊Vue怎么通过JSX动态渲染组件聊聊Vue怎么通过JSX动态渲染组件Dec 05, 2022 pm 06:52 PM

Vue怎么通过JSX动态渲染组件?下面本篇文章给大家介绍一下Vue高效通过JSX动态渲染组件的方法,希望对大家有所帮助!

VSCode插件分享:一个实时预览Vue/React组件的插件VSCode插件分享:一个实时预览Vue/React组件的插件Mar 17, 2022 pm 08:07 PM

在VSCode中开发Vue/React组件时,怎么实时预览组件?本篇文章就给大家分享一个VSCode 中实时预览Vue/React组件的插件,希望对大家有所帮助!

VUE3开发入门教程:使用组件实现分页VUE3开发入门教程:使用组件实现分页Jun 16, 2023 am 08:48 AM

VUE3开发入门教程:使用组件实现分页分页是一个常见的需求,因为在实际开发中,我们往往需要将大量的数据分成若干页以展示给用户。在VUE3开发中,可以通过使用组件实现分页功能,本文将介绍如何使用组件实现简单的分页功能。1.创建组件首先,我们需要创建一个分页组件,使用“vuecreate”命令创建VUE项目,并在src/components目录下创建Pagin

如何使用 Vue 实现仿照片墙组件?如何使用 Vue 实现仿照片墙组件?Jun 25, 2023 am 08:19 AM

在现代Web开发中,组件化是一个极受欢迎的开发模式。而Vue.js则是一个非常适合组件化的前端框架。在这篇文章中,我们将介绍如何使用Vue.js创建一个仿照片墙组件。在开始之前,我们需要明确一些准备工作。首先,我们需要安装Vue.js。安装的方法非常简单,只需在终端中输入以下命令:npminstallvue安装完成后,我们可以创建一个名为

常用 Vue UI 组件的使用技巧常用 Vue UI 组件的使用技巧Jun 25, 2023 am 08:31 AM

在现代Web开发中,UI组件是不可或缺的一部分。Vue.js框架中有许多优秀的UI组件库,如Element-UI、Vuetify、AntDesignVue等。这些组件库提供了许多易于使用的组件,可以帮助我们更加高效地创建Web应用程序。本文将介绍一些常用的VueUI组件,以及使用这些组件的技巧和实用技能。一、El-TableEl-Table是Eleme

VUE3初学者入门:使用Vue.js组件组合实现可复用组合VUE3初学者入门:使用Vue.js组件组合实现可复用组合Jun 15, 2023 pm 08:53 PM

Vue.js是一款流行的前端JavaScript框架,它提供了一种简单易用的方式来构建动态网页应用程序。Vue.js的主要特点是其模块化的设计和可插拔的组件系统。这使得开发者可以轻松地创建可复用的组件,从而提高了应用程序的重用性和可维护性。在本文中,我们将重点介绍VUE3初学者如何使用Vue.js组件组合实现可复用组合。Vue.js组件是一个完整的封装元素,

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前By尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
4 周前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境