美文网首页
Vue.js学习

Vue.js学习

作者: 蔡华鹏 | 来源:发表于2018-10-01 18:14 被阅读0次

    一、了解Vue.js

    1.1.1 Vue.js是什么?

    • 简单小巧、渐进式、功能强大的技术栈

    1.1.2 为什么学习Vue.js?

    • 学习曲线平缓、易上手、功能强大、轻便
    • 目前最流行的三大框架之一,适用范围广
    • 升职加薪 ------ 哈哈哈哈哈哈哈哈

    1.1.3 Vue.js的模式

    • MVVM模式,视图层和数据层的双向绑定,让我们无需再去关系DOM操作的事情,更过的精力放在数据和业务逻辑上去

    1.1.4 Vue.js环境搭建

    • script
    • vue脚手架工具vue-cli搭建。

    二、数据绑定,指令,事件

    2.1.1 vue实例和数据绑定

    一、

    <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    

    通过构造函数Vue就可以创建一个Vue的根实例,并启动Vue应用---入口

    var app = new Vue({
      el: '',
      data: {
      }
    })
    

    二、
    其中必不可少的一个选项就是el,el用于指定一个页面中已存在的DOM元素来挂载Vue实例

    三、
    通过Vue实例的data选项,可以声明应用内需要双向绑定的数据。建议所有会用到的数据都预先在data内声明,这样不至于将数据散落在业务逻辑中,难以维护。也可以指向一个已经有的变量

    四、
    挂载成功后,我们可以通过app.$el来访问该元素。Vue提供了很多常用的实例属性与方法,都已 $开头,比如 $el,Vue实例本身也代理了data对象里所有属性,所以可以这样访问

    五、
    如果是访问data里的属性,用app.属性名

    2.1.2

    created: 实例穿件完成后调用,此阶段完成了数据的观测等,但尚未挂载,$el还不可用。需要初始化处理一些数据时会比较有用。------还未挂载

    mounted: el挂载到实例上后调用,一般我们的第一个业务逻辑会从这里开始。------刚刚挂载

    beforeDestroy: 实例销毁之前调用。主要解绑一些使用addEventListener监听的事件等。

    2.1.3 文本插值和表达式

    语法: 使用双大括号(Mustache语法)"{{ }}"是最基本的文本插值方法,他会自动将我们双向绑定的数据实时显示出来

    用法:

    • 在{{ }}中,处了简单的绑定属性值外,还可以使用JavaScript表达式进行简单的运算、三元运算等
    • Vue.js只支持单个表达式,不支持语句和流控制

    2.2.1 过滤器

    Vue支持在{{ }}插值的尾部添加一小管道符"|"对数据进行过滤,经常用于格式化文本,比如字母全部大写、货币千位使用逗号分隔等。过滤的规则是自定义的,通过给Vue实例添加选项filters来设置
    过滤器:{{data | filter1 | filter2}}
    {{data | formatData(1,2)}}中的第一个和第二个参数,分别对应过滤器的第二个和第三个参数

    2.2.2 指令和事件

    指令( Directives )是 Vue 模板中最常用的一项功能,它带有前缀 v-,能帮我们
    快速完成DOM操作。循环渲染。显示和隐藏

    • v-­text:—————­解析文本 和{{ }} 作用一样
    • v­-html:————— 解析html
    • v­-bind—————–v­bind 的基本用途是动态更新 HTML 元素上的属性,比如 id 、class 等,本节只介绍基本章节,后面章节会更加深入详细讲述
    • v­-on——————它用来绑定事件监听器
      v­-on具体介绍
      在普通元素上, v­on 可以监听原生的 DOM 事件,除了 click 外,还有
      dblclick、 keyup, mousemove 等。表达式可以是一个方法名,这些方法都写在 Vue 实例的 methods属性内,并且是函数的形式,函数内的 this 指向的是当前 Vue 实例本身,因此可以直接使用 this.xxx 的形式来访问或修改数据vue中用 到的所有方法都定义在methods

    2.2.3 语法糖

    语法糖是指在不影响功能的情况下 , 添加某种简洁方法实现同样的效果 , 从而更加方便程
    序开发。

    • v-bind ——> : (冒号)
    • v-on ——> @

    运用以上知识点,总和一个小demo:

    <!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>demo</title>
        <style>
          .data {
              background: red;
              height: 18px;
          }
        </style>
    </head>
    <body>
        <div id="app">
            {{name}} <br>
            {{name | formatDate}}
            <br>
            <div v-html="html"></div>
            <span v-text="weather"></span>
            <br>
            <div v-bind:class="className"></div>
            <button v-on:click="click">{{countnum}}</button>
        </div>
        <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <script>
            var plusDate = function(value){
                return value < 10 ? '0' + value : value
            }
          var app = new Vue({
              el : '#app',
              data : {
                  name: new Date(),
                  html: '<div>你好</div>',
                  weather: '今天天气不错',
                  className: 'data',
                  countnum: 0
              },
              
              filters:{
                  formatDate: function(value) {
                      var date = new Date(value)
                      var year = date.getFullYear()
                      var month = plusDate(date.getMonth()+1)
                      var day = plusDate(date.getDate())
                      var hours = plusDate(date.getHours())
                      var min = plusDate(date.getMinutes())
                      var sec = plusDate(date.getSeconds())
                      return year + '--' + month + '--' + day + '  ' + hours + ':' + min + ':' + sec
                  }
              },
              mounted: function(){
                  var _this = this
                  this.timer = setInterval(function(){
                      _this.name = new Date()
                  },1000)
              },
              methods: {
                  click: function(){
                      this.countnum = this.countnum + 1 
                  }
              },
              beforeDestroy: function(){
                  clearInterval(this.timer)
              }
          })
        </script>
    </body>
    </html>
    

    三、 计算属性

    3.1 什么是计算属性

    我们己经可以搭建出一个简单的 Vue 应用,在模板中双向绑定一些数据或表达式了。但是表达式如果过长,或逻辑更为复杂时,就会变得雕肿甚至难以阅读和维护

    <div>
    {{ text.split ( ’,’ ) •reverse () . join (’,’)}}
    </div>
    
    • 这里的表达式包含 3 个操作,并不是很清晰,所以在遇到复杂的逻辑时应该使用 计算属性
    • 所有的计算属性都以函数的形式写在 Vue 实例内的computed 选项内,最终返回计算后的结果。

    3.2 计算属性用法

    • 在一个计算属性里可以完成各种复杂的逻辑,包括运算、函数调用等,只要最终返回一个结果就可以。除了上例简单的用法
    • 计算属性还可以依赖多个 Vue 实例的数据,只要其中任一数据变化,计算属性就会重新执行,视图也会更新

    getter和setter

    • 每一个计算属性都包含一个 getter 和一个 setter,我们上面的两个示例都是计算属性的默认用法 , 只是利用了 getter来读取。在你需要时,也可以提供一个 setter 函数 , 当手动修改计算属性的值就像修改一个普通数据那样时,就会触发 setter函数,执行一些自定义的操作

    • 计算属性除了上述简单的文本插值外,还经常用于动态地设置元素的样式名称 class 和内联样式 style

    小技巧: 计算属性还有两个很实用的小技巧容易被忽略:

    • 一、是计算属性可以依赖其他计算属性:
    • 二、是计算属性不仅可以依赖当前 Vue 实例的数据,还可以依赖其他实例的数据

    3.3计算属性缓存

    调用 methods 里的方法也可以与计算属性起到同样的作用

    • 页面中的方法: 如果是调用方法,只要页面重新渲染。方法就会重新执行,不需要渲染,则不需要重新执行

    • 计算属性:不管渲染不渲染,只要计算属性依赖的数据未发生变化,就永远不变

    • 结论: 没有使用计算属性,在 methods 里定义了一个方法实现了相同的效果,甚至该方法还可以接受参数,使用起来更灵活。既然使用 methods 就可以实现,那么为什么还需要计算属性呢?原因就是计算属性是基于它的依赖缓存的。 一个计算属性所依赖的数据发生变化时,它才会重新取值,所以text 只要不改变,计算属性也就不更新

    何时使用: -----------使用计算属性还是 methods 取决于你是否需要缓存,当遍历大数组和做大量计算时,应当使用计算属性,除非你不希望得到缓存。

    计算属性demo

    <!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>计算属性</title>
    </head>
    <body>
        <div id="data">
            {{fullName}} <br>
            {{watch()}}
        </div>
        <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <script>
          var app = new Vue({
              el: '#data',
              data: {
                  firstName:'Cai',
                  lastName: 'hua'
              },
              computed: {
                 fullName: function(){
                      return this.firstName + ' ' + this.lastName
                  }
              },
              methods: {
                  watch: function(){
                    return this.firstName + ' ' + this.lastName
                  }
              }
          })
        </script>
    </body>
    </html>
    

    四、 v-­bind以及class与style的绑定

    应用场景: DOM 元素经常会动态地绑定一些 class 类名或 style 样式

    4.1 了解bind指令

    v-­bind的复习:

    • 链接的 href 属性和图片的 src 属性都被动态设置了,当数据变化时,就会重新渲染。

    • 在数据绑定中,最常见的两个需求就是元素的样式名称 class 和内联样式 style 的动态绑定,它们也是 HTML的属性,因此可以使用 v­-bind 指令。

    • 我们只需要用 v­-bind计算出表达式最终的字符串就可以,不过有时候表达式的逻辑较复杂,使用字符串拼接方法较难阅读和维护,所以 Vue.js 增强了对 class 和 style 的绑定。

    4.2 绑定 class 的几种方式

    4.2.1 对象语法

    • 给 v-­bind:class 设置一个对象,可以动态地切换 class,值对应true ,false

    • 当 class 的表达式过长或逻辑复杂时,还可以绑定一个计算属性,这是一种很友好和常见的用法,一般当条件多于两个时, 都可以使用 data 或 computed

    4.2.2 数组语法

    当需要应用多个 class 时, 可以使用数组语法 , 给:class 绑定一个数组,应用一个 class列表:

    • 数组成员直接对应className--类名
    • 可以用三目运算实现,对象和数组混用

    4.2.3 在组件上使用 : 暂时不考虑—­挖坑

    4.3 绑定内联样式

    使用 v­-bind:style (即:style ) 可以给元素绑定内联样式,方法与 :class 类似,也有对象语法和数组语法,看起来很像直接在元素上写 CSS

    注意 : css 属性名称使用驼峰命名( came!Case )或短横分隔命名( kebab­case),应用多个样式对象时 , 可以使用数组语法,在实际业务 中,style 的数组语法并不常用 , 因为往往可以写在一个对象里面, 而较为常用 的应当是计算属性

    使用 :style 时, Vue .js 会自动给特殊的 css 属性名称增加前缀, 比如 transform 。

    无需再加前缀属性!!!!

    v-bind绑定demo:

    <!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>v-bind绑定</title>
        <style>
          .divStyle{
              width: 88px;
              height: 88px;
              background: red;
          }
          .borderStyle{
              border: 8px solid black;
          }
          .color{
              color: red;
          }
          .size{
              font-size: 28px;
          }
          .blueClass{
              color: blue;
          }
          .font{
              font-size: 36px;
          }
        </style>
    </head>
    <body>
        <div id="demo">
            //对象语法 <br>
            <div v-bind:class="{divStyle : isActive, borderStyle : isBorder}"></div>
            <hr>
            //数组语法<br>
            <div v-bind:class="[colorClass,sizeClass]">Hello word</div>
            <hr>
            //对象和数组混用
            <div v-bind:class="[{blueClass : isBlue},fontClass]">你好!</div>
            <hr>
            //绑定内联样式
            <div v-bind:style="{'background':background,'fontSize':fontSize + 'px'}">真好!</div>
        </div>
        <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <script>
          var app = new Vue({
              el:'#demo',
              data:{
                  isActive: true,
                  isBorder: true,
                  colorClass:"color",
                  sizeClass: "size",
                  isBlue:true,
                  fontClass:"font",
                  background: 'red',
                  fontSize:'56'
              }
          })
        </script>
    </body>
    </html>
    

    五、vueJS中的内置指令

    5.1 基本指令

    5.1.1 v-­cloak一般与display:none进行结合使用

    作用:解决初始化慢导致页面闪动的最佳实践

    5.1.2 v-­once

    定义:它的元素和组件只渲染一次

    5.2 条件渲染指令

    5.2.1 v-­if, v-­eles-­if ,v-­else

    用法: 必须跟着屁股走

    v-if的弊端 :
    Vue 在渲染元素时 ,出于效率考虑,会尽可能地复用已有的元素而非重新渲染, 因此会出现乌龙,只会渲染变化的元素,也就是说,input元素被复用了

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

    5.2.2 v-­show

    • 只改变了css属性display
    v­-if和v­-show的比较

    v-­if:

    • 实时渲染:页面显示就渲染,不显示。我就给你移除

    v-­show:

    • v-­show的元素永远存在也页面中,只是改变了css的display的属性

    5.3 列表渲染指令v­-for

    用法: 当需要将一个数组遍历或枚举一个对象属性的时候循环显示时,就会用到列表渲染指令 v­-for。

    两种使用场景:
    • 遍历多个对象
    • 遍历一个对象的多个属性

    v-for demo

    <body>
        <div id="demo">
                //遍历多个对象一定是遍历的数组
                //带索引的写法:括号的第一个变量,代表item,第二个代表index
            <ul>
                <li v-for="vuestu in vueStudy">{{vuestu.name}}</li>
            </ul>
            <br>
            //遍历一个对象的多个属性
            //拿到value,key,index的写法 v-k-i--外开
            <div v-for="(value,key,index) in women">{{index}}-----{{key}}------{{value}}</div>
        </div>
        <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <script>
          var app = new Vue({
              el:'#demo',
              data:{
                  vueStudy:[
                      //每个对象对应一个li
                      {name:'敲代码'},
                      {name:'看资料'},
                      {name:'看蔡华鹏博客'}
                  ],
                  women:{
                  grid1: '张柏芝',
                  grid2: '迪丽热巴',
                  grid3: '高圆圆'
              }
              }
          })
        </script>
    </body>
    

    5.4 数组更新,过滤与排序

    改变数组的一系列方法:

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

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

    1. 改变数组的指定项
    2. 改变数组长度

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

    解决方法:

    1. set
    2. splice

    5.5 方法和事件

    [object MouseEvent]

    5.5.1 基本用法

    v-­on绑定的事件类似于原生 的onclick等写法:

    methods:{
      handle:function (count) {
        count = count || 1;
        this.count += count;
      }
    }
    

    如果方法中带有参数,但是你没有加括号,默认传原生事件对象event

    5.5.2 修饰符

    • 在vue中传入event对象用 $event
    • 向上冒泡
      stop:阻止单击事件向上冒泡
      prevent:提交事件并且不重载页面
      self:只是作用在元素本身而非子元素的时候调用
      once: 只执行一次的方法
    可以监听键盘事件:

    <input @keyup.13 ="submitMe"> ——­指定的keyCode

    vueJS为我们提供了:

    .enter
    .tab
    .delete 等等、、、、、、
    

    六、 表单与v-­model

    6.1 基本用法

    v­-model:

    VUE提供了v­model指令, 用于在表单类元素上双向绑定事件

    input和textarea

    可以用于input框,以及textarea等

    注意: 所显示的值只依赖于所绑定的数据,不再关心初始化时的插入的value

    单选按钮:

    • 单个单选按钮,直接用v­-bind绑定一个布尔值,用v-­model是不可以的
    • 如果是组合使用,就需要v­-model来配合value使用,绑定选中的单选框的value值,此处所绑定的初始值可以随意给

    复选框:

    • 单个复选框,直接用定一个布尔值,可以用v­-model可以用v-­bind
    • 多个复选框– 如果是组合使用,就需要v­-model来配合value使用,v-model绑定一个数组—如果绑定的是字符串,则会转化为true。false,与所有绑定的复选框的checked属性相对应

    下拉框:

    • 如果是单选,所绑定的value值初始化可以为数组,也可以为字符串,有value直接优先匹配一个value值,没有value就匹配一个text值
    • 如果是多选,就需要v­-model来配合value使用,v­-model绑定一个数组,与复选框类似
    • v-­model一定是绑定在select标签上

    总结一下:
    如果是单选,初始化最好给定字符串,因为v­model此时绑定的是静态字符串或者布尔值如果是多选,初始化最好给定一个数组

    6.2 绑定值

    • 单选按钮
      只需要用v­-bind给单个单选框绑定一个value值,此时,v­-model绑定的就是他的value值

    • 复选框

    • 下拉框
      在select标签上绑定value值对option并没有影响

    6.3 修饰符

    • lazy
      v-model默认是在input输入时实时同步输入框的数据,而lazy修饰符,可以使其在失去焦点或者敲回车键之后在更新
    • number
      将输入 的字符串转化为number类型
    • trim
      trim自动过滤输入过程中收尾输入的空格

    七、 可复用性的组件详解

    7.1 使用组件的原因

    • 作用:提高代码的复用性

    7.2 组件的使用方法

    1. 全局注册
    Vue.component('my-component',{
    template:'<div>我是组件的内容</div>'
    })
    优点:所有的vue实例都可以用
    缺点:权限太大,容错率降低
    
    2. 局部注册
    var app = new Vue({
      el:'#app',
      components:{
        'my-component':{
          template: '<div>我是组件的内容</div>'
        }
      }
    })
    
    3. vue组件的模板在某些情况下会受到html标签的限制,比如 <table> 中只能还有 <tr> , <td> 这些元素,所以直接在table中使用组件是无效的,此时可以使用is属性来挂载组件
    <table>
      <tbody is="my-component"></tbody>
    </table>
    

    7.3 组件使用的奇淫技巧

    • 推荐使用小写字母加­-进行命名(必须) child, my-­componnet命名组件
    • template中的内容必须被一个DOM元素包括 ,也可以嵌套
    • 在组件的定义中,除了template之外的其他选项---data,computed,methods
    • data必须是一个方法

    7.4 使用props传递数据 父亲向儿子传递数据

    • 在组件中使用props来从父亲组件接收参数,注意,在props中定义的属性,都可以在组件中直接使用
    • props来自父级,而组件中data return的数据就是组件自己的数据,两种情况作用域就是组件本身,可以在template,computed,methods中直接使用
    • props的值有两种,一种是字符串数组,一种是对象
    • 可以使用v-­bind动态绑定父组件来的内容

    7.5 单向数据流

    • 解释 : 通过 props 传递数据 是单向的了, 也就是父组件数据变化时会传递给子组件,但是反过来不行。
    • 目的 :是尽可能将父子组件解稿,避免子组件无意中修改了父组件的状态。
    • 应用场景: 业务中会经常遇到两种需要改变 props 的情况

    一种是父组件传递初始值进来,子组件将它作为初始值保存起来,在自己的作用域下可以随意使用和修改。这种情况可以在组件 data 内再声明一个数据,引用父组件的 props
    步骤一:注册组件
    步骤二:将父组件的数据传递进来,并在子组件中用props接收
    步骤三:将传递进来的数据通过初始值保存起来

    <div id="app">
    <my-comp init-count="666"></my-comp>
    </div>
    <script>
    var app = new Vue({
      el:'#app',
      components:{
        'my-comp':{
          props:['init-count'],
          template:'<div>{{count}}</div>',
          data:function () {
            return{
            count:this.initCount
            }
          }
        }
      }
    })
    </script>
    

    另一种情况就是 prop 作为需要被转变的原始值传入。这种情况用计算属性就可以了
    步骤一:注册组件
    步骤二:将父组件的数据传递进来,并在子组件中用props接收
    步骤三:将传递进来的数据通过计算属性进行重新计算

    <body>
        <div id="data">
            <input type="text" v-model="width">
            <my-conponent :width="width"></my-conponent>
        </div>
        
        <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <script>
          var app = new Vue({
              el:'#data',
              data:{
                  width:''
              },
              components:{
                  'my-conponent':{
                    props:['width'],
                    template:'<div :style="style"></div>',
                    computed:{
                      style:function(){
                          return{
                              width:this.width+'px',
                              background:'red',
                              height:'30px'
                          }
                      }
                  }
                  }
              }
          })
        </script>
    </body>
    

    7.6 数据验证

    • @ vue组件中camelCased (驼峰式) 命名与 kebab­case(短横
      线命名)

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

    验证的 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;
        }
      }
    }
    });
    

    7.7 组件通信

    组件关系可分为父子组件通信、兄弟组件通信、跨级组件通信

    7.7.1 自定义事件—子组件给父组件传递数据

    使用v-­on 除了监昕 DOM 事件外,还可以用于组件之间的自定义事件。
    JavaScript 的设计模式 一一观察者模式, dispatchEventaddEventListener这两个方法。 Vue 组件也有与之类似的一套模式,子组件用$emit()触发事件 ,父组件用$on()监听子组件的事件
    直接来代码

    • 第一步:自定义事件
    • 第二步: 在子组件中用$emit触发事件,第一个参数是事件名,后边的参数是要传递的数据
    • 第三步:在自定义事件中用一个参数来接受
    <body>
        <div id="app">
            <p>您好,您现在的银行余额是{{total}}元</p>
            <btn-compnent @change="handleTotal"></btn-compnent>
            <!-- <button-component @change="money"></button-component> -->
        </div>
        <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <script>
            
            var app = new Vue({
                el: '#app',
                data: {
                    total: 0
                },
                components: {
                    'btn-compnent': {
                        template: '<div>\
                    <button @click="handleincrease">+10000</button> \
                    <button @click="handlereduce">-10000</button>\
                    </div>',
                        data: function () {
                            return {
                                count: 0
                            }
                        },
                        methods: {
                            handleincrease: function () {
                                this.count = this.count + 10000;
                                this.$emit('change', this.count);
                            },
                            handlereduce: function () {
                                this.count = this.count - 10000;
                                this.$emit('change', this.count);
                            }
                        }
                    }
                },
                methods: {
                    handleTotal: function (total) {
                        this.total = total;
                    }
                }
            })
        </script>
    </body>
    

    7.7.2 在组件中使用v-­model

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

    v-­model 其实是一个语法糖,这背后其实做了两个操作:

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

    要使用v-­model,要做到:

    • 接收一个 value 属性。
    • 在有新的 value 时触发 input 事件
    <body>
        <div id="app">
            <p>您好,您现在的银行余额是{{total}}元</p>
            <btn-compnent v-model="total"></btn-compnent>
        </div>
        <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <script>
            //关于
            var app = new Vue({
                el: '#app',
                data: {
                    total: 0
                },
                components: {
                    'btn-compnent': {
                        template: '<div>\
                    <button @click="handleincrease">+1</button> \
                    <button @click="handlereduce">-1</button>\
                    </div>',
                        data: function () {
                            return {
                                count: 0
                            }
                        },
                        methods: {
                            handleincrease: function () {
                                this.count++;
    ----------------------注意观察.这一行,emit的是input事件----------------
                                this.$emit('input', this.count);
                            },
                            handlereduce: function () {
                                this.count--;
                                this.$emit('input', this.count);
                            }
                        }
                    }
                },
                methods: {
                    /* handleTotal:function (total) {
                    this.total = total;
                    }*/
                }
            })
        </script>
    </body>
    

    7.7.3 非父组件之间的通信

    官网描述:

    image
        <div id="app">
            <my-acomponent></my-acomponent>
            <my-bcomponent></my-bcomponent>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js">
        </script>
        <script>
            Vue.component('my-acomponent', {
                template: '<div><button @click="handle">点击我向B组件传递数据</button></div>',
                data: function () {
                    return {
                        aaa: '我是来自A组件的内容'
                    }
                },
                methods: {
                    handle: function () {
                        this.$root.bus.$emit('lala', this.aaa);
                    }
                }
            })
            Vue.component('my-bcomponent', {
                template: '<div></div>',
                created: function () {
                    //A组件在实例创建的时候就监听事件---lala事件
                    this.$root.bus.$on('lala', function (value) {
                        alert(value)
                    });
                }
            })
        </script>
    

    父链:this.$parent

    Vue.component('child-component', {
                template: '<button @click="setFatherData">通过点击我修改父亲的数据</button>',
                methods: {
                    setFatherData: function () {
                        this.$parent.msg = '数据已经修改了'
                    }
                }
            })
    

    子链:this.$refs

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

    var app = new Vue({
                el: '#app',
                data: {
                    //bus中介
                    bus: new Vue(),
                    msg: '数据还未修改',
                    formchild: '还未拿到'
                },
                methods: {
                    getChildData: function () {
                        //用来拿子组件中的内容 ---- $refs
                        this.formchild = this.$refs.c.msg;
                    }
                }
            })
    

    7.8使用slot分发内容

    7.8.1 什么是slot(插槽)

    为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为 内容分发.Vue.js 实现了一个内容分发 API,使用特殊的 ‘slot’ 元素作为原始内容的插槽。

    7.8.2 编译的作用域

    在深入内容分发 API 之前,我们先明确内容在哪个作用域里编译。假定模板为:

    <child-component>
    {{ message }}
    </child-component>
    

    message 应该绑定到父组件的数据,还是绑定到子组件的数据?答案是父组件。组件作用域简单地说是:

    • 父组件模板的内容在父组件作用域内编译
    • 子组件模板的内容在子组件作用域内编译

    7.8.3 插槽的用法

    • 父组件的内容与子组件相混合,从而弥补了视图的不足
    • 混合父组件的内容与子组件自己的模板
      单个插槽:
    <div id="app">
            <my-component>
                <p>我是父组件的内容</p>
            </my-component>
        </div>
        Vue.component('my-component',{ template:'
        <div>\
            <slot>\ 如果父组件没有插入内容,我就作为默认出现\
            </slot>\
        </div>' })
    
    

    具名插槽:

       具名插槽:
        <name-component>
            <h3 slot="header">我是标题</h3>
            <p>我是正文内容</p>
            <p>正文内容有两段</p>
            <p slot="footer">我是底部信息</p>
        </name-component>
        Vue.component('name-component',{ template:'
        <div>\
            <div class="header">\n' + '
                <slot name="header">\n' + ' \n' + ' </slot>\n' + '
            </div>\n' + '
            <div class="contatiner">\n' + '
                <slot>\n' + ' \n' + ' </slot>\n' + '
            </div>\n' + '
            <div class="footer">\n' + '
                <slot name="footer">\n' + '\n' + ' </slot> \n' + '
            </div>'+ ' </div>' })
    

    7.8.4 作用域插槽

    作用域插槽是一种特殊的slot,使用一个可以复用的模板来替换已经渲染的元素——从子组件获取数据
    template模板是不会被渲染的

      Vue.component('my-component',{ template:'
        <div>\
            <slot text="我是来自子组件的数据" ss="fdjkfjlsd" name="abc">\
            </slot>\
        </div>' })
    

    7.8.5 访问slot

    通过this.$slots.(NAME)

    mounted:function () {
            //访问插槽
            var header = this.$slots.header;
            var text = header[0].elm.innerText;
            var html = header[0].elm.innerHTML;
            console.log(header)
            console.log(text)
            console.log(html)
            }
    

    7.9 组件高级用法–动态组件

    VUE给我们提供 了一个元素叫component

    • 作用是: 用来动态的挂载不同的组件
    • 实现:使用is特性来进行实现的

    直接甩代码:

    <body>
        <div id="data">
                <component :is ="show"></component>
                <button @click="msg('a')">第一句</button>
                <button @click="msg('b')">第二句</button>
                <button @click="msg('c')">第三句</button>
                <button @click="msg('d')">第四句</button>
        </div>
        <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
        <script>
            Vue.component('msga', {
                    template: '<div>锄禾日当午</div>',
                    data:function(){
                        return{                                           
                        }
                    }
                })
                Vue.component('msgb', {
                    template: '<div>汗滴禾下土</div>',
                    data:function(){
                        return{                                           
                        }
                    }
                })
                Vue.component('msgc', {
                    template: '<div>谁知盘中餐</div>',
                    data:function(){
                        return{                                           
                        }
                    }
                })
                Vue.component('msgd', {
                    template: '<div>粒粒坚辛苦</div>',
                    data:function(){
                        return{                                           
                        }
                    }
                })
          var app = new Vue({
              el:'#data',
              data:{
                  show:'msga'
              },
              methods:{
                  msg:function(value){
                      this.show = 'msg' + value
                  }
              }
          })
        </script>
    </body>
    

    八、 自定义指令

    自定义指令的基本用法

    和组件类似分全局注册和局部注册,区别就是把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 钩子中可用。

    自定义的指令
    <div v-cuihua:.a.b.c="obq"></div>
    

    九 、render函数

    9.1 render函数初步了解

    template下只允许有一个子节点

     <template id="hdom">
            <div>
                <h1 v-if="level==1">
                    <slot></slot>
                </h1>
                <h2 v-if="level==2">
                    <slot></slot>
                </h2>
                <h3 v-if="level==3">
                    <slot></slot>
                </h3>
            </div>
        </template>
        <script>
            //是用vue组件定义
            // Vue.component('child',{
            // props:['level'],
            // template:'#hdom'
            // })
            //使用render函数进行定义组件
            Vue.component('child', {
                render: function (createElement) {
                    return createElement('h' + this.level,
                        this.$slots.default);
                },
                props: ['level']
            })
    

    9.2 render函数的第一个参数

    在render函数的方法中,参数必须是createElement,createElement的类型是function,render函数的第一个参数可以是 String | Object | Function

    Vue.component('child', {
                // ----第一个参数必选
                //String--html标签
                //Object---一个含有数据选项的对象
                //FUnction---方法返回含有数据选项的对象
                render: function (createElement) {
                    alert(typeof createElement)
                    // return createElement('h1')
                    // return createElement({
                    // template:'<div>锄禾日当午</div>'
                    // })
                    var domFun = function () {
                        return {
                            template: '<div>锄禾日当午</div>'
                        }
                    }
                    return createElement(domFun());
                }
            });
    

    9.3 render函数的第二个参数

    Vue.component('child', {
                // ----第二个参数可选,第二个参数是数据对象----只能是Object
                render: function (createElement) {
                    return createElement({
                        template: '<div>我是龙的传人</div>'
                    }, {
                            'class': {
                                foo: true,
                                baz: false
                            },
                            style: {
                                color: 'red',
                                fontSize: '16px'
                            },
                            //正常的html特性
                            attrs: {
                                id: 'foo',
                                src: 'http://baidu.com'
                            },
                            //用来写原生的Dom属性
                            domProps: {
                                innerHTML: '<span style="color:blue;font-size: 18px">我是蓝色</span>'
                            }
                        })
                }
            });
    

    9.3 render函数的第三个参数

    第三个参数也是可选===String | Array—作为我们构建函数的子节点来使用的

    Vue.component('child', {
                // ----第三个参数是可选的,可以是 String | Array---代表子节点
                render: function (createElement) {
                    return createElement('div', [
                        createElement('h1', '我是h1标题'),
                        createElement('h6', '我是h6标题')
                    ])
                }
            });
    

    9.4 this.$slots在render函数中的应用

    第三个 参数存的就是VNODE
    createElement(‘header’,header), 返回的就是VNODE
    var header = this.$slots.header; //–这返回的内容就是含有=VNODE的数组

    Vue.component('my-component', {
                render: function (createElement) {
                    debugger
                    var header = this.$slots.header; //--这返回的内容就是含有=V
                    NODE的数组
                    var main = this.$slots.default;
                    var footer = this.$slots.footer;
                    return createElement('div', [
                        createElement('header', header),
                        createElement('main', main),
                        createElement('footer', footer)
                    ]);
                }
            })
    

    9.5 在render函数中使用props传递数据

        <div id="app">
            <button @click="switchShow">点击切换美女</button>  {{show}}
            <my-component :show="show">
    
            </my-component>
        </div>
        <script>
                Vue.component('my-component', {
                    props: ['show'],
                    render: function (createElement) {
                        var imgsrc;
                        if (this.show) {
                            imgsrc = 'img/001.jpg'
                        } else {
                            imgsrc = 'img/002.jpg'
                        }
                        return createElement('img', {
                            attrs: {
                                src: imgsrc
                            },
                            style: {
                                width: '600px',
                                height: '400px'
                            }
                        });
                    }
                })
        </script>
    

    9.6 v-­model在render函数中的使用

        <!--<my-component :name="name" @input="showName"></my-componen
    t>-->
        <my-component :name="name" v-model="name"></my-component>
        <br> {{name}}
    
        <script>
            Vue.component('my-component', {
                render: function (createElement) {
                    var self = this;//指的就是当前的VUE实例
                    return createElement('input', {
                        domProps: {
                            domProps: {
                                value: self.name
                            },
    
                            value: self.name
                        },
                        on: {
                            input: function (event) {
                                debugger
                                var a = this;
                                //此处的this指的是什么?指的就是window
                                self.$emit('input', event.target.value)
                            }
                        }
                    })
                },
                props: ['name']
            })
        </script>
    

    9.7 作用域插槽在render函数中的使用

    Vue.component('my-component', {
                    render: function (createElement) {
                        return createElement('div', this.$scopedSlots.default({
                            text: '我是子组件传递过来的数据',
                            msg: 'scopetext'
                        }))
                    }
                })
    

    9.8 函数化组件的应用

    使用context的转变

    // this.text----context.props.text
    //this.$slots.default-----context.children
    

    functional: true,表示该组件无状态无实例

    十、 使用vue-­cli脚手架一键搭建工程

    首先电脑上要安装最新版的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
    
    目录结构的分析
    ├── 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基础环境配置
    │ ├── 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// 项目说明
    

    十一、 vue-­router路由和前端状态管理

    11.1 vue­-router路由基本加载

    简单四步走

    1. 安装
    npm install --save vue-router
    
    1. 引用
    import router from 'vue-router'
    Vue.use(router)
    
    1. 配置路由文件,并在vue实例中注入
    var rt = new router({
      routes:[{
        path:'/',//指定要跳转的路径
        component:HelloWorld//指定要跳转的组件
      }]
    })
    new Vue({
      el: '#app',
      router:router,
      components: { App },
      template: '<App/>'
    })
    
    1. 确定视图加载的位置
    <router-view></router-view>
    

    11.2 vue-­router路由的跳转

    <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>
    

    11.3 vue-­router路由参数的传递

    • 必须在路由内加入路由的name
    • 必须在path后加/: +传递的参数
    1. 传递参数和接收参数看下边代码
    <router-link
      :to="{name: helloearth,params:{msg: 只有一个地球}}">
      HELLO WORLD
    </router-link>
    读取参数: $route.params.XXX
    方式:===/helloworld/你好世界
    
    
    <router-link
      :to="{path: '/helloearth',query:{msg: 只有一个地球}}">
      HELLO WORLD
    </router-link>
    方式:===/helloworld?name=XX&count=xxx
    函数模式
    你可以创建一个函数返回 props。这样你便可以将参数转换成另一种类型,将静态值与基于路由的值结合等等。
    const router = new VueRouter({
      routes: [
        { path: '/search', component: SearchUser, props: (route) => ({
          query: route.query.q }) }
      ]
    })
    

    11.4.1 Axios之get请求详解

    axios的简介:

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

    • 从浏览器中创建 XMLHttpRequest
    • 从 node.js 发出 http 请求
    • 支持 Promise API
    • 拦截请求和响应
    • 转换请求和响应数据
    • 取消请求
    • 自动转换JSON数据
    • 客户端支持防止 CSRF/XSRF
    1. 安装
    npm install axios
    
    1. 引入加载
    import axios from 'axios'
    
    1. 将axios全局挂载到VUE原型上
    Vue.prototype.$http = axios;
    
    1. 发出请求 以cnode社区API为例子
    // 为给定 ID 的 user 创建请求
    使用传统的function
    getData(){
      var self = this;
      this.$http.get('https://cnodejs.org/api/v1/topics')
      .then(function (res) {
    //此处的this指向的不是当前vue实例
        self.items = res.data.data
        console.log(res.data.data)
      })
      .catch(function (err) {
        console.log(err)
      })
    }
    // 可选地,上面的请求可以这样做
    两种传递参数的形式
    axios.get('/user', {
      params: {
        ID: 12345
      }
    })
    axios.get('/user', {
      ID: 12345
    })
    ---------------------------------
    axios.get('https://cnodejs.org/api/v1/topics?page=1&limit=15')
    

    11.4.2 Axios之post请求详解

    // 为给定 ID 的 user 创建请求
    使用传统的function
    getData(){
      var self = this;
      this.$http.post(url,{
        page:1,
        limit:10
      })
      .then(function (res) {
    //此处的this指向的不是当前vue实例
        self.items = res.data.data
        console.log(res.data.data)
      })
      .catch(function (err) {
        console.log(err)
      })
    }
    

    POST传递数据有两种格式:

    • form-­data ?page=1&limit=48
    • x­-www-­form­-urlencoded { page: 1,limit: 10 }

    在axios中,post请求接收的参数必须是form­data
    qs插件—­qs.stringify

    11.5 Vuex之store

    用来管理状态,共享数据,在各个组件之间管理外部状态如何使用?

    • 第一步:引入vuex,并通过use方法使用它
    • 第二步: 创建状态仓库
    • 第三步:通过this.$sore.state.XXX直接拿到需要的数据
    //创建状态仓库,注意Store,state不能改
    var store = new Vuex.Store({
      state:{
        XXX:xxx
      }
    })
    //直接通过this.$sore.state.XXX拿到全局状态
    

    11.6 Vuex的相关操作

    vuex状态管理的流程
    view———­>actions———–>mutations—–>state————­>view

    除了能够获取状态如何改变状态呢?

    //创建状态仓库,注意Store,state不能改
    var store = new Vuex.Store({
      state:{
        XXX:xxx
      },
      mutations:{
      }
    })
    this.$store.commit(XXX);
    // 此处的XXX是你在mucations中定义的方法名
    var store = new Vuex.Store({
      state:{
        XXX:xxx
      },
      mucations:{
        a:function(state){
        }
      },
      actions:{
        b:function(context){
          context.commit('a');
        }
      }
    })
    // 如何调用
    this.$store.dispatch(XXX);
    getters:{
    }
    this.$store.getters.getCount
    

    注意:actions提交的是mutation,而不是直接变更状态
    actions可以包含异步操作,但是mutation只能包含同步操作

    The early bird catches the worm

    相关文章

      网友评论

          本文标题:Vue.js学习

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