1.31 Vue.js 学习总结 ( 一 )

 

1.关于 render

  render这个函数,个人感觉就是让js直接写html和css,可以做到完全分离

  这里贴一下书上的代码示例,和我自己瞎搞的一个实例

  1 <!DOCTYPE html>
  2 <html>
  3 <head>
  4   <title></title>
  5 </head>
  6 <body>
  7 <style>
  8   .btn {
  9     outline: none;
 10     border: none;
 11     cursor: pointer;
 12     padding: 5px 12px;
 13   }
 14   .btn-text {
 15     color: #409eff;
 16     background-color: transparent;
 17   }
 18   .btn-text:hover {
 19     color: #66b1ff;
 20   }
 21 </style>
 22 <div id="app">
 23   <!-- 将实例中 fields & goods 传入组件 -->
 24   <fly-table :fields="fields" :goods="goods">
 25     <span slot="title">Fly Table Component</span>
 26   </fly-table>
 27 </div>
 28 <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
 29 <script type="text/javascript">
 30   Vue.component('fly-table', {
 31     props: { // 组件接收外界传入的参数
 32       fields: {
 33         type: Array,
 34         default () {
 35           return []
 36         }
 37       },
 38       goods: {
 39         type: Array,
 40         default () {
 41           return []
 42         }
 43       }
 44     },
 45     methods: {
 46       reverse () { // 定义数组倒序方法
 47         this.goods.reverse()
 48       }
 49     },
 50     render (createElement) { // 使用render函数渲染DOM
 51       /**
 52        * createElement 可接收三个参数
 53        * 1. HTML标签字符串(String)| 组件选项对象(Object)| 节点解析函数(Function)
 54        * 2. 定义节点特性的对象(Object)
 55        * 3. 子节点,createElement构建的VNode节点或字符串生成的无标签文本节点(Array|String)
 56        */
 57       return createElement('div', {
 58         // * 作为子组件时的插槽名称
 59         slot: 'fly-table'
 60       }, [
 61         createElement('h2' ,this.$slots.title),
 62         createElement('button', {
 63           // class 用于绑定类名,同v-bind:class的绑定方式
 64           class: ['btn', 'btn-text'],
 65           // attrs 用于绑定节点一般属性,如id、disabled、title等
 66           attrs: {
 67             disabled: false,
 68             title: '点击使数组倒序'
 69           },
 70           // domProps 用于绑定节点DOM属性,如innerHTML、innerText等
 71           domProps: {
 72             innerText: '倒序'
 73           },
 74           on: {
 75             // 绑定事件,使用箭头函数以免创建函数作用域
 76             click: () => {
 77               this.goods.reverse()
 78             }
 79           },
 80           // 自定义指令
 81           directives: [],
 82           // 其他属性
 83           key: 'btnReverse',
 84           ref: 'btnReverse'
 85         }),
 86         createElement('table', {
 87           // style 用于绑定样式,同v-bind:style的绑定方式
 88           style: {
 89             width: '400px',
 90             textAlign: 'left',
 91             lineHeight: '42px',
 92             border: '1px solid #eee',
 93             userSelect: 'none'
 94           }
 95         }, [
 96           createElement('tr', [
 97             this.fields.map(field => createElement('th', field.prop))
 98           ]),
 99           this.goods.map(item => createElement('tr', {
100             style: {
101               color: item.isMarked ? '#ea4335' : ''
102             }
103           }, this.fields.map(field => createElement('td', {
104             style: {
105               borderTop: '1px solid #eee'
106             }
107           }, [
108             field.prop !== 'operate' // 如果不是操作列,显示文本
109               ? createElement('span', item[field.prop])
110               : createElement('button', { // 否则显示按钮
111                 class: ['btn', 'btn-text'],
112                 domProps: {
113                   innerHTML: '<span>切换标记</span>'
114                 },
115                 on: {
116                   click: () => { // 当按钮被点击时,切换该行文本标记状态(被标记时字体颜色为红色)
117                     item.isMarked = !item.isMarked
118                   }
119                 }
120               })
121           ]))))
122         ])
123       ])
124     }
125   })
126   // 声明 Vue 实例
127   let vm = new Vue({
128     el: '#app',
129     data () {
130       return {
131         fields: [
132           {
133             label: '名称',
134             prop: 'name'
135           },
136           {
137             label: '数量',
138             prop: 'quantity'
139           },
140           {
141             label: '价格',
142             prop: 'price'
143           },
144           {
145             label: '',
146             prop: 'operate'
147           }
148         ],
149         goods: [
150           {
151             name: '苹果',
152             quantity: 200,
153             price: 6.8,
154             isMarked: false
155           },
156           {
157             name: '西瓜',
158             quantity: 50,
159             price: 4.8,
160             isMarked: false
161           },
162           {
163             name: '榴莲',
164             quantity: 0,
165             price: 22.8,
166             isMarked: false
167           }
168         ]
169       }
170     }
171   })
172 </script>
173 </body>
174 </html>
View Code
 1 <!DOCTYPE html>
 2 <html lang="zh-CN">
 3 
 4 <head>
 5     <meta charset="UTF-8">
 6     <title>Document</title>
 7     <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
 8 </head>
 9 <style>
