創建
index.js
import "./index.less" //{0}
export default {
name: 'testComp',
props: {
title:""
},
data() {
return {
name:'test'
}
},
computed:{},
created() {},
..., //{1}
methods: {
test(){
console.log("testFn")
}
},
render() { //{2}
console.log(this.title);
console.log(this.name);
this.test();
return (
<div>
函數式組件
</div>
)
},
}
{0} :這個是引入的css
{1}:這里省略掉其他的內容
{2}:只里有一個
render
函數,這個函數類似普通組件的template
,但是比template
做的事多頁面效果:
總結:
其實函數式組件和普通組件沒有很大的區別,主要通過
render
函數返回頁面顯示內容,而render
函數是可以通過this
調用到所有內容的
index.less
div{
color: red;
}
app.vue
<test-comp title="測試組件"></test-comp>
基礎開發
還是和以前組件一樣正常開發就是了,只是說
HTML
部分通過函數返回,下面編寫幾種常用的返回方式
簡單函數返回
methods上添加方法simpleReturn
simpleReturn() {
return (<span class='test'>這是一種簡單返回</span>)
}
render函數上調用該方法
render() {
return (
<div>
函數式組件{this.simpleReturn()}
</div>
)
},
index.less上添加樣式test
div{
color: red;
}
.test{
color: blue;
}
展示效果
基本語法: 這里你可以看到我們不再使用
template
上的{{}}
,而是{}
表示js
相關代碼還有這里用的還是class,在react上是className,不要混了哦!
if判斷返回
methods上添加方法ifReturn
ifReturn(bol) {
let content = null;
if(bol){
content = <p class='test'>我是true的返回</p>;
}else{
content = <p class='test'>我是false的返回</p>;
}
return content
}
render函數上調用該方法
render() {
return (
<div>
函數式組件{this.simpleReturn()}
{this.ifReturn(false)}
{this.ifReturn(true)}
</div>
)
},
展示效果
for循環返回
methods上添加方法forReturn
forReturn(arr) {
let content = [];
for (let index = 0; index < arr.length; index++) {
content.push(<li>{arr[index]} : {index}</li>)
}
return content
}
render函數上調用該方法
render() {
return (
<div>
// 因為關注點問題,我省略了前面的代碼!!! 后面貼全部
<ul>
{this.forReturn(["測試","哈哈","嘻嘻","哇哇"])}
</ul>
<ul>
{["測試","哈哈","嘻嘻","哇哇"].map((item,index) => <li>{index}:{item}</li>)}
</ul>
</div>
)
},
展示效果
這里有兩種方式實現循環,其實基本一樣,但是代碼分離可能對后面的維護更方便,注意這里使用的是數組的
map
方法,不知道的可以查查資料
屬性綁定(中階)
如果說這個不能綁定屬性,那再怎么說都不香了,其實我們看到這里的所有
js
部分都是由{}
完成的,所以我們大膽猜測一下,屬性綁定是不是也是這樣呢???
render函數
render() {
return (
<div>
// 因為關注點問題,我省略了前面的代碼!!! 后面貼全部
<input v-model={name}/>
</div>
)
},
效果
咦,
test
沒上去,這個綁定咋不靈了,難道我們猜錯了,不會吧,不會吧,不會真的錯了吧!!!思考:我們在哪寫的代碼???
回答:
render函數
呀!!!注意:對,
render函數
,你以前在函數中使用是直接用的name
屬性的嗎???是不是明白了什么,以前能在
template
上使用不需要this
,但是現在要了!!!
所以最后修改為
render() {
return (
<div>
// 因為關注點問題,我省略了前面的代碼!!! 后面貼全部
<input v-model={this.name}/>
<input value={this.name}/>
</div>
)
},
效果:
值綁定上去了,而且是響應式的
總結一下:這里綁定是要用
{}
,不再是以前的v-bind(:)
,還要注意一定要this
事件綁定(中階)
這給我一種原生的差不多,感覺沒有
vue
的指令啥的,那么是否綁定事件也是和原生的差不多呢???試試看!!!
render函數
render() {
return (
<div>
// 因為關注點問題,我省略了前面的代碼!!! 后面貼全部
<ul onclick={this.inputInfo} >
{["測試","哈哈","嘻嘻","哇哇"].map((item,index) => <li>{index}:{item}</li>)}
</ul>
<input onInput={this.inputInfo} v-model={this.name}/>
</div>
)
},
我在
ul
上綁定了一個onclick
事件,然后在input
上綁定了一個onInput
事件,然后測試一下,發現都成功了
有沒有發現我上面的
true
和false
變成了假的
和真實
,我清一下緩存刷新就好了,我想不會吧,不會吧,這玩意還有緩存???這也太不穩定了吧!!!當我把所有筆記寫完的時候我突然意識到了,咦,這個可能不是緩存原因!!!哈哈哈,所以還是要三思而后行呀!!!嘻嘻嘻
總結
是不是都會了呢!!!其實函數式組件也就這么簡單,但是其實我還有沒有告訴你的,嘻嘻
復雜綁定(中高)
這個復雜可以是你想的那個復雜,也可以是看上去就很復雜的樣子,暫時只了解了兩個,后續有用到在補充
v-bind="$attrs"
這個你是不是很熟悉呢!!!簡單的說就是,你在父組件上寫定義的變量,只要你子組件上不接收,然后你的孫子組件上添加上
v-bind="$attrs"
這段,那么這個就可以繼續傳遞下去,那這個有什么用呢!!!那么在這里怎么用呢???
app.vue
<test-comp type="primary" plain title="測試組件"></test-comp>
render函數
render() {
console.log(this.$attrs)
return (
<div>
// 因為關注點問題,我省略了前面的代碼!!! 后面貼全部
<el-button {...{props:this.$attrs}}>主要按鈕</el-button>
<el-button {...{attrs:this.$attrs}}>主要按鈕</el-button>
</div>
)
},
效果
可以看到這個屬性已經繼承下去了,是不是很棒,但是這個寫法就有點小復雜了
{...{props:this.$attrs}}:最外層
{}
表示綁定
,然后內部使用展開對象...
,然后就是一個對象,屬性props
(其實這就是參數,也可以使用attrs
),然后將$attrs
里保存的是沒有接收的參數(真的是沒有接收的嗎?我試試),這里的title
是接收了的,但是我新加的兩個屬性是沒有的,結果都在這里,就說明真的是這樣的
多屬性一次綁定
咦!這里咋是一個對象呢?不是
a屬性 = b
,而且這里的翻譯一下不就是{...{props:{plain:"",type:"primary"}}},那么我要是想在這里綁定一些其他屬性呢???我是不是可以渾水摸魚一波,和這個this.$attrs
一起混進去呢?
app.vue
<test-comp plain title="測試組件"></test-comp>
render函數
render() {
console.log(this.$attrs)
return (
<div>
// 因為關注點問題,我省略了前面的代碼!!! 后面貼全部
<el-button {...{props:this.$attrs}}>主要按鈕</el-button>
</div>
)
},
效果
可以看到,我們父組件綁定的屬性減少,但是樣式還是一樣沒變,因為我們在子組件給他加上去了,所以你想加多少就加多少,是不是很爽
但是這樣說好像沒什么用,其實這里只是一個參數外放的思路而已,也許對你來說沒意思,或者說不需要我提示
v-on="$listeners"
了解一下
v-on="$listeners"
,這個和v-bind="$attrs"
差不多,只是一個傳遞數據,一個傳遞事件,這樣你就可以在這個父組件的子孫后代....中直接觸發父組件的方法
我們上面的看到
v-bind="$attrs"
變成了{...{attrs: this.$attrs}}
這樣.咦,這里沒有接收的數據是不是都是存在了$attrs
里,而v-on="$listeners"
代表的則是事件傳遞,那么是不是所有的事件都存在了$listeners
了呢???
<el-table {...{ attrs: this.$attrs,on: this.$listeners }} class="table-info-detail">
<el-table-column prop='test' label='測試' ></el-table-column>
</el-table>
等下次我會寫一個完成的函數式組件出來,是一個表格組件,如果你做管理后台,一天到晚的復制粘貼代碼,我覺得你可以抱住試試的心態關注一下我!!!不過我的組件是基於element-ui的,還有技術有限,如果沒有達到你的期望,還請見諒!!!
插槽數據的獲取
看上面兩個,其實我們也能大致猜到,這里的插槽也在這個位置,只是形式有點不同,讓我們來瞧一瞧
<el-table-column
prop="solt"
label="插槽"
{...{
scopedSlots: {
default: ({ row, $index }) => {
},
},
}}></el-table-column>
上面的展示的為
el-table-column
的默認插槽,其他插槽不需要多解釋了吧!!!
咦,那添加插槽呢???
render
render() {
console.log(this.$attrs)
let propsObj = Object.assign({},this.$attrs,{type:"primary"});
return (
<div>
// 因為關注點問題,我省略了前面的代碼!!! 后面貼全部
{this.$scopedSlots.default({
index: 0,
})}
</div>
)
},
app.vue
<test-comp boder @cell-click="cellClick" :data="[{test:'4444545'},{test:'4444545'}]">
<template slot-scope="{index}">
<span style="color:red">插槽{{index}}</span>
</template>
</test-comp>
總結
到此就結束了,上面的知識點知道后,基本上是可以寫一個很不錯的組件出來的, 學習的過程總是這么的開心,哈哈哈,相信明天的自己會更強吧!!!
所有代碼
import "./index.less"
export default {
name: 'testComp',
props: {
title: ""
},
data() {
return {
name: "test"
}
},
computed: {},
created() {
},
methods: {
test() {
console.log("testFn")
},
simpleReturn() {
return (<span class='test'>
這是一種簡單返回
</span>)
},
ifReturn(bol) {
let content = null;
if(bol){
content = <p class='test'>我是true的返回</p>;
}else{
content = <p class='test'>我是false的返回</p>;
}
return content
},
forReturn(arr) {
let content = [];
for (let index = 0; index < arr.length; index++) {
content.push(<li>{arr[index]} : {index}</li>)
}
return content
},
inputInfo(){
console.log(this.name)
}
},
render() {
console.log(this.$attrs)
let propsObj = Object.assign({},this.$attrs,{type:"primary"});
return (
<div>
函數式組件{this.simpleReturn()}
{this.ifReturn(false)}
{this.ifReturn(true)}
<ul>
{this.forReturn(["測試","哈哈","嘻嘻","哇哇"])}
</ul>
<ul onclick={this.inputInfo} >
{["測試","哈哈","嘻嘻","哇哇"].map((item,index) => <li>{index}:{item}</li>)}
</ul>
<input onInput={this.inputInfo} v-model={this.name}/>
<el-button {...{props:propsObj}}>
</el-button>
<el-table {...{attrs: this.$attrs, on: this.$listeners}} className="table-info-detail">
<el-table-column prop='test' label='測試'></el-table-column>
</el-table>
{this.$scopedSlots.default({
index: 0,
})}
</div>
)
},
}
index.less
div{
color: red;
}
.test{
color: blue;
}
app.vue
<template>
<div id="app">
<test-comp boder @cell-click="cellClick" :data="[{test:'4444545'},{test:'4444545'}]">
<template slot-scope="{index}">
<span style="color:red">插槽{{index}}</span>
</template>
</test-comp>
</div>
</template>
<script>
import testComp from './components/testComp'
export default {
name: 'App',
components: {
testComp
},
data() {
return {
}
},
methods: {
cellClick(row, column, cell, event){
console.log(row, column, cell, event)
},
}
}
</script>
<style lang="less">
</style>