前端(vue)入門到精通課程,老師線上輔導:聯絡老師
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API偵錯工具:
如何渲染動態元件呢?【相關推薦:】
有一組陣列結構如下:
const arr = [
{ tag: 'van-field' }, // 輸入框
{ tag: 'van-cell' }, // 彈出層
{ tag: 'van-stepper' } // 步進器
]
登入後複製
想通過迴圈arr,拿到tag
渲染對應的元件。
下面我們分析如何寫才是最優。
我們可以寫一個v-for
去迴圈arr陣列,然後通過v-if
去判斷tag,渲染對應的元件型別。
這樣子寫不是不可以,只不過擴充套件性不好,每次加一個標籤,模板就要再加一個v-if。
我相信很多人起初都是這樣寫。
但這不是我們優雅人該寫的程式碼。
我們能不能根據tag
的標籤來渲染出真正的標籤。
關鍵是迴圈內,怎麼根據遍歷的tag去渲染出真正的元件。
<van-cell v-for="(cell, cellKey) in arr" :key="cellKey" >
<!-- 動態渲染 -->
</van-cell>
登入後複製
有請今天的主角JSX上場。
父元件
<van-cell v-for="(cell, cellKey) in arr" :key="cellKey" >
<!-- 用jsx動態渲染 -->
<RendTag :cell="cell" />
</van-cell>
const arr = [
{ tag: 'van-field' }, // 輸入框
{ tag: 'van-cell' }, // 彈出層
{ tag: 'van-stepper' } // 步進器
]
登入後複製
子元件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: '請輸入姓名',
"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渲染成真正的元件
我們用普通的元件,無法像JSX一樣渲染成我們想要的元件。
這裡的v-model
用計算屬性的坑,我推薦看一遍:
其實這兩篇是有一定的掛鉤的,只不過我在這裡拆開了需求。
主要也是方便朋友們閱讀理解。
藉著該需求,我們惡補一下JSX。
JSX 是一種 Javascript 的語法擴充套件,JSX = Javascript + XML
,即在 Javascript 裡面寫 XML,因為 JSX 的這個特性,所以他即具備了 Javascript 的靈活性,同時又兼具 html 的語意化和直觀性。
活度強的部分元件可以用JSX來代替(比如以上需求);
整個工程沒有必要都使用JSX。
我們在元件中,也可以嵌入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>
);
}
};
登入後複製
可以看到,其實和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>
);
}
};
登入後複製
v-html、v-if、v-for、v-model常用指令在JSX中無法使用,需要使用其他方式來實現。
v-html
在JSX中,如果要設定DOM的innerHTML
,需要用到domProps
。
元件使用:
<HelloWorld
msg="<div class='custom-div'>這是自定義的DOM</div>">
</HelloWorld>
登入後複製
元件程式碼:
export default {
name: "HelloWorld",
props: {
msg: String
},
data() {
return {};
},
methods: {},
render() {
return <div domPropsInnerHTML={this.msg}></div>;
}
};
登入後複製
渲染DOM結果:
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>
);
}
};
登入後複製
監聽事件
監聽事件想到用 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中使用。
event.stopPropagation()
來代替event.preventDefault()
來代替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>
);
}
};
登入後複製
父傳子。
範例:
<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>
);
}
};
登入後複製
子傳父。
範例:
<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吧,用模板Template足以了。
但經過這個需求,我想JSX在處理動態渲染元件還是蠻佔有優勢的?。
日後面試官問我JSX在Vue的有什麼應用場景,我想我可以把這個需求說一說。
(學習視訊分享:、)
以上就是聊聊Vue怎麼通過JSX動態渲染元件的詳細內容,更多請關注TW511.COM其它相關文章!