前言
思維的混亂是自學的第一障礙,即便是看著官網資料,google一下也是必不可少的,知識點太碎,不整理根本記不住.配合官網教程服用風味更佳!
一個使用render函式會更合適的案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<!-- Vue 推薦在絕大多數情況下使用 template 來建立你的 HTML。
然而在一些場景中,你真的需要 JavaScript 的完全程式設計的能力,
這時你可以用 render 函式,它比 template 更接近編譯器。
下面是不適合template的一個示例 -->
<h1>Hello world!</h1>
<div id="app">
<!-- 生成錨點標題 (anchored headings)元件 -->
<anchored-heading :level="1">Hello world!</anchored-heading>
</div>
<!-- 放在type=”text/x-template”中的內容將不會被瀏覽器解析,
不被執行,不被顯示,它只是默默地舉根隱身草站在那裡。 -->
<!-- <script type="text/x-template" id="anchored-heading-template">
<h1 v-if="level === 1">
<slot></slot>
</h1>
<h2 v-else-if="level === 2">
<slot></slot>
</h2>
<h3 v-else-if="level === 3">
<slot></slot>
</h3>
<h4 v-else-if="level === 4">
<slot></slot>
</h4>
<h5 v-else-if="level === 5">
<slot></slot>
</h5>
<h6 v-else-if="level === 6">
<slot></slot>
</h6>
</script>
<script>
Vue.component('anchored-heading', {
template: '#anchored-heading-template',
props: {
//props的一些校驗
level: {
type: Number,
required: true
}
}
})
let vm = new Vue({
el: '#app'
})
</script> -->
<!-- 使用模板字串,替代上面的寫法,上面的寫法,我不熟悉 -->
<!-- <script>
let vm = new Vue({
el: '#app',
data: {
},
components: {
'anchored-heading': {
props: {
level: {
type: Number,
required: true
}
},
template: `
<h1 v-if="level === 1">
<slot></slot>
</h1>
<h2 v-else-if="level === 2">
<slot></slot>
</h2>
<h3 v-else-if="level === 3">
<slot></slot>
</h3>
<h4 v-else-if="level === 4">
<slot></slot>
</h4>
<h5 v-else-if="level === 5">
<slot></slot>
</h5>
<h6 v-else-if="level === 6">
<slot></slot>
</h6>
`
}
}
})
</script> -->
<script>
//render函式的方式建立元件
Vue.component('anchored-heading', {
render: function (createElement) {
return createElement(
'h' + this.level, // 標籤名稱(例:h1) this.level是props中的level
this.$slots.default // 子元素陣列 (虛擬節點,參照API的vm.$slots的例項可以看出)
)
},
props: {
level: {
type: Number,
required: true
}
},
mounted() {
console.log(this.$slots.default);
console.log(this);
}
})
let vm = new Vue({
el: '#app',
data: {
},
})
</script>
</body>
</html>
複製程式碼
render函式有3個引數:
第一個引數(必須) - {String | Object | Function}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<script>
new Vue({
el: '#app',
// 第一種:String
// render: h => h('div','一個HTML標籤字元')
//第二種:元件選項Object(引數物件可以在函式外部定義好再新增,會簡潔一些)
// render: h => h({
// template: `<div>{{msg}}</div>`,
// data() {
// return {
// msg: '元件選項物件'
// }
// }
// })
// 第三種: Function
render: h => {
// let func = h => {template: `<div>一個返回HTML標籤字元或元件選項物件的函式</div>`};
//第一種箭頭函式簡寫不生效,是{}被錯誤識別的問題,let func = h => 'div'就沒有問題
let func = h => {
return {template: `<div>一個返回HTML標籤字元或元件選項物件的函式</div>`};
}
// let func = function() {
// return {template: `<div>一個返回HTML標籤字元或元件選項物件的函式</div>`};
// };
return h(func());
}
})
</script>
</body>
</html>
複製程式碼
第二個引數(可選) - {Object}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>render</title>
<script src="https://cdn.bootcss.com/vue/2.3.4/vue.js"></script>
</head>
<body>
<div id="app">
<elem></elem>
</div>
<script>
Vue.component('elem', {
render: function(h) {
var self = this;
return h('div', {//一個包含模板相關屬性的資料物件
'class': {
foo: false,
bar: true
},
style: {
color: 'red',
fontSize: '14px'
},
attrs: {
class: 'change',//當沒有class配置項時,此處的class屬性就會生效
qwe: 'qwe',//可以新增自定義屬性
id: 'foo'
},
domProps: {
innerHTML: 'baz'
}
});
}
});
new Vue({
el: '#app'
});
</script>
</body>
</html>
複製程式碼
第三個引數(可選) - {String | Array}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>render</title>
<script src="https://cdn.bootcss.com/vue/2.3.4/vue.js"></script>
</head>
<body>
<div id="app">
<elem></elem>
</div>
<script>
Vue.component('elem', {
render: function(createElement) {
// return createElement('div', '文字');//使用字串生成文字節點
return createElement('div', [//由createElement函式構建而成的陣列
'文字節點',//節點包括文字節點,註釋節點,與元素節點,文字節點可以直接在此處去寫
createElement('h1', '主標'),//createElement函式返回VNode物件,元素節點
createElement('h2', '副標')
]);
}
});
new Vue({
el: '#app'
});
</script>
</body>
</html>
複製程式碼
三個引數都有的一個示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- <my-component class="qwe" :someProp="我是父元件傳來的值"></my-component> -->
<!-- 此處的my-component對虛擬節點而言沒有起到任何作用 -->
</div>
<script>
// Vue.component('MyComponent', {
// template: `<div>{{someProp}}</div>`
// }) //這種掛載元件的方式,子虛擬節點是拿不到的
const MyComponent = {
template: `<div>{{myProp}}</div>`,
props: ['myProp']
}
let vm = new Vue({
el: '#app',
data: {
},
render: function (createElement) {
return createElement(
'div',
{
// 'class': 'qwe',
attrs: {
class: 'qwe',
}
},
[
'先寫一些文字',// 文字節點
createElement('h1','一則頭條'),//元素節點
createElement(
MyComponent,
{
// props: ['myProp']
// props: ['myProp'] //即便是寫了my-component元件標籤,有了自定義屬性,一樣拿不到這個值
// //我猜想是是該元件是虛擬節點的子虛擬節點導致的,已經套了好幾層了
})
]
)
},
mounted() {
console.log(this);
},
})
</script>
</body>
</html>
複製程式碼
兩種元件寫法對比(點選事件案例)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>render</title>
<script src="https://cdn.bootcss.com/vue/2.3.4/vue.js"></script>
</head>
<body>
<div id="app">
<my-element></my-element>
</div>
<script>
//模板化的元件建立方式
Vue.component('MyElement',{
template: `
<button :class="classData" :id="idData" :style="styleData" @click="handelClick">按鈕</button>
`,
data() {
return {
msg: '模板化測試資料',
styleData: {
fontSize: '16px',
color: 'red'
},
classData: {
btn1: true,
btn2: false
},
idData: 'only'
}
},
methods: {
handelClick() {
console.log(this.msg);
}
}
})
//render函式化的元件建立方式
// Vue.component('MyElement',{
// render: function (createdElement) {
// return createdElement('button',{
// 'class': {
// btn1: true,
// btn2: false
// },
// style: {
// fontSize: '16px',
// color: 'red'
// },
// attr: {
// id: 'only'
// },
// on: {
// click: this.handelClick
// }
// //不能直接在on中定義事件函式,此處的this指向window,拿不到data中的資料
// // on: {
// // click: function() {
// // console.log(this);
// // }
// // }
// },'按鈕')
// },
// //箭頭函式的簡寫一定要注意,此處會報錯,我猜還是this指向的問題,如下圖:
// // render: h => h('button',{
// // on: {
// // click: this.handelClick
// // }
// // },'按鈕'),
// data() {
// return {
// msg: '測試資料'
// }
// },
// methods: {
// handelClick() {
// console.log(this.msg);
// }
// }
// })
new Vue({
el: '#app'
})
</script>
</body>
</html>
複製程式碼
this.$slots用法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>render</title>
<script src="https://cdn.bootcss.com/vue/2.3.4/vue.js"></script>
</head>
<body>
<div id="app">
<my-component>
<h1 slot="header">我是頭部,放在對應的具名插槽中</h1>
<p>我會被放在匿名插槽中</p>
<p>我會會被放在匿名插槽中</p>
<p slot="footer">我是尾部</p>
</my-component>
</div>
<script>
Vue.component('MyComponent',{
// 用h去替換createElement,目前在使用上未發現問題
render: function(h) {
let header = this.$slots.header;
let main = this.$slots.default;
let footer = this.$slots.footer;
return h('div',[//返回由VNode(虛擬節點)組成的陣列
h('header',header),
h('main',main),
h('footer',footer)
])
}
})
new Vue({
el: '#app'
});
</script>
</body>
</html>
複製程式碼
VNodes 必須唯一
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>render</title>
<script src="https://cdn.bootcss.com/vue/2.3.4/vue.js"></script>
</head>
<body>
<!-- VNode必須唯一 -->
<div id="app">
<my-component></my-component>
</div>
<script>
// let child = {
// render: function(h) {
// return h('p','我希望自己能多次出現')
// }
// }
// Vue.component('MyComponent',{
// render: function(h) {
// let childNode = h(child);
// return h('div',[
// childNode,childNode,childNode//VNodes必須唯一,這樣寫是無效的,不會生成3個的
// ])
// }
// })
Vue.component('MyComponent', {
render: function(h) {
return h('div',[
// apply() 的第一個引數是物件,第二個引數是陣列,作為引數列表。
// 然後其實第二個引數只要是個類陣列物件就可以了,比如 {length: 5}
// 就可以看作一個類陣列物件,長度是 5,每個元素由於沒賦值,所以都是undefined,比如 v[0] 是 undefined。
// 所以,Array.apply(null, { length: 5}) 相當於
// Array(undefined, undefined, undefined, undefined, undefined)
// 參考連結:https://segmentfault.com/q/1010000006793990
Array.apply(null, {
length: 10
// map() 方法建立一個新陣列,其結果是該陣列中的每個元素都呼叫一個提供的函式後返回的結果。
// 參考連結:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/map
}).map(function () {
return h('p','我希望自己能多次出現')
})
])
}
})
new Vue({
el: '#app'
})
</script>
</body>
</html>
複製程式碼
使用props傳遞資料
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<my-component class="qwe" :show="show"></my-component>
<my-component class="qwe" :show="!show"></my-component>
</div>
<script>
Vue.component('MyComponent',{
render: function (createElement) {
if(this.show) {
return createElement('p','true');
} else {
return createElement('p','false');
}
},
props: {
show: {
type: Boolean,
default: false
}
}
})
let vm = new Vue({
el: '#app',
data: {
show: true
}
})
</script>
</body>
</html>
複製程式碼
v-model指令(資料雙向繫結)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>render</title>
<script src="https://cdn.bootcss.com/vue/2.3.4/vue.js"></script>
</head>
<body>
<div id="app">
<el-input :name="myName" @input="handelChange"></el-input>
<div>{{'我的名字是'+ myName}}</div>
</div>
<script>
Vue.component('ElInput',{
render: function(h) {
let self = this;
return h('input',{
domProps: {
// DOM屬性,還有例如:innerHTML
value: self.name
},
on: {
input: function (event) {
// console.log(event,this);
// console.log(self);//這個指向也是很難受,不懂啊
//此處的this如前所述,指向了window,這應該也是self去儲存外層this的原因
self.$emit('input',event.target.value)
}
}
})
},
props: {
name: String
}
})
let vm = new Vue({
el: '#app',
data: {
myName: 'hc'
},
methods: {
handelChange(value) {
this.myName = value;
}
}
})
</script>
</body>
</html>
複製程式碼