2.1 指定被挂载元素
el选项可用于指定Vue实例的挂载目标,属性值仅限于CSS选择器或者DOM节点对象。选项的相关用法如下所示:
<style>
. fixed-width {
display: inline-block;
width: 100px;
}
</style>
<p id="app"><strong class=" fixed-width">CSS选择器:</strong>{{ msg }}</p >
<p id="app2"><strong class=" fixed-width">DOM节点:</strong>{{ msg }}</p >
<p id="app3"><strong class=" fixed-width">手动挂载:</strong>{{ msg }}</p >
<button onclick="handleMount()">手动挂载</button>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min. js"></script>
<script type="text/javascript">
let vm1 = new Vue({
el: '#app', // 选择器
data () {
return {
msg: 'Hello World'
}
}
})
let vm2 = new Vue({
el: document.getElementById('app2'), // HTMLElement
data () {
return {
msg: 'Hello World'
}
}
})
let vm3 = new Vue({
// el: document.getElementById('app3'), // 这里未使用el,而是用其等效用法
data () {
return {
msg: 'Hello World'
}
}
})
let handleMount = function () {
vm3.$mount('#app3')
}
</script>
注意下面代码:
手动挂载
let vm3 = new Vue({
data () {
return {
msg: ‘Hello World’
}
}
})
let handleMount = function () {
vm3.$mount(’#app3’)
}
点击手动挂载后:
2.2 视图的字符串模板
Vue允许开发者使用字符串作为实例的模板,模板字符串由template选项接收,示例的代码如下:
<div id="app">target element</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.
js"></script>
<script type="text/javascript">
let vm = new Vue({
el: '#app',
template: '<h1>template element</h1>' // 模板节点将替换原有DOM节点
})
</script>
代码的运行结果如图
.2.3 渲染函数render
render函数同样也可以用于渲染视图,它提供了回调方法createElement以供我们创建DOM节点,下面来看一段示例代码:
<style>
.btn {
outline: none;
border: none;
cursor: pointer;
padding: 5px 12px;
}
.btn-text {
color: #409eff;
background-color: transparent;
}
.btn-text:hover {
color: #66b1ff;
}
</style>
<div id="app">
<!-- 将实例中 fields & goods 传入组件 -->
< fly-table : fields=" fields" :goods="goods">
<span slot="title">Fly Table Component</span>
</ fly-table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.
js"></script>
<script type="text/javascript">
Vue.component(' fly-table', {
props: { // 组件接收外界传入的参数
fields: {
type: Array,
default () {
return []
}
},
goods: {
type: Array,
default () {
return []
}
}
},
methods: {
reverse () { // 定义数组倒序方法
this.goods.reverse()
}
},
render (createElement) { // 使用render函数渲染DOM
/**
* createElement 可接收三个参数
* 1. HTML标签字符串(String)| 组件选项对象(Object)| 节点解析函数
(Function) * 2. 定义节点特性的对象(Object)
* 3. 子节点,createElement构建的VNode节点或字符串生成的无标签文本节点
(Array|String)
*/
return createElement('div', {
// 作为子组件时的插槽名称
slot: ' fly-table'
}, [
createElement('h2' ,this.$slots.title),
createElement('button', {
// class 用于绑定类名,同v-bind:class的绑定方式
class: ['btn', 'btn-text'],
// attrs 用于绑定节点一般属性,如id、disabled、title等
attrs: {
disabled: false,
title: '点击使数组倒序'
},
// domProps 用于绑定节点DOM属性,如innerHTML、innerText等
domProps: {
innerText: '倒序'
},
on: {
// 绑定事件,使用箭头函数以免创建函数作用域
click: () => {
this.goods.reverse()
}
},
// 自定义指令
directives: [],
// 其他属性
key: 'btnReverse',
ref: 'btnReverse'
}),
createElement('table', {
// style 用于绑定样式,同v-bind:style的绑定方式
style: {
width: '400px',
textAlign: 'left',
lineHeight: '42px',
border: '1px solid #eee',
userSelect: 'none'
}
}, [
createElement('tr', [
this. fields.map( field => createElement('th', field.prop))
]),
this.goods.map(item => createElement('tr', {
style: {
color: item.isMarked ? '#ea4335' : ''
}
}, this. fields.map( field => createElement('td', {
style: {
borderTop: '1px solid #eee'
}
}, [
field.prop !== 'operate' // 如果不是操作列,显示文本
? createElement('span', item[ field.prop]) : createElement('button', { // 否则显示按钮
class: ['btn', 'btn-text'],
domProps: {
innerHTML: '<span>切换标记</span>'
},
on: {
click: () => { // 当按钮被点击时,切换该行文本标记状态
(被标记时字体颜色为红色)
item.isMarked = !item.isMarked
}
}
})
]))))
])
])
}
})
// 声明 Vue 实例
let vm = new Vue({
el: '#app',
data () {
return {
fields: [
{
label: '名称',
prop: 'name'
},
{
label: '数量',
prop: 'quantity' },
{
label: '价格',
prop: 'price'
},
{
label: '',
prop: 'operate'
}
],
goods: [
{
name: '苹果',
quantity: 200,
price: 6.8,
isMarked: false
},
{
name: '西瓜',
quantity: 50,
price: 4.8,
isMarked: false
},
{
name: '榴莲',
quantity: 0,
price: 22.8,
isMarked: false
}
]
}
}
})
</script>
fly-table作为一个定制化功能组件,允许用户查看表格数据、倒序表格、标记表格数据等操作,其DOM渲染由render函数执行,DOM节点由createElement方法创建。之后,定义了Vue实例,并在实例作用域中将数据传入组件。
在初始渲染表格数据时,使用了JS中Array API的map方法,并使用三目运算符判断生成span节点还是button节点。
template和render选项均是用于增加JS代码以减少HTML代码的开发,这样做的好处有两个:一使开发人员可以聚焦于JS代码的书写;二也更贴近于Vue的底层编译器。相比于template, render函数充分地体现了JS的完全编程能力(脱离HTML和CSS代码的开发)。
render函数的回调方法
createElement允许开发者在合适的位置为DOM节点绑定监听事件。
on: {
click: () => {}
}
这是为按钮绑定点击事件的用法,其他事件的绑定方法也大致如此。 不过,在Vue的事件系统中,还有一些很重要的内容,如事件修饰符。在render函数中,如何为事件绑定修饰符呢? 对于一些不易编写的事件修饰符,Vue提供了简写前缀,如表所示。
用法如下: on: {
‘!click’: () => {}, // .capture
‘~keyup’: () => {}, // .once
‘~!mouseover’: () => {} // .capture.once
}
而其他的一些事件修饰符,开发者可以使用原生JS编写,示例如表所示。
部分事件修饰符与原生JS的对照表
用法如下:
on: {
keyup: function (event) {
// .self
if (event.target !== event.currentTarget) return
// .shift && .enter(.13)
if (!event.shiftKey || event.keyCode !==13) return
// .stop
event.stopPropagation()
// .prevent
event.preventDefault()
}
}
下面是有关render函数的拓展内容。 在HTML中,任何内容都是节点,即使没有标签的文本也是节点,层层节点嵌套,形成了一棵DOM树,
在DOM中查询和更新节点是一件比较低效的工作,为此,Vue提供了render函数和虚拟DOM。虚拟DOM将对真实DOM发生的变化进行追踪,以降低DOM查询用时
与document.createElement不同,render中的createElement创建的并不是真实的DOM节点,而是虚拟节点(Virtual Node, VNode),含有开发者描述的节点信息。由VNode组成的树形结构即“虚拟DOM”,Vue将通过虚拟DOM在页面上渲染出真实的DOM。 最后一点,在组件树中,VNode必须保持其身份的唯一,以便Vue一一对应地对每个真实的DOM节点进行追踪。
.2.4 选项的优先级
我们可以发现,el、template、render三个选项的功能是一致的——获取实例模板(指定或是创建)。然而,当实例同时存在这三个选项时Vue将如何处理呢?下面我们通过几个示例来观察一下。
(1)当el、render、template共存时,代码如下:
<div id="app">
<h1>el: {{ msg }}</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.
js"></script>
<script type="text/javascript">
let vm = new Vue({
el: '#app',
render (c) {
return c('h1', 'render: ' + this.msg)
},
template: '<h1>template: {{ msg }}</h1> ',
data () {
return {
msg: 'I want you!'
}
}
})
</script>
运行结果如图
在这个示例中,Vue优先采用了render选项创建的模板。 (2)当el、template共存时,实例代码如下:
<body>
<div id="app">
<h1> el: {{ msg }}</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script type="text/javascript">
let vm=new Vue(
{
el:'#app',
template:'<h1>template: {{ msg }}</h1>',
data(){
return{
msg:'i want you!'
}
}
}
)
</script>
</body>
结果:
可以看到vue优先采用了template选项创建的模板
注: