笔记2. vue中DOM渲染 指定被挂载元素 视图的字符串模板 选项的优先级

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选项创建的模板
注:

el:'#app' 中的 app可以任意取id
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页