搜尋
首頁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渲染對應的組件。

聊聊Vue怎麼透過JSX動態渲染元件

下面我們分析如何寫才是最優。

二、進行分析

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上場。

聊聊Vue怎麼透過JSX動態渲染元件

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渲染成真正的元件

聊聊Vue怎麼透過JSX動態渲染元件

#我們用普通的元件,無法像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>
    );
  }
};

聊聊Vue怎麼透過JSX動態渲染元件

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結果:

聊聊Vue怎麼透過JSX動態渲染元件

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

直接使用:<input v-model="{this." value>

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。

聊聊Vue怎麼透過JSX動態渲染元件

后记

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

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

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

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

以上是聊聊Vue怎麼透過JSX動態渲染元件的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:掘金社区。如有侵權,請聯絡admin@php.cn刪除
VUE.JS與React:JavaScript框架的比較分析VUE.JS與React:JavaScript框架的比較分析Apr 30, 2025 am 12:10 AM

Vue.js和React各有優缺點,選擇時需綜合考慮團隊技能、項目規模和性能需求。 1)Vue.js適合快速開發和小型項目,學習曲線低,但深層嵌套對象可能導致性能問題。 2)React適用於大型和復雜應用,生態系統豐富,但頻繁更新可能導致性能瓶頸。

vue.js vs.反應:用例和應用程序vue.js vs.反應:用例和應用程序Apr 29, 2025 am 12:36 AM

Vue.js適合小型到中型項目,React適合大型項目和復雜應用場景。 1)Vue.js易於上手,適用於快速原型開發和小型應用。 2)React在處理複雜狀態管理和性能優化方面更有優勢,適合大型項目。

VUE.JS與React:比較性能和效率VUE.JS與React:比較性能和效率Apr 28, 2025 am 12:12 AM

Vue.js和React各有優勢:Vue.js適用於小型應用和快速開發,React適合大型應用和復雜狀態管理。 1.Vue.js通過響應式系統實現自動更新,適用於小型應用。 2.React使用虛擬DOM和diff算法,適合大型和復雜應用。選擇框架時需考慮項目需求和團隊技術棧。

vue.js vs.反應:社區,生態系統和支持vue.js vs.反應:社區,生態系統和支持Apr 27, 2025 am 12:24 AM

Vue.js和React各有優勢,選擇應基於項目需求和團隊技術棧。 1.Vue.js社區友好,提供豐富學習資源,生態系統包括VueRouter等官方工具,支持由官方團隊和社區提供。 2.React社區偏向企業應用,生態系統強大,支持由Facebook及其社區提供,更新頻繁。

React和Netflix:探索關係React和Netflix:探索關係Apr 26, 2025 am 12:11 AM

Netflix使用React來提升用戶體驗。 1)React的組件化特性幫助Netflix將復雜UI拆分成可管理模塊。 2)虛擬DOM優化了UI更新,提高了性能。 3)結合Redux和GraphQL,Netflix高效管理應用狀態和數據流動。

vue.js vs.後端框架:澄清區別vue.js vs.後端框架:澄清區別Apr 25, 2025 am 12:05 AM

Vue.js是前端框架,後端框架用於處理服務器端邏輯。 1)Vue.js專注於構建用戶界面,通過組件化和響應式數據綁定簡化開發。 2)後端框架如Express、Django處理HTTP請求、數據庫操作和業務邏輯,運行在服務器上。

vue.js和前端堆棧:了解連接vue.js和前端堆棧:了解連接Apr 24, 2025 am 12:19 AM

Vue.js與前端技術棧緊密集成,提升開發效率和用戶體驗。 1)構建工具:與Webpack、Rollup集成,實現模塊化開發。 2)狀態管理:與Vuex集成,管理複雜應用狀態。 3)路由:與VueRouter集成,實現單頁面應用路由。 4)CSS預處理器:支持Sass、Less,提升樣式開發效率。

Netflix:探索React(或其他框架)的使用Netflix:探索React(或其他框架)的使用Apr 23, 2025 am 12:02 AM

Netflix選擇React來構建其用戶界面,因為React的組件化設計和虛擬DOM機制能夠高效處理複雜界面和頻繁更新。 1)組件化設計讓Netflix將界面分解成可管理的小組件,提高了開發效率和代碼可維護性。 2)虛擬DOM機制通過最小化DOM操作,確保了Netflix用戶界面的流暢性和高性能。

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脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。