10     .test{
11         color: coral;
12     }
13     #slot-title{
14         color: pink;
15     }
16 </style>
17 <body>
18     <div id="app">
19         <test :msg="msg">
20             <span id="slot-title" slot="title">this is a ttile</span>
21         </test>
22     </div>
23 </body>
24 
25 <script>
26     Vue.component('test', {
27         props: {
28             msg: {
29                 type: String,
30                 default() {
31                     return []
32                 }
33             }
34         },
35         render: function (createElement) {
36             return createElement('div', {
37                 class: ["test"]
38                 // domProps:{
39                 //     innerText:'hello world'
40                 // }
41             }, [
42                 createElement("h2",this.$slots.title),
43                 // createElement("h2",{
44                 //     slot:"",
45                 //     style:{
46                 //         color: ""
47                 //     }
48                 // }),  // 这个好像没有用
49                 createElement("div", {
50                     domProps: {
51                         innerText: this.msg
52                     }
53                 })
54             ])
55         }
56     })
57     var vm = new Vue({
58         el: '#app',
59         data() {
60             return {
61                 msg: 'this is created by [render]'
62             }
63         },
64         methods: {}
65     });
66 </script>
67 
68 </html>
View Code

  简单来说,render 里面就是一个 不断套娃 的过程,正如html的标签一样,盒子套盒子,整吐了都

  render ( createElement ) 中 createELement 的参数 ( 第一个 通常就是 html标签类型 | 第二个是一个对象,里面是下图的一些属性 | 第三个 通常是一个数组 装的是createElement方法  /* 套娃 */  )

  

 

  如果看完了上面的代码,可能就会有一个简单的概念,然后我们深入一下

  有没有想过 render 里面的 createElement 到底返回的是什么,其实可以这样理解

    每有一个 createElement 就有一个 VNode

  官网的解释

  

  然后是 VNode的约束,即 

 

 

 

  

  书上有一句看似不起眼的话

    “ 最后一点,在组件树中,VNode 必须保持其身份的唯一,以便 Vue 一一对应地对每一个真实的 DOM 节点进行追踪。 ”

  其实 我认为 就是 重复的 VNode 就没办法好好更新 真实的 DOM

 2.关于 filter

  {{ msg | dealMsg_1 | dealMsg_2 }}  用管道符号搞的这种,就是filter 而且应该是 

    从左往右,依次递交

      

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4   <title></title>
 5 </head>
 6 <body>
 7 <div id="app">
 8   <h1>{{ title }}</h1>
 9   <h1>{{ title | supplyTitle1 }}</h1>
10   <!-- 存在多个filter时,将从左向右执行 -->
11   <h1>{{ title | supplyTitle1 | supplyTitle2 }}</h1>
12 </div>
13 <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
14 <script type="text/javascript">
15   let vm = new Vue({
16     el: '#app',
17     data () {
18       return {
19         title: 'Test#%for#%Filter.'
20       }
21     },
22     filters: {
23       supplyTitle1 (value) { // 表达式的值将作为形参传入
24         console.log('Supply Title 1')
25         return value.replace(/#/g, ' ')
26       },
27       supplyTitle2 (value) {
28         console.log('Supply Title 2')
29         return value.replace(/%/g, '')
30       }
31     }
32   })
33 </script>
34 </script>
35 </body>
36 </html>
View Code

3.关于 el,template , render 的顺序

  render > template > el

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4   <title></title>
 5 </head>
 6 <body>
 7 <div id="app">
 8   <h1>el: {{ msg }}</h1>
 9 </div>
10 <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
11 <script type="text/javascript">
12   let vm = new Vue({
13     el: '#app',
14     render (c) {
15       return c('h1', 'render: ' + this.msg)
16     },
17     template: '<h1>template: {{ msg }}</h1> ',
18     data () {
19       return {
20         msg: 'I want you!'
21       }
22     }
23   })
24 </script>
25 </body>
26 </html>
View Code

4.对于 mixin与实例的冲突与合并

   

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4   <title></title>
 5 </head>
 6 <body>
 7 <style>
 8   #app {
 9     color: #2c3e50;
10     font-family: Roboto, sans-serif;
11   }
12   .label {
13     display: inline-block;
14     min-width: 160px;
15   }
16 </style>
17 <div id="app">
18   <h1>{{ title }}</h1>
19   <p><strong class="label">Text:</strong>{{ text }}</p>
20   <p><strong class="label">Plus Text:</strong>{{ plusText }}</p>
21   <p><strong class="label">Upper Text:</strong>{{ text | supplyUpper }}</p>
22   <button @click="toggleText">切换文本</button>
23 </div>
24 <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
25 <script type="text/javascript">
26   // 强耦合,需要被混入组件的data根节点中包含text属性
27   let mixin = {
28     data () {
29       return {
30         title: 'Test for mixin'
31       }
32     },
33     mounted () {
34       console.log('mixin mounted')
35     },
36     methods: {
37       toggleText () {
38         this.text = 'mixin text'
39       }
40     },
41     computed: {
42       plusText () { // 此处需要创建函数作用域以使this指向Vue实例
43         return '+ ' + this.text + ' +'
44       }
45     },
46     filters: { // 选项过滤器
47       supplyUpper: value => value.toUpperCase()
48     },
49     watch: { // 监听器
50       text (value) {
51         console.log('mixin text: ' + value)
52       }
53     }
54   }
55   let vm = new Vue({
56     el: '#app',
57     mixins: [ mixin ],
58     data () {
59       return {
60         title: 'A Title',
61         text: 'which one?'
62       }
63     },
64     mounted () {
65       console.log('instance mounted')
66     },
67     methods: {
68       toggleText () {
69         this.text = 'instance text'
70       }
71     },
72     watch: {
73       text (value) {
74         console.log('instance text: ' + value)
75       }
76     }
77   })
78 </script>
79 </body>
80 </html>
View Code

 

 

总结

  今天学习的还好,就是对render 那里卡了一下午

  有过一次做轮播图的经验,但是感觉这些东西 在实际项目的时候还是会用笨方法来操作

  看后续实战项目的学习了

 

posted @ 2021-01-31 20:08  WaterMealone  阅读(114)  评论(0编辑  收藏  举报