Vue学习笔记

作者: 冬天吃橘子_Autumn | 来源:发表于2019-06-13 18:41 被阅读0次

    最近在学习Vue,下面是学习过程中总结了一些基本的知识点

    Vue

    一. 基本知识

    1. 实例化

    var app = new Vue({
    
        el: '#app',  //绑定到元素上
        data: {
            message:'hello world'
        },
        filters:{
            filterName1:function(){},
            filterName2:function(){}
        },
        methods:{
            methodName1:function(){},
            methodName2:function(){}
        },
        //生命周期钩子
        created:function(){
            //未挂载到dom之前触发
        },
        mounted:function(){
            //挂载到dom后触发
        },
        beforeDestroy:function(){
            
        }
        
    })
    

    2. 过滤器

    {{ data中的变量名 | filter中的过滤器名 }}

    3. 指令和事件

    • v-text:解析文本,和{{ }}作用一样

    • v-html:解析html

    • v-bind:动态更新HTML元素上的属性

    • v-on:绑定事件监听器

    • v-bind语法糖:冒号 :

    • v-on语法糖:@

    • v-bind的作用,以及v-bind的变量语法,数组语法,对象语法:

      1. v-bind通常用来绑定属性的,格式是v-bind:属性名 = "值",简写:属性名 = "值"
      2. 变量语法:v-bind:class = "变量",变量形式 ,这里的变量的值,通常是在css定义好的类名;
      3. 数组语法:v-bind:class= "[变量1,变量2]" ,数组形式,其实跟上面差不多,只不过可以同时绑定多个class名;
      4. 对象语法:v-bind:class = {classname1:boolean,classname2:boolean},对象形式,这里的classname1(2)其实就是样式表中的类名,这里的boolean通常是一个变量,也可以是常量、计算属性等,这种方法也是绑定class最常用的方式。

    4. VUE内置指令

    • v-cloak : 解决页面没加载完的时候出现类似{{ msg }}等变量名的现象,一般和display:none一起使用

      <style>
          [v-cloak]:{
              display-none;
          }
      </style>
      -------------------------
      <p v-cloak>
          {{ msg }}
      </p>
      
    • v-once:只在页面中渲染一次,改变变量的值也不会重新渲染

      <p v-once>
          {{ msg }}
      </p>
      
    • 条件指令:v-if

      • v-if : 后面接的是等号,等号后面的内容必须是布尔值,布尔值为true则渲染,否则不渲染

      • v-else

      • v-else-if

      • 例:

        <p v-if = '6>3'>{{ apple }}</p>
        <p v-else-if = '9<6'> {{ banana}} </p>
        <p v-else> {{ orange }} </p>
        
      • v-if的弊端:Vue在渲染元素时,出于效率考虑,会尽可能的复用已有的元素而非重新渲染,因
        此会出现乌龙

      • 解决方法:加key,唯一,提供key值可以来决定是否复用该元素

    • v-show:只改变display属性

      • v-if和v-show的区别:

        v-if:实时渲染:页面显示就渲染,不显示就移除

        v-show:元素始终存在于页面中,只是改变了display属性

    • v-for

      • 遍历多个对象:data 里面是一个数组

        <div id='app'>
            <ul>
                <!-- intm in items -->
                <li v-for="fruit in fruits">{{ fruit.name }}</li>
            </ul>
            
            <ul>
              <!-- 带索引的写法 -->
              <li v-for="(fruit,index) in fruits">第{{ index }}个 {{ fruit.name }}</li>
            </ul>
        </div>
        
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    //这里是一个数组
                    fruits: [
                        {name: 'apple'},
                        {name: 'banana'},
                        {name: 'orange'}
                    ]
                }
            })
        </script>
        
    • 遍历一个对象的多个属性

      <div id='app'>
          <span v-for='value in fruits'>{{ value }}</span>
          
          <!-- 带v-k-i的写法:value key index (外开)  -->
          <p v-for="(value,key,index) in fruits2">
            value:{{value}}<br>
            key:{{key}}<br>
            index:{{index}}
          </p>
      </div>
      
      <script>
          var app = new Vue({
              el: '#app',
              data: {
                  //这里是一个对象
                  fruits: {
                      fruit1: 'apple',
                      fruit2: 'banana',
                      fruit3: 'orange'
                  }
              }
          })
      </script>
      
    • v-model表单

    5. 计算属性

    • 基础例子

      <div id="example">
        <p>Original message: "{{ message }}"</p>
        <p>Computed reversed message: "{{ reversedMessage }}"</p>
      </div>
      var vm = new Vue({
        el: '#example',
        data: {
          message: 'Hello'
        },
        computed: {
          // 计算属性的 getter
          reversedMessage: function () {
            // `this` 指向 vm 实例
            return this.message.split('').reverse().join('')
          }
        }
      })
      
    • 计算属性的 setter

      计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter :

      在赋值的时候会触发set函数,把新赋的值以参数的形式传递进去

      // ...
      computed: {
        fullName: {
          // getter
          get: function () {
            return this.firstName + ' ' + this.lastName
          },
          // setter
          set: function (newValue) {
            var names = newValue.split(' ')
            this.firstName = names[0]
            this.lastName = names[names.length - 1]
          }
        }
      }
      // ...
      

      现在再运行 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstNamevm.lastName也会相应地被更新。

    6. 数组更新、过滤与排序

    改变数组的一系列方法:

    • push() 在末尾添加元素
    • pop() 将数组的最后一个元素移除
    • shift() 删除数组的第一个元素
    • unshift():在数组的第一个元素位置添加一个元素
    • splice() :可以添加或者删除函数—返回删除的元素
      三个参数:
      • 第一个参数 表示开始操作的位置
      • 第二个参数表示:要操作的长度
      • 第三个为可选参数:
        • sort():排序
        • reverse()

    两个数组变动vue检测不到:

    1. 改变数组的指定项
    2. 改变数组长度
      过滤:filter

    解决方法:

    改变指定项: Vue.set(app.arr,1,”car”);
    app.arr.splice(1): 改变数组长度

    二. 组件

    组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用 is 特性进行了扩展的原生 HTML 元素。所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。

    1. 组件用法

    • 全局注册

      Vue.component('component-name',{
        template: '<div>组件内容</div>'
      })
      //优点:所有Vue实例都可以使用
      //缺点:权限太大,容错率低
      
    • 局部注册

      var app = new Vue({
        el: '#app',
        data:{},
          components: {
              'component-name': {
                  template: '<div>组件内容</div>'
              }
          }
      })
      
    • 注意事项:

      • 组件名用横杆命名法,不能用驼峰命名法

      • template中的内容必须被一个DOM元素包起来

      • 在组件的定义中,除了template,还可以有data、methods、computed选项

      • data必须是一个方法

        data: function(){
            return {
                message: 'hello world'
            }
        }
        

    2. props父级向子级传递数据

    • 在组件中使用props从父组件接收参数,props中定义的属性,在组件送可以直接使用

    • props来自父级,而data中return的数据是自己组件本身的数据,两种数据的作用域都是组件本身,可以在template、methods、computed中直接使用

    • props的值有两种,一种是字符串数组,一种是对象

    • 可以使用v­bind动态绑定父组件来的内容

      <div id="app">
          ---用v-bind传递数据(需要回车)-------------------------<br>
          <input type="text" v-model.lazy="parentMsg">
          <bind-component v-bind:msg='parentMsg'></bind-component>
      </div>
      
      var app = new Vue({
          el: '#app',
          data: {
              count: 0,
              parentMsg: '这是来自父级的数据'
          },
          components: {
              'bind-component': {
                  props:['msg'],
                  template: '<div>{{ msg }}</div>'
              }
          }
      })
      

    3. 单项数据流

    • props传递数据是单向的,父级数据的变化会传递给子级,反之就行不通了

    • 单向数据流可以避免子组件无意中修改父组件状态

    • 应用情景:

      • 第一种:父组件传递初始值进来,子组件将它作为初始值保存起来,在自己的作用域
        下可以随意使用和修改。

        <div id="app">
            <my-component msg="来自父级的数据"></my-component>
        </div>
        ---javascript---------------------
        <script>
            var app = new Vue({
                el: '#app',
                data: {},
                components: {
                    'my-component': {
                        props: ['msg'],
                        template: '<p>{{ newMsg }}<p>',
                        data: function () {
                            return {
                                //在data中保存下来
                                newMsg: this.msg
                            }
                        }
                    }
                }
            })
        </script>
        
      • 第二种:需要被转变的原始值传入,通过props获取,通过计算属性进行转换

        <div id="app">
            <input type="number" v-model="width">
            <computed-component :wth='width'></computed-component>
          </div>
        
          <script src="https://cdn.jsdelivr.net/npm/vue"></script>
          <script>
            var app = new Vue({
              el: '#app',
              data: {width:10},
              components: {
                'computed-component': {
                  props: ['wth'],
                  template:'<div :style="style"></div>',
                  //用计算属性转换传入的值
                  computed: {
                    style: function(){
                      return {
                        width: this.wth + 'px',
                        height: '100px',
                        background: 'red'
                      }
                    }
                  }
                }
              }
            })
          </script>
        

    4. 组件命名注意事项

    • 在html中, myMessage 和 mymessage 是一致的,因此在组件中的html
      中使用必须使用kebab­case(短横线)命名方式。在html中不允许使用驼
      峰!!!!!!
    • 在组件中, 父组件给子组件传递数据必须用短横线。在template中,必
      须使用驼峰命名方式,若为短横线的命名方式。则会直接保错。
    • 在组件的data中,用this.XXX引用时,只能是驼峰命名方式。若为短横线
      的命名方式,则会报错。

    5. 数据类型验证

    • 验证的 type 类型可以是:

      • String
      • Number
      • Boolean
      • Object
      • Array
      • Function
      Vue.component ( ‘ my-compopent ’, {
          props : {
              //必须是数字类型
              propA : Number ,
              //必须是字符串或数字类型
              propB : [String , Number] ,
              //布尔值,如果没有定义,默认值就是 true
              propC: {
                  type : Boolean ,
                      default : true
              },
              //数字,而且是必传
              propD: {
                  type: Number ,
                  required : true
              },
              //如果是数组或对象,默认值必须是一个函数来返回
              propE: {
                  type : Array,
                  default : function () {
                      return [] ;
                  }
              },
              //自定义一个验证函数
              propF: {
                  validator : function (value) {
                      return value > 10;
                  }
              }
          }
      });
      

    三. 组件通信

    1. 自定义事件

    用于:子组件给父级传递数据

    子组件用$emit ( '父组件中事件名' , 要传递的数据 ) 来触发事件 ,父组件用@'父组件中事件名'='触发的函数'来 监昕子组件的事件,触发的函数的参数即为子组件传递来的数据

    第一步:自定义事件
    第二步:在子组件中用$emit触发事件,第一个参数是事件名,后边的参数是要传递的数据
    第三步:在自定义事件中用一个参数来接受

    <div id="app">
        您的余额是:{{ acount }}<br>
        <my-component :acount="acount" @change-acount='handleAcount'></my-component>
    </div>
    
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                acount: 2000
            },
            methods:{
                handleAcount:function(value){
                    this.acount = value
                }
            },
            components: {
                'my-component': {
                    props:['acount'],
                    template: `<div>
                                <button @click="addAcount">+1000</button> 
                                <button @click="reduceAcount">-1000</button>
                             </div>`,
                    data: function(){
                        return {
                            count: this.acount
                        }
                    },
                    methods:{
                        addAcount: function(){
                            this.count += 1000
                            //注意这里$emit的参数
                            this.$emit('change-acount',this.count)
                        },
                        reduceAcount: function(){
                            this.count -= 1000
                            this.$emit('change-acount',this.count)
                        }
                    }
                }
            }
        })
    

    2. 在组件中使用v-model

    在组件中使用v­-model 其实是一个语法糖,这背后其实做了两个操作

    • v-­bind 绑定一个 value 属性
    • v-­on 指令给当前元素绑定 input 事件

    $emit('input',value)的代码,这行代码实际上会触发一个 input事件, ‘input’后的参数就是传递给v­-model绑定
    属性的值

    <div id="app">
        您的余额是:{{ acount }}<br>
        <!-- <my-component :acount="acount" @change-acount='handleAcount'></my-component> -->
        <!-- 下面使用v-model -->
        <my-component :acount="acount" v-model='acount'></my-component>
    </div>
    
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                acount: 2000
            },
            components: {
                'my-component': {
                    props:['acount'],
                    template: `<div>
                                <button @click="addAcount">+1000</button> 
                                <button @click="reduceAcount">-1000</button>
                              </div>`,
                    data: function(){
                        return {
                            count: this.acount
                        }
                    },
                    methods:{
                        addAcount: function(){
                            this.count += 1000
                            // 这里触发的是input事件
                            this.$emit('input',this.count)
                        },
                        reduceAcount: function(){
                            this.count -= 1000
                            this.$emit('input',this.count)
                        }
                    }
                }
            }
        })
    </script>
    

    3. 非父组件之间的通信---bus中介

    用于两个组件之间的通信,(非父子关系),可以在根组件中用一个空的Vue对象作为中介,一个组件中监听该中介的自定义事件,另一个组件中触发该自定义事件并传递数据

    <div id="app">
        <acomponent></acomponent>
        <bcomponent></bcomponent>
    </div>
    
    <script>
        Vue.component('acomponent', {
          template: '<button @click="handle">点击向B组件传递数据</button>',
          data: function () {
            return {
              msg: '我是来自A组件的数据'
            }
          },
          methods: {
            handle: function () {
              // 触发根组件的bus中的method1事件
              this.$root.bus.$emit('method1', this.msg)
            }
          }
        })
        Vue.component('bcomponent', {
          template: '<div>{{ msg }}</div>',
          data: function () {
            return {
              msg: '这是B组件'
            }
          },
          created: function () {
            // 对根组件bus监听method1事件
            this.$root.bus.$on('method1',  (value)=> {
              this.msg = value
            })
          }
        })
        var app = new Vue({
          el: '#app',
          data: {
            bus: new Vue()
          }
        })
    </script>
    

    4. 父链和子链

    父链:this.$parent

    子链:this.$refs.索引
    提供了为子组件提供索引的方法,用特殊的属性ref为其增加一个索引

    <div id="app">
        <button @click='clickA'>A子组件</button>
        <button @click='clickB'>B子组件</button>
        <son-a ref='a'></son-a>
        <son-b ref='b'></son-b>
    </div>
    
    <script>
        var app = new Vue({
            el: '#app',
            data: { msg: '来自父组件的msg' },
            methods: {
                clickA: function(){
                    alert(this.$refs.a.name)
                },
                clickB: function(){
                    alert(this.$refs.b.name)
                }
            },
            components: {
                'son-a': {
                    template: '<div>这是子组件:{{ msg }}</div>',
                    data: function () {
                        return {
                            msg: this.$parent.msg,
                            name: 'son-a'
                        }
                    }
                },
                'son-b': {
                    template: '<div><div>',
                    data: function () {
                        return {
                            name: 'son-b'
                        }
                    }
                }
            }
        })
    </script>
    
    

    四. 插槽slot标签

    1. 单个插槽

    用于混合父组件的内容与子组件的模板

    在子组件中加入<slot></slot>标签,当父组件中没有传入内容时,默认显示slot标签中的内容,反之,则将传入内容替换掉原来slot标签中的内容

    <div id="app">
        <my-component>
            <p>{{ msg }}</p>
        </my-component>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        Vue.component('my-component', {
            template: `<div>
                            <slot>
                                如果父元素没传内容进来,就默认显示我吧!
                            </slot>
                       </div>`
        })
        var app = new Vue({
            el: '#app',
            data: {msg:'父元素的内容'}
        })
    </script>
    
    

    2. 具名插槽

    把父组件要传入的标签命名slot='名称',在子组件的slot标签中添加name属性

    <div id="app">
        <my-component>
            <div slot='header'>标题</div>
            <div slot='container'>正文</div>
            <div slot='footer'>底部</div>
        </my-component>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        Vue.component('my-component', {
          template: `<div>
                      <slot name='header'>
                        如果父元素没传内容进来,就默认显示我吧!
                      </slot>
                     </div>`
        })
        var app = new Vue({
          el: '#app',
          data: {msg:'父元素的内容'}
        })
    </script>
    
    

    3. 作用域插槽

    从子组件中获取数据:在父组件中添加<template></template>标签,slot属性的值与子元素<slot>标签的name属性一样,用slot-scope属性获取传来的数据(除了name)

    <div id="app">
        <my-component>
            <!-- 这里的prop是变量名,随便取一个名字都可以
                 slot的值要跟子组件的name相同
                 template标签不会被渲染
                 template标签用其他例如<p>、<span>等都可以 -->
            <template slot-scope='prop' slot='abc'>
                <!-- 可以获取除了name以外传来的内容 -->
                {{ prop.text }}
            </template>
        </my-component>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>    
        Vue.component('my-component', {
          template: `<div>
                      <slot name='abc' text='子组件中传来的内容'>
                        如果父元素没传内容进来,就默认显示我吧!
                      </slot>
                     </div>`
        })
        var app = new Vue({
          el: '#app',
          data: {msg:'父元素的内容'}
        })
    </script>
    
    

    4. 访问slot

    通过this.$slots.name访问

    Vue.component('my-component2', {
          template: `<div>
                      <slot name='header'>
                        如果父元素没传内容进来,就默认显示我吧!
                      </slot>
                      <slot name = 'footer'></slot>
                     </div>`,
          mounted:function(){
            var header = this.$slots.header
            var footer = this.$slots.footer
            console.log(header[0].elm.innerText)
            console.log(footer[0].elm.innerText)
          }
    })
    

    五. 动态组件

    VUE给我们提供 了一个元素叫component
    作用是: 用来动态的挂载不同的组件
    实现:使用is特性来进行实现的

    <div id="app">
        <!-- 绑定is属性 -->
        <component :is='thisView'></component>
        <button @click="handleView('A')">页面一</button>
        <button @click="handleView('B')">页面二</button>
        <button @click="handleView('C')">页面三</button>
        <button @click="handleView('D')">页面四</button>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                thisView: 'compA'
            },
            methods:{
                'handleView':function(value){
                    this.thisView = 'comp' + value
                }
            },
            components:{
                'compA':{template:'<div>页面一</div>'},
                'compB':{template:'<div>页面二</div>'},
                'compC':{template:'<div>页面三</div>'},
                'compD':{template:'<div>页面四</div>'}
            }
        })
    </script>
    

    六. 自定义指令

    自定义指令的基本用法

    和组件类似分全局注册和局部注册,区别就是把component换成了derective

    • 钩子函数

      指令定义函数提供了几个钩子函数(可选):

      • bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时 执行一次的初始化动作。
      • inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。 update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的 绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。
      • componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。 unbind: 只调用一次, 指令与元素解绑时调用。
    • 钩子函数的参数有:

      • el: 指令所绑定的元素,可以用来直接操作 DOM 。
      • binding: 一个对象,包含以下属性:
        • name: 指令名,不包括 v­ 前缀。
        • value: 指令的绑定值, 例如: v­my­directive=”1 + 1”, value 的值是 2。
        • oldValue: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
        • expression: 绑定值的字符串形式。 例如 v­my­directive=”1 + 1” , expression 的值是 “1 + 1”。
        • arg: 传给指令的参数。例如 v­my­directive:foo, arg 的值是 “foo”。
        • modifiers: 一个包含修饰符的对象。 例如: v­my­directive.foo.bar, 修饰符对象,,,modifiers 的值是 { foo: true, bar: true }。
      • vnode: Vue 编译生成的虚拟节点。
      • oldVnode: 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。 自定义的指令

    七、render函数

    1. 基本用法

    在自定义组件时,template属性内容有时会很长,而且,在切换组件内的内容时,不显示的内容可能也会渲染一遍再隐藏,而在组件中用render函数可以解决这个问题

    render函数的参数必须是createElement,这是在源码中已经定义好的函数

    render函数要记得把createElement函数执行结果返回出去

    <div id="app">
        <comp :thisview='thisView'>
            <slot slot='red'>red</slot>
            <slot slot='blue'>blue</slot>
        </comp>
        <button @click='clickRed'>red</button>
        <button @click='clickBlue'>blue</button>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        Vue.component('comp', {
            props: ['thisview'],
            //这里的参数必须是createElement,是源码中已经定义好的函数
            render: function (createElement) {
                return createElement('div', this.$slots[this.thisview])
            },
            data: function () {
                return {
                    view: this.thisview
                }
            }
        })
        var app = new Vue({
            el: '#app',
            data: { thisView: 'red' },
            methods: {
                clickRed: function () {
                    this.thisView = 'red'
                },
                clickBlue: function () {
                    this.thisView = 'blue'
                }
            }
        })
    </script>
    
    

    2. createElement函数的参数

    render函数返回createElement函数的执行结果

    • 第一个参数 :createElement函数的第一个参数必选,可以是String、Object、Function

      • String:html标签,比如'div'、'h1'等等

        Vue.component('child',{
            render:function(createElement){
                return createElement('div')
            }
        })
        
        
    • Object:含有数据选项的对象,比如:

      Vue.component('child',{
          render:function(createElement){
              return createElement({
                  template: '<div>文字内容</div>'
              })
          }
      })
      
      
    • Function:返回含有数据选项的对象,比如:

      Vue.component('child',{
          render:function(createElement){
              var domFn = function(){
                  return {
                      template: '<div>文字内容</div>'
                  }
              }
              return createElement(domFn())
          }  
      })
      
      
    • 第二个参数:数据对象(可选)——只能是Object

      下面是一些常见的选项:style、class、attrs、domProps等

      Vue.component('child',{
          render:function(createElement){
              return createElement({
                  template: '<div>文字内容</div>'
              },{
                  'class': {
                      //表示类名class,true为有该类名,false则相反
                      //class在js中是关键字,最好用引号包起来,不加也没事
                      foo: true,
                      baz: false
                  },
                  style: {
                      color: 'red',
                      //css中的横杆命名在这里都要写成驼峰命名
                      fontSize: '20px'
                  },
                  attrs: {
                      //attributes,正常的HTML属性,大部分可以写进来
                      id: 'red',
                      src: '../XXX.jpg'
                  },
                  domProps: {
                      //用来写原生的DOM属性
                      innerHTML: '<span style="color:red;">文字内容</span>'
                  }
              })
          }
      })
      
    • 第三个参数:代表子节点,可选——可以是String 或 Array(Array常用)

      因为第二个参数可选且必须为Object,所以,如果第二个参数为String或Array,那么意味着第二个参数为空,这个String或Array是第三个参数,子节点

      其实第三个参数存的就是VNODE虚拟节点

      Vue.component('child',{
          render: function(createElement){
              return createElement({
                  template: '<div>内容</div>'
              },{
                  class:{
                      red: true
                  }
              },[
                  //这里的内容时字符串,不是对象,所以也是子节点(第三个参数)
                  createElement('span','内容'),
                  createElement('span','内容')
              ])
          }
      })
      

    3. this.$slots在render函数中的使用

    插槽的用法

    第三个 参数存的就是VNODE

    createElement(‘header’,header), 返回的就是VNODE

    var header = this.$slots.header; //这返回的内容就是含有VNODE的数组

    <div id="app">
        <child>
            <span slot='header'>我是标题</span>
            <span slot='main'>我是正文</span>
            <span slot='main'>我是正文</span>
            <span slot='footer'>我是结尾</span>
        </child>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        Vue.component('child', {
            render: function (createElement) {
                var header = this.$slots.header
                var main = this.$slots.main
                var footer = this.$slots.footer
                return createElement('div', {
                    'class': {
                        red: true
                    }
                }, [
                    createElement('header', header),
                    createElement('main', main),
                    createElement('footer', footer)
                ])
            }
        })
        var app = new Vue({
            el: '#app',
            data: {}
        })
    
    

    4. 在 render中使用props传递数据

    5. 在render函数中使用v-model

    <div id="app">
        <my-component :inputvalue='inputvalue' @change='changevalue'></my-component><br>
        <!-- 这里的v-model是语法糖,绑定input事件,当触发input事件时,把传来的值付给inputvalue -->
        <my-component :inputvalue='inputvalue' v-model='inputvalue'></my-component><br>
        {{ inputvalue }}
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                inputvalue: '111'
            },
            methods: {
                changevalue: function (value) {
                    this.inputvalue = value
                }
            },
            components: {
                'my-component': {
                    props: ['inputvalue'],
                    render: function (createElement) {
                        return createElement('input', {
                            attrs: {
                                value: this.inputvalue
                            },
                            on: {
                                input: (event) => {
                                    this.$emit('change', event.target.value)
                                    this.$emit('input', event.target.value)
                                }
                            }
                        })
                    }
                }
            }
        })
    </script>
    
    

    6. 作用域插槽

    向组件的插槽中传递数据

    $scopedSlots.default

    <div id="app">
        <my-component>
            <template scope='abc'>
                {{ abc.text }}<br>
                {{ abc.name }}
            </template>
        </my-component>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {},
            components: {
                'my-component': {
                    render: function (createElement) {
                        return createElement('div', this.$scopedSlots.default({
                            text: '我是子组件传来的数据',
                            name: '陈秋钿'
                        }))
                    }
                }
            }
        })
    </script>
    

    7. 函数化组件

    functional:true //表示当前Vue实例无状态、无实例

    无实例:组件内部没有this,可以通过context上下文来解决,render函数的第一个参数是createElement,第二个参数是context,这里this是window

    context.parent

    context.props

    context.props.text ---- this.text

    context.children ----- this.$slots.default

    八. vue-cli脚手架

    1. 安装步骤

    首先电脑上要安装最新版的nodeJS.官网下载,安装完之后安装淘宝npm镜像

    npm install -g cnpm --registry=https://registry.npm.taobao.org

    • 安装五部走:

      • 全局安装vue­cli

        npm install -g vue-cli

      • 进入目录–初始化项目

        vue init webpack my-project

      • 进入项目

        cd my-project

      • 安装依赖

        npm install

      • 启动项目

        npm run dev

    • 部署项目:

      npm run build

    2. 目录结构

    ├── build // 项目构建(webpack)相关代码 记忆:(够贱) 9个
    │ ├── build.js // 生产环境构建代码
    │ ├── check­versions.js // 检查node&npm等版本
    │ ├── dev­client.js // 热加载相关
    │ ├── dev­server.js // 构建本地服务器
    │ ├── utils.js // 构建配置公用工具
    │ ├── vue­loader.conf.js // vue加载器
    │ ├── webpack.base.conf.js // webpack基础环境配置 //entry程序的入口
    │ ├── webpack.dev.conf.js // webpack开发环境配置
    │ └── webpack.prod.conf.js // webpack生产环境配置
    二、
    ├── config// 项目开发环境配置相关代码 记忆: (环配) 3个
    │ ├── dev.env.js // 开发环境变量(看词明意)
    │ ├── index.js //项目一些配置变量
    │ └── prod.env.js // 生产环境变量
    三、
    ├──node_modules// 项目依赖的模块 记忆: (依赖) *个
    四、
    ├── src// 源码目录5
    1
    │ ├── assets// 资源目录
    │ │ └── logo.png
    2
    │ ├── components// vue公共组件
    │ │ └── Hello.vue
    3
    │ ├──router// 前端路由
    │ │ └── index.js// 路由配置文件
    4
    │ ├── App.vue// 页面入口文件(根组件)
    5
    │ └── main.js// 程序入口文件(入口js文件)
    五、
    └── static// 静态文件,比如一些图片,json数据等
    │ ├── .gitkeep
    剩余、
    ├── .babelrc// ES6语法编译配置
    ├── .editorconfig// 定义代码格式
    ├── .gitignore// git上传需要忽略的文件格式
    ├── index.html// 入口页面
    ├── package.json// 项目基本信息
    ├── README.md// 项目说明

    3. 其他

    以 .vue 结尾的是组件文件,组件文件中的样式只对组件中的标签有用

    九. 前端路由和vuex状态管理

    访问不同的路由,加载不同的组件(输入不同的网址,显示不同的内容)

    watch: {
        // 如果路由有变化,会再次执行该方法
        $route: "getUserData"
    }
    

    1. vue­-router路由基本加载

    • 安装

      npm install --save vue-router
      
      • 引用
      import router from 'vue-router'
      Vue.use(router)
      
    • 配置路由文件,并在vue实例中注入

      var rt = new router({
          routes:[{ //这里是routes,不是routers啊
              path:'/',//指定要跳转的路径
              component:HelloWorld//指定要跳转的组件
          }]
      })
      new Vue({
          el: '#app',
          router: rt,
          components: { App },
          template: ''
      })
      
    • 确定视图加载的位置

      <router-view></router-view>
      

    2. 路由的跳转

    用router-link

    <router-link to="/"></router-link>
    
    <template>
        <ul>
            <li>
                <router-link to="/helloworld">HELLO WORLD</router-link>
            </li>
            <li>
                <router-link to="/helloearth">HELLO EARTH</router-link>
            </li>
        </ul>
    </template>
    

    3. 通过路由传递参数

    • 在路由中加入name属性
    • 在path后面加 "/ : 要传递的参数 "
    • router-link标签中绑定toname 和 params结合使用,在组件中用 $route.params.XXX 获取传来的参数
    <!-- list.vue -->
    <template>
        <ul>
            <li>
                <router-link :to="{name: 'helloworld',params:{worldmsg: '你好世界'}}">
                    HELLO WORLD
                </router-link>
            </li>
            <li>
                <router-link :to="{name:'helloearth',params:{earthmsg:'你好地球'}}">
                    HELLO EARTH
                </router-link>
            </li>
        </ul>
    </template>
    
    
    <!-- HelloEarth.vue -->
    <template>
        <div class="hello">
            <h1>{{ msg }}</h1>
            <h2>Essential Links</h2>
            <h3>{{ $route.params.earthmsg }}</h3>
        </div>
    </template>
    
    <script>
        export default {
            name: 'HelloEarth',
            data () {
                return {
                    msg: 'HELLO EARTH'
                }
            }
        }
    </script>
    
    // index.js(router)
    export default new router({
      routes: [{
        name: 'helloworld',
        path: '/helloworld/:worldmsg',
        component: HelloWorld
      },{
        name: 'helloearth',
        path: '/helloearth/:earthmsg',
        component: HelloEarth
      }]
    })
    

    4. Axios —— get请求

    this.$http.get( 'url ', {params:{}})

    axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:

    • 从浏览器中创建 XMLHttpRequest
    • 从 node.js 发出 http 请求
    • 支持 Promise API
    • 拦截请求和响应
    • 转换请求和响应数据
    • 取消请求
    • 自动转换JSON数据
    • 客户端支持防止 CSRF/XSRF
    • 使用方法

      1. 安装

        npm install axios

      2. 引入加载

        import axios from 'axios'

      3. 将axios挂载到全局Vue上(不用每个文件都引入加载)

        Vue.prototype.$http = axios

        这里的http是一个变量名,换成其他的也可以,用this.http.get()函数就能发送请求,(这里this是指当前Vue实例)

      4. 发出get请求

        axios基于promise,有.then()、.catch()

        在请求链接上加参数的两种方法:

        ​ 直接在链接后面加 ?page=1&limit=10

        ​ 或者,get函数加第二个参数 {params:{ page:1;limit:10}}

        <template>
            <div>
                <button @click='getData'>点击请求数据</button>
                <ul>
                    <li v-for="item in items">{{item.title}}</li>
                </ul>
            </div>
        </template>
        
        <script>
            export default {
                name: "HelloWorld",
                data() {
                    return {
                        msg: "Welcome to Your Vue.js App",
                        items: []
                    };
                },
                methods: {
                    getData() {
                   // this.$http.get('https://cnodejs.org/api/v1/topics?page=1&limit=10')
                        this.$http
                            .get("https://cnodejs.org/api/v1/topics", {
                            params: {
                                page: 1,
                                limit: 10
                            }
                          })
                            .then(res => {
                               this.items = res.data.data;
                                   console.log(res.data.data);
                           })
                            .catch(function(err) {
                                console.log(err);
                            });
                    }
                }
            };
        </script>
        
        

    5. Axios —— post请求

    • 与get相似,把get换成post

    • POST传递数据有两种格式:

      form­data格式: ?page=1&limit=48

      x­www­form­urlencoded格式: { page: 1,limit: 10 }

    • 在axios中,post请求接收的参数必须是form­data格式,可以使用qs插件把我们写的内容转换为formdata格式

      qs插件—­qs.stringify

      npm install qs

    import qs from'qs'
    postData() {
        this.$http.post(url, qs.stringify({
            params: {
                page: 1,
                limit: 10
            }
        }))
        .then(res => {
            this.items = res.data.data;
            console.log(res.data.data);
        })
        .catch(function(err) {
            console.log(err);
        });
    }
    
    

    6.vuex的store用法

    子组件和父组件之间的通信可以通过props以及$emit来完成,非父组件之间的通信需要通过他们之间的共同父组件来完成,当文件较多时,就会很乱很麻烦,所以就用到了Vuex的store

    简而言之,vuex可以用来管理状态,共享数据,在各个组件之间管理外部状态

    应用场景:多个页面间共享的登录状态

    1. 安装vuex,引入并通过use方法使用它

      npm i vuex

      import Vuex from 'vuex'

      Vue.use(Vuex)

    2. 创建状态仓库

      //这里的Store和state是不能改的!
      var store = new Vuex.Store({
        //state 状态
        state: {
          num: 100
        }
      })
      //在入口文件中引入store,跟引入router一样
      new Vue({
        el: '#app',
        router,    
        store, //就是这一句
        components: { App },
        template: '<App/>'
      })
      
      
    1. 在任意组件中,都可以通过 this.$store.state.XXX 直接拿到共享的数据

      computed:{
          getNum:function(){
              return this.$store.state.num
          }
      }
      
      

    7. vuex的相关操作及核心用法

    vuex状态管理的流程

    view———­>actions———–>mutations—–>state————­>view

    • 方法1:在mutations选项中定义状态改变事件,在组件中通过this.$store.commit('事件名')触发转台的改变

    • 方法2:actions,用来操作mutations的,可有可无,但是actions可以进行异步操作而mutations不能,

      通过this.$store.dispatch('事件名')

      注意:actions提交的是mutation,而不是直接变更状态

      actions可以包含异步操作,但是mutation只能包含同步操作

    • 方法三:getters,我觉得这个跟计算属性有点像

      var store = new Vuex.Store({
          state: {
              num: 100
          },
          mutations:{
              addNum(state){
                  state.num ++
              },
              reduceNum(state){
                  state.num --
              }
          },
          actions:{
              //传入的参数为上下文
              ruduce(context){
                  context.commit('reduceNum')
              }
          },
          getters:{
              getCount(state){
                  return state.num > 0 ? state.num : 0
              }
          }
      })
      
      //在组件中
      this.$store.commit('addNum')
      this.$store.dispatch('ruduce')
      this.$store.getters('getCount')
      
      

    十. 过渡

    <div id="demo">
      <button v-on:click="show = !show">
        Toggle
      </button>
      <transition name="fade">
        <p v-if="show">hello</p>
      </transition>
    </div>
    new Vue({
      el: '#demo',
      data: {
        show: true
      }
    })
    .fade-enter-active, .fade-leave-active {
      transition: opacity .5s;
    }
    .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
      opacity: 0;
    }
    
    

    在进入/离开的过渡中,会有 6 个 class 切换。

    1. v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
    2. v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
    3. v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
    4. v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
    5. v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
    6. v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。

    相关文章

      网友评论

        本文标题:Vue学习笔记

        本文链接:https://www.haomeiwen.com/subject/mslefctx.html