美文网首页
Vue整理--感谢穗儿同学

Vue整理--感谢穗儿同学

作者: 领带衬有黄金 | 来源:发表于2019-08-29 14:38 被阅读0次

    Vue

    1. Vue 定义

    官网:https://cn.vuejs.org/

    Vue (类似于 view) 是一套用于构建用户界面的渐进式框架,Vue 被设计为可以自底向上逐层应用,Vue是mvvm模式的。

    2. Vue API

    2.1 全局配置

    2.2 全局API

    2.2.1 filter 过滤器

    ​ Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示。

    <div id="app">
        <ul>
          <li
            v-for="goods in goodsList"
            :key="goods.id"
          >
            <!-- 在双花括号中 -->
            <h5>{{goods.title | toUpper}}</h5>
            <!-- 竖线之后写过滤器的名字,就会把前面值传递给过滤器,
                  过滤器处理之后再作为插值表达式来显示 -->
            <p>{{goods.price | toFix}}</p>
          </li>
        </ul>
      </div>
    
    补充:
    <!-- 在 `v-bind` 中  待理解-->
    <li v-bind:id="rawId | formatId"></li>  
    
      const app = new Vue({
          el: '#app',
          data: {
            goodsList: [
              {
                id: 1,
                title: '罗技鼠标',
                price: 9.9999999999
              }
            ]
          },
          filters: {
            // 定义一个过滤器,接收要过滤的值,返回过滤的结果
            toFix (val) {
              return val.toFixed(2)
            },
            toUpper (val) {
              return val.toUpperCase()
            }
          }
        })
    

    过滤器是 JavaScript 函数,因此可以接收参数。如:

    {{ message | filterA('arg1', arg2) }}
    
    filterA 被定义为接收三个参数的过滤器函数。其中 message 的值作为第一个参数,
    普通字符串 'arg1' 作为第二个参数,表达式 arg2 的值作为第三个参数。
    

    2.3 选项 / 数据

    2.3.1 data

    类型:Object | Function

    data => Vue实例中的数据对象,对象必须是纯粹的对象 (含有零个或多个的 key/value 对)。

    ​ 注意:data 属性使用了箭头函数,则 this 不会指向这个组件的实例,不过你仍然可以将其实例作为函数的第一个参数来访问。

    组件的data必须是一个方法。因为每个组件的数据是独立的,使用方法可以保证不共享,在data里return一个对象。复用组件时,data必须是个函数(function)

    var data = { a: 1 }
    
    // 直接创建一个实例
    var vm = new Vue({
      data: data
    })
    vm.a // => 1
    vm.$data === data 
    

    2.3.2 methods 事件处理器

    类型:{ [key: string]: Function }

    methods是用来写方法的地方,可以在其他地方调用这里的方法。methods 将被写到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this 自动绑定为 Vue 实例。

    ​ 注意:不应该使用箭头函数来定义 method 函数 (例如 plus: () => this.a++)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined。

    var vm = new Vue({
      data: { a: 1 },
      methods: {
        plus: function () {
          this.a++
        }
      }
    })
    vm.plus() // 调用方法
    vm.a // 输出 2  
    

    2.3.3 computed 计算属性

    类型:{ [key: string]: Function | { get: Function, set: Function } }

    ​ 计算属性将被写到 Vue 实例中。所有 get 和 set 的 this 上下文自动地绑定为 Vue 实例。计算属性每次的计算结果都会被缓存,除非依赖的响应式属性变化才会重新计算。注意,如果某个依赖 (比如非响应式属性) 在该实例范畴之外,则计算属性是不会被更新的。

    ​ 注意:一个计算属性如果使用了箭头函数,则 this 不会指向这个组件的实例,不过你仍然可以将其实例作为函数的第一个参数来访问。

    var vm = new Vue({
      data: { a: 1 },
      computed: {
        // 仅读取  
        aDouble: function () {
          return this.a * 2
        },
        // 读取和设置
        aPlus: {
          get: function () {
            return this.a + 1
          },
          set: function (v) {
            this.a = v - 1
          }
        }
      }
    })
    vm.aPlus   // => 2
    vm.aPlus = 3  // 设置计算结果为 3
    vm.a         // 所以输出a => 2
    vm.aDouble // => 4
    

    2.3.4 watch 侦听属性

    类型:{ [key: string]: string | Function | Object | Array }

    watch 用于监听(观察)某个属性是否发生改变,发生改变就做出相应的操作来响应这个数据变化。一个对象,键是需要观察的表达式,值是对应回调函数、方法名或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性是否发生数据变化,并做出响应。

    ​ 注意:不应该使用箭头函数来定义 watcher 函数 (例如 searchQuery: newValue => this.updateAutocomplete(newValue))。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.updateAutocomplete 将是 undefined。

    <div id="app">
        <label>姓:<input type="text" v-model="xing"></label><br>
        <label>名:<input type="text" v-model="ming"></label><br>
        <label>姓名:<input type="text" v-model="name"></label><br>
    </div>   
    
     const app = new Vue({
          el: '#app',
          data: {
            xing: '',
            ming: '',
            name:''
          },
          watch: {
            // 监听值的修改
            // 只要值发生了改变,都会执行这个方法
            xing (nVal, oVal) {
              console.log(nVal, oVal)
              // 姓发生了改变
              this.name = nVal + this.ming
            },
            ming (nVal) {
              this.name = this.xing + nVal
            },
            name (nVal) {
              this.xing = nVal.slice(0, 1)
              this.ming = nVal.slice(1)
            }
          }
        })
    

    2.3.5 props

    类型:Array<string> | Object

    ​ props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。

    基于对象的语法使用以下选项:

    • type: 校验数据类型。可以是下列原生构造函数中的一种:StringNumberBooleanArrayObjectDateFunctionSymbol、任何自定义构造函数、或上述内容组成的数组。
    • default: any prop 指定一个默认值。
    • required: Boolean定义该 prop 是否是必填项。
    • validator: Function自定义验证函数会将该 prop 的值作为唯一的参数代入。
    props: {
      title: String,
      likes: Number,
      isPublished: Boolean,
      commentIds: Array,
      author: Object,
      callback: Function,
      contactsPromise: Promise // or any other constructor
    }
    

    ​ props 使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:

    <!-- 在 html 中是 post-title 的 -->
    
    <blog-post post-title="hello!"></blog-post>
    
    Vue.component('blog-post', {
      // 在 JavaScript 中是 postTitle 的
      props: ['postTitle'],
      template: '<h3>{{ postTitle }}</h3>'
    })
    

    ​ props 是单向数据流, 所有的prop都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。所以props可用于组件传参(父 => 子)。

    2.4 特殊特性

    2.4.1 ref

    ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs对象上。如果用在子组件上,引用就指向组件实例。

    在普通的 DOM 元素上使用,引用指向的就是 DOM 元素。

    <div id="app">
        
        <input type="text" ref="add" value="hello">
    </div>
    
    new Vue ({
        el: '#app',
        data: {
            
        },
        methods: {
            // 取到input这个DOM元素
            this.$refs.add.focus()
        }
    })
    

    3. Vue的基础使用

    3.1 引入Vue

    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    
    或者保存 Vue.js 到本地,本地调用也可
    

    3.2 声明式渲染

    ​ 声明式渲染 就是利用插值表达式进行数据渲染

    Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:
    
    <div id="app">
      {{ message }}    <!-- 插值表达式 -->
    </div>
    
    var app = new Vue({
      el: '#app',
      data: {
        message: 'Hello Vue!'
      }
    })
    
    输出:Hello Vue!
    

    注意:此时数据和 DOM 已经被建立了关联,所有东西都是响应式的。如:修改 app.message 的值,输出信息也会更改。

    3.3 Vue 实现双向绑定的原理(插值表达式的原理):

    ​ Vue的双向绑定是基于defineProperty实现的。流程如下:

    注意:defineProperty是用来给一个对象定义属性的。基于defineProperty的get/set实现

    3.4 模板语法

    ​ Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML ,所以能被遵循规范的浏览器和 HTML 解析器解析。

    ​ 在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。

    3.4.1 插值表达式

    数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:
    <div id="app">
      {{ message }}   ——插值表达式
    </div>
    
    注:插值表达式里面代表是javascript表达式。所以字符要加引号
      <div id="app">
        {{isHandsome}} <br>
        {{1+1}} <br>
        {{isHandsome && 'you are right'}} <br>  
        {{1 + 1 !== 2 ? '你算对了' : '回去读小班'}} <br>
      </div>
    

    3.4.2 template标签

    template标签,HTML5提供的新标签,更加规范和语义化 ;可以把列表项放入template标签中,然后进行批量渲染

    <template id="tem">
            <div id="app">
                <h1 id="title">hello world!</h1>
            </div>
    </template>
    
    打开网页,会发现在浏览器并没有渲染出任何信息,这是因为template标签内容天生不可见,设置了display:none;属性。
    
    
    var tem =document.getElementById("tem");//获取template标签
    var title = tem.content.getElementById("title"); //在template标签内部内容,必须要用.content属性才可以访问到
    console.log(title); //找到h1
    

    template标签中的 元素是被当做一个不可见的包裹元素,主要用于分组的条件判断和列表渲染。

    3.5 Vue 指令

    ​ Vue.js的指令 (Directives) 是带有 v- 前缀的特殊特性。指令特性的值预期是单个 JavaScript 表达式 (v-for 是例外情况)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。

    3.5.1 v-text

    v-text 更新元素文本内容, 让元素的文本内容显示属性的内容。

    <div id="app">
        <!-- 插值表达式不会解析html字符串,当作普通文本在渲染 -->
        {{str}}     输出结果:<b>hello</b>
        
        <!-- 指令,指令里面是javascript 所以str要加引号-->
        <p v-text="str"></p>    输出结果:<b>hello</b>
        
        <!-- 由于v-text里面必须放javascript,所以会把内容当然属性或者方法去读取,因此下面这行代码会报错 -->
       <p v-text="你真帅"></p>   输出结果:报错
    
        <!-- 当指令和插值表达式同时存在的时候指令生效 -->
        <p v-text="'你真帅'">{{str}}</p>     输出结果:你真帅 
    </div>
    
    const app = new Vue({
          el: '#app',
          data: {
            str: '<b>hello</b>'
          }
        })
    

    3.5.2 v-html

    ​ 双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令

    <div id="app">
        <!-- v-html能解析html字符串 -->
        <p v-html="str"></p>    输出结果:加粗的 hello 
    </div>
    

    3.5.3 条件渲染 v-if(else) / v-show

    v-if(else)

    v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 true 值的时候被渲染。

    v-if 是通过是否渲染来决定显示隐藏。v-show 是一定会渲染,通过display样式来决定是否显示隐藏。

    <div id="app">
        <div v-if="false">这是一个弹框1</div>         false  不渲染显示
        <div v-if="1 + 1 === 2">这是一个弹框2</div>   true   渲染显示
    </div>
    

    ​ 也可以用 v-else 添加一个“else 块”,v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。v-else指令与v-if或者v-show同时使用,v-if条件不成立则会显示v-else内容。

    <div id="app">
            <!-- false, 渲染else;true,渲染if -->
        <div v-if="isModelShow">这是一个弹框4</div>  
            <!-- v-else只作用与上一个兄弟元素的v-if -->
        <div v-else>这事跟弹框4相反的一个显示</div>
    </div>
    
    const app = new Vue({
          el: '#app',
          data: {
            isModelShow: false
          }
        })
    

    v-show

    ​ 用于根据条件展示元素的选项是 v-show 指令。用法跟v-if大致一样:

    <div id="app">
        <div v-show="true">这是一个弹框5</div>           显示
        <div v-show="1 + 1 === 3">这是一个弹框6</div>    隐藏
    </div>
    

    注意:v-show 不支持 <template> 元素,也不支持 v-else

    v-ifv-show的区别:

    v-show不管条件是否成立,都会渲染html,而v-if只有条件成立才会渲染。

    v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性 display

    ​ 非常频繁地切换显示隐藏,则使用 v-show 较好;反之,则使用 v-if 较好。

    3.5.4 v-for 列表渲染 (循环)

    v-for 指令根据一组数组的选项列表进行渲染。v-for 指令需要使用 item in items 形式的特殊语法,items 是源数据数组并且 item 是数组元素迭代的别名。

    <ul id="example-1">
      <li v-for="item in items">
        {{ item.message }}
      </li>
    </ul>
    
    var example1 = new Vue({
      el: '#example-1',
      data: {
        items: [
          { message: 'Foo' },
          { message: 'Bar' }
        ]
      }
    })
    
    输出结果: ·Foo
             ·Bar
    
    

    v-for可以循环字符串 、数字、对象、数组等。

    v-for 也可以循环数字。在这种情况下,它将重复多次模板。

    <div id="app">
      <span v-for="n in 10">{{ n }} </span>
    </div>
    

    例:v-for循环对象,可以遍历 索引、键名、属性。

    <div id="app">
        <!-- 给每一个循环动态绑定一个唯一的key,这个key一般是一条数据的id,或者name,title之类的唯一标识     -->
        <div v-for="(value, key, index) in person" v-bind:key="obj.id">
          {{ index }}.{{ key }}: {{ value }}
        </div>
    
        <!-- 循环data数据,得到索引和元素值,循环渲染当前标签 -->
         <div v-for="(value, key) in person" :key="like.id">
              {{ key }}: {{ value }}
         </div>
    </div>
    
    new Vue({
      el: '#app',
      data: {
        person: {
              name: '小明',
              age: 20,
              gender: '男'
            }
      }
    })
    

    3.5.5 v-model 表单输入绑定

    v-model 指令用于表单 <input><textarea><select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

    v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

    • text 和 textarea 元素使用 value 属性和 input 事件;

    • checkbox 和 radio 使用 checked 属性和 change 事件;

    • select 字段将 value 作为 prop 并将 change 作为事件。

      1. input文本应用
      <!-- 输入框的v-model指令负责绑定value -->
      <!-- 双向绑定,用户在input里输入值会自动绑定到data上 -->
      <div id="app">
          <input type="text" v-model="username">
             {{username}}
      </div>
      
          const app = new Vue({
            el: '#app',
            data: {
              username: 'zhangsan'
            }
          })
      
      2.多行文本 textarea
      <span>Multiline message is:</span>
      <p style="white-space: pre-line;">{{ message }}</p>
      <br>
      <textarea v-model="message" placeholder="add multiple lines"></textarea>
      
      3.复选框 checkbox
      单个复选框,绑定到布尔值  true 选中,false 未选中
      <!-- v-model使用在checkbox上的时候代表多选框的选中状态,绑定的是checked属性 -->
      <input type="checkbox" id="checkbox" v-model="checked">
      <label for="checkbox">{{ checked }}</label>
      
      多个复选框,绑定到同一个数组:
      <!-- v-model可以使用一个数组来绑定多选按钮,选中的value值就会存在这个数组里 -->
      <div id='example-3'>
        <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
        <label for="jack">Jack</label>
        <input type="checkbox" id="john" value="John" v-model="checkedNames">
        <label for="john">John</label>
        <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
        <label for="mike">Mike</label>
        <br>
        <span>Checked names: {{ checkedNames }}</span>
      </div>
      
      
      new Vue({
        el: '#example-3',
        data: {
          checkedNames: []
        }
      })
      
      4.单选按钮 radio
      <div id="example-4">
        <input type="radio" id="one" value="One" v-model="picked">
        <label for="one">One</label>
        <br>
        <input type="radio" id="two" value="Two" v-model="picked">
        <label for="two">Two</label>
        <br>
        <span>Picked: {{ picked }}</span>
      </div>
      
      new Vue({
        el: '#example-4',
        data: {
          picked: ''
        }
      })
      
      5.下拉菜单 select
      <!-- v-model用在select上,绑定的就是选中的那个option的value -->
      <div id="example-5">
        <select v-model="selected">
          <option disabled value="">请选择</option>
          <option>A</option>
          <option>B</option>
          <option>C</option>
        </select>
        <span>Selected: {{ selected }}</span>
      </div>
      
      new Vue({
        el: '...',
        data: {
          selected: ''
        }
      })
      

    3.5.6 v-clock

    v-clock指令可以解决使用插值表达式页面闪烁问题(解决页面卡顿给用户带来不好体验)。

    方法:将该指令加在html标签中时,可以在该文件中加style属性为display:none。

    [v-cloak] {
        display: none;
      }
    
    <!--  加上v-cloak这个指令以后,在vue实例化之前div身上就会有v-cloak这个属性,实例化之后这个属性就会被移除
    -->
    <div id="app" v-cloak>
        {{msg}}
    </div>
    
     const app = new Vue({
          el: '#app',
          data: {
            msg: 'hello world'
          }
        })
    

    3.5.7 v-bind 属性绑定

    v-bind 用于动态地绑定一个或多个特性,v-bind用来绑定一个属性,属性值作为JavaScript去执行。

    可以在其名称后面带一个参数,中间放一个冒号隔开,这个参数通常是HTML元素的特性(attribute),如v-bind: class 、v-bind: src 等。 注意:class可以和v-bind:class同时存在,叠加渲染。

    1. 绑定属性 (如:href、src)

    <div id="app">
        <a v-bind:href = "baiduLink">百度一下</a>
        <!-- v-bind 简写为 : -->
        <a :href = "baiduLink">百度一下</a>  
        
        <img :src="imgUrl" alt="">
    </div>
    
    const app = new Vue({
          el: '#app',
          data: {
            baiduLink:'https://www.baidu.com/',
            imgUrl:'https://ss3.baidu.com/-rVXeDTa2gU2pMbgoY3K/it/u=1488861817,1113726833&fm=202'
    
          }
        })
    

    2. 绑定 style - Class

    .box {
        width: 200px;
        height: 200px;
        background: red;
        margin-bottom: 10px;
      }
      .ac {
        background: green;
      }
    
    <div id="app">
        <!-- 绑定class名称 -->
        <div :class="'box'"></div>
        <div :class="className"></div>
    
        <!-- 可以绑定一个对象,通过isAc的boolean来决定ac是否存在 -->
        <div :class="{ac: isAc}"></div>
        <!-- 普通class和绑定class可以共存,最后把两部分叠加渲染 -->
        <div class="box" :class="{ac: isAc}"></div>
        <!-- 这个是最复杂的用法,绑定一个数组,数组元素可以直接是class名称就能直接绑定,如果另外一个class根         据数据决定,那就再写一个对象 -->
        <div :class="[className, {ac: isAc}]"></div>
    
        <p :style="style">Lorem ipsum dolor</p>
    
    </div>
    
    const app = new Vue({
          el: '#app',
          data: {
            className: 'box',
            isAc: false,
            style: {
              width: '100px',
              height: '100px',
              color: 'red'
            }
          }
        })
    

    3.5.8 v-on 事件监听

    v-on 指令用于监听 DOM 事件,并在触发时运行一些 JavaScript 代码。例如给button添加点击事件

    <button v-on:click="show">
        <!-- v-on:click指令可以简写为@click,修改代码:-->
    <button @click="show">
    

    ​ 许多事件处理逻辑会更为复杂,所以直接把 JavaScript 代码写在 v-on 指令中是不可行的。因此 v-on 还可以接收一个需要调用的方法名称。

    <div id="app">
        <button v-on:click="onNumDecrease">decrease</button>
        {{num}}
        <button @click="onNumAdd(12, $event)">Add</button>
    </div>
    
        const app = new Vue({
          el: '#app',
          data: {
            num: 1
          },
          methods: {
            // 定义当前vue实例的方法
            onNumDecrease (e) {
              // 事件处理函数在v-on监听的时候不写括号,函数的第一个参数就是事件对象
              console.log(e)
              // this.$data.num
              this.num--
            },
            onNumAdd (n, e) {
              // 事件处理函数在v-on监听的时候写了括号,那就可以传参,而且传一个特殊变量$event就是事件对象
              console.log(n)
              console.log(e)
            }
          }
        })
    

    3.5.9 事件修饰符

    ​ 事件处理程序中经常需要处理默认事件等,为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。事件修饰符监听事件的同时就阻止默认事件等。

    ​ 常用事件修饰符有:.stop 、 .prevent 、 .capture 、.self 、.once 、.passive 。

    .stop 防止事件冒泡

    ​ 冒泡事件:嵌套两三层父子关系,然后所有都有点击事件,点击子节点,就会触发从内至外 子节点 => 父节点的点击事件。

    <!-- 阻止单击事件继续传播 阻止冒泡 -->
    <a v-on:click.stop="doThis"></a>
    

    .prevent 阻止默认事件

    .prevent等同于JavaScript的event.preventDefault(),用于取消默认事件。

     <!-- 提交事件不再重载页面 阻止默认提交-->
    <form v-on:submit.prevent="onSubmit"></form>
    
     <!-- 点击右键不再出现菜单 阻止右键菜单-->
    <p @contextmenu.prevent="onCM">Lorem ipsum dolor</p>
    

    .capture 捕获事件

    捕获事件:嵌套两三层父子关系,然后所有都有点击事件,点击子节点,就会触发从外至内 父节点 => 子节点的点击事件

    <!-- 添加事件监听器时使用事件捕获模式 -->
    <!-- 即元素自身触发的事件先在此处理,然后才交由内部元素进行处理 -->
    <div v-on:click.capture="doThis">...</div>
    

    .self 触发事件

    .self只会触发自己范围内的事件,不会包含子元素。

    <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
    <!-- 即事件不是从内部元素触发的 -->
    <div v-on:click.self="doThat">...</div>
    
    注意:
    使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,
    用 v-on:click.prevent.self 会阻止所有的点击,
    而 v-on:click.self.prevent 只会阻止对元素自身的点击。
    

    .once 只执行一次点击

    如果我们在@click事件上添加.once修饰符,只要点击按钮只会执行一次。

    <!-- 点击事件将只会触发一次 -->
    <a v-on:click.once="doThis"></a>
    

    .passive 新增

    <!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
    <!-- 而不会等待 `onScroll` 完成  -->
    <!-- 这其中包含 `event.preventDefault()` 的情况 -->
    <div v-on:scroll.passive="onScroll">...</div>
    

    这个 .passive 修饰符能够提升移动端的性能。

    注意:不要把 .passive.prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive 会告诉浏览器你不想阻止事件的默认行为。

    3.5.10 v-on:keyup 按键修饰符

    在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符。可以使用按键名,也可使用按键码。

    常用按键名:enter 、tab 、delete 、esc 、space 、left 、up 、right 、down

    常用按键码:13(enter ) 、 37-40(左上右下)

    <!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
    <!-- 按下 enter,提交表单 -->
    <input @keyup.enter="submit">
    <!-- 按下 enter,提交表单 -->
    <input v-on:keyup.13="submit">
    

    4. Vue 组件

    4.1 组件概念

    ​ 组件是可复用的 Vue 实例,且带有一个名字。我们可以在一个通过 new Vue 创建的 Vue 根实例(父组件)中,把这个组件作为自定义元素来使用。

    data 方法

    一个组件的 data 选项必须是一个函数,函数体内 return一个对象。因为组件里的数据是独立的,使用方法可以保证不共享,其他地方不能调用这个data的数据。

    data () {
        return {
            
        }
    }
    

    4.2 组件注册

    为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册局部注册

    4.2.1 全局注册

    ​ 用 Vue.component 来创建的组件,叫做全局组件,全局组件可以在全局内使用。全局组件可以用在任何新创建的 Vue 根实例 (new Vue) 的模板(包括组件树中的所有子组件的模板)中。

    创建方法:

    // Vue.component 的第一个参数是组件名,第二个参数是一个对象
    Vue.component('my-component-name', {
       // ... 选项 ...
    })
    
    // 组件名可以驼峰命名,也可以中线连接(在HTML中使用组件时驼峰命名需变为 my-component-name)
    Vue.component('MyComponentName', { /* ... */ })
    

    范例:

    <div id="app">
        <hello-world></hello-world>
    </div>
    
    <script>
    // 注册全局组件
    Vue.component('HelloWorld', {
        template: '<div>{{msg}}</div>',
        // 组件的data必须是一个方法,因为每个组件的数据是独立的,使用方法可以保证不共享,return一个对象
        data () {
            return {
                msg: 'hello'
            }
        }
    })
    
    const app = new Vue({
        el: '#app',
        data: {
            msg1: 'hello'
        }
    })
    </script>
    

    4.2.2 局部注册

    ​ 局部注册组件就只能在当前实例里面使用,局部注册的组件在其他子组件中不可用。

    创建方法:

    // 局部注册组件
    var ComponentA = { /* ... */ }
    
    var ComponentB = {
      components: {
          // 局部注册的组件在其他子组件中不可用
        'component-a': ComponentA
      },
      // ...
    }
    
    // new 一个Vue实例
    new Vue({
      el: '#app',
      components: {
          // 在父组件中使用子组件 A B
        'component-a': ComponentA,
        'component-b': ComponentB
      }
    })
    

    范例:

    <div id="app">
        <!-- 这里打印出 hello world -->
        <hello-world></hello-world>
        <!-- 下面这个地方不能解析,因为这个组件是app1局部的 -->
        <hello-vue></hello-vue>
    </div>
    <div id="app1">
        <!-- 这里打印出 hello world -->
        <hello-world></hello-world>
        <!-- 这里打印出 hello vue -->
        <hello-vue></hello-vue>
    </div>
    
    <script>
        Vue.component('HelloWorld', {
          template: '<div>hello world</div>'
        })
        // 定义一个组件
        const HelloVue = {
          template: '<h2>hello Vue</h2>'
        }
        const app = new Vue({
          el: '#app',
          data: {
            
          }
        })
        const app1 = new Vue({
          el: '#app1',
          components: {
            // 这里用到解构赋值
            HelloVue
          }
        })
    </script>
    

    注意:注册的组件大驼峰命名,在html里面使用这个组件的时候需要把大写变为小写,然后使用中线连接

    ​ 每个template里面一般都有一个div进行外层包裹

    4.3 组件传递数据

    4.3.1 通过 Prop 向子组件传递数据(父 => 子)

    props

    ​ 处理数据传输,使用这个组件的时候把父组件定义的msg传递给组件内部,在组件内部通过props来接收, 组件内部的props可以直接作为data使用

    当以绑定的方式传递,这个时候会把app实例中的data的数据传递过去。

    注意:每个子组件都必须在父组件里进行注册

    示例:

    <div id="app">
        <!-- 打印出 hello component -->
        <hello-world msg="hello component"></hello-world>
        <!-- 打印出 hello -->
        <hello-world :msg="msg1"></hello-world>
    </div>
    
    <script>
        const HelloWorld = {
          template: '<div>{{msg}}</div>',
          props: ['msg']
        }
        const app = new Vue({
          el: '#app',
          data: {
            msg1: 'hello'
          },
          components: {
            HelloWorld
          }
        })
      </script>
    

    如果要传递数字boolean需要绑定,否则传递过去后会解析成字符串。​

    props配置属性时,可以校验数据类型,是否必须传 required: true;或者default:0 默认值。

    示例:

        <!-- 传递数字或者boolean需要绑定,否则传递过去以后解析成字符串 -->
        <hello-world msg="hello component" :num="3"></hello-world>
    
        <!-- props中配置属性 -->
          props: {
            msg: {
              type: String,
              required: true // 这里代表必传
            },
            num: {
              type: Number,
              default: 0 // 这里代表不传时,默认为0
            },
            isCompleted: Boolean
          }
        }
    

    props绑定驼峰方式要改写成中线;html属性名用中线连接js使用驼峰

    示例:

    <div id="app">
        <!-- html属性名用中线 -->
        <hello-world :user-name="userName"></hello-world>
      </div>
    
      <script>
        const HelloWorld = {
          template: '<div>{{userName}}</div>',
          // 这里的javascript使用驼峰
          props: ['userName']
        }
        const app = new Vue({
          el: '#app',
          data: {
            userName: 'xiaoming'
          },
          components: {
            HelloWorld
          }
        })
      </script>
    

    4.3.2 通过$emit 向父组件传递数据(子 => 父)

    $emit

    emit 监听子组件事件

    ​ 由于props单向的数据流,只能单向响应父组件向子组件的数据传递。不能响应子组件向父组件的数据传递。

    ​ 所以如果需要子组件向父组件进行数据响应,就得使用$emit这个自定义属性,利用这个自定义属性发出一个emit事件,事件命名要用中线连接而不用驼峰。

    然后在父组件中监听子组件的自定义事件,当子组件emit这个事件的时候,父组件的这个方法就会响应执行;

    父组件中能响应子组件对数据的修改,并且函数方法的第一个参数就是自定义事件传递过来的参数。

    注意:子组件的props一般不允许修改。

    示例:

    <div id="app">
                            <!-- 监听 num-add 这个事件 父组件响应事件的方法onParentAddNum-->
        <hello-world :num="num" @num-add="onParentAddNum"></hello-world>
        {{num}}
    </div>
    
    <script>
        const HelloWorld = {
          template: '<div>{{num}}<button @click="onAddNum">Add</button></div>',
          props: ['num'],
          methods: {
            onAddNum () {
                // 自定义emit事件 事件名 num-add
              this.$emit('num-add', {
                num: this.num + 1
              })
            }
          } 
        }
        const app = new Vue({
          el: '#app',
          data: {
            num: 1
          },
          methods: {
              // 监听事件 响应方法
            onParentAddNum (data) {
              this.num = data.num
            }
          },
          components: {
            HelloWorld
          }
        })
    </script>
    

    4.3.3 通过 bus 向兄弟组件传递数据(兄 => 弟)

    event bus 事件总线

    事件总线就是利用空的Vue实例来进行两个兄弟组件之间的数据传输

    方法

    1. 创建一个空的Vue实例 const bus = new Vue();

    2. 在第一个兄弟组件中使用bus触发一个emit自定义事件 bus.$emit;

    3. 在第二个兄弟组件中使用$bus.on进行监听(这个方法写在created(){}中);

      解释:created() 这里的代码是Vue实例创建之后执行的

    4. 在点击的时候就会触发这个事件,第二个兄弟组件就能响应这个事件;

    5. 第二个兄弟组件一上来就需要监听事件总线的事件,响应第一个兄弟组件里通过bus给它的emit的这个事件,就可以接收到传递给它的参数data

    示例:

    <div id="app">
        <ge></ge>
        <di></di>
    </div>
    
    <script>
        const bus = new Vue()
        const ge = {
          template: '<div><span @click="onDawodi">打我弟</span></div>',
          methods: {
            onDawodi () {
                // 
              bus.$emit('wuwuwu', {
                kusheng: 'yinyinyin'
              })
            }
          }
        }
        const di = {
          template: '<div><span>{{ku}}</span></div>',
          data () {
            return {
              ku: ''
            }
          },
          created () {
               // 初始化 就监听 bus 事件总线
              // 触发 bus.$emit 的点击事件 onDawodi,马上响应 wuwuwu 这个自定义事件
             // 接收传递过来的data,把data的数据赋给当前data方法中的对象
            // 数据传输成功
            bus.$on('wuwuwu', (data) => {
              this.ku = data.kusheng
            })
          }
        }
        const app = new Vue({
          el: '#app',
          components: {
            ge,
            di
          }
        })
    </script>
    

    4.4 template 标签

    ​ 可以在html中写一个template标签,并给这个标签起一个id,在创建组件的时候使用template关联这个id;在这个标签里就放DOM元素。

    在DOM元素div(id = "app")标签中写入组件标签,在组件的标签中对父组件的数据进行绑定。

    示例:

    <!-- html 'app' 中使用组件 product -->
    <div id="app">
        <product
          :price="price"
          :title="title"
          :src="src"
        ></product>
    </div>
    
    <!-- 创建组件 product 的template -->
    <template id="product">
        <div>
          <div class="img">
            <img :src="src" alt="">
          </div>
          <p>{{title}}</p>
          <p>¥<span>{{price}}</span></p>
        </div>
    </template>
    
    <script>
        // 定义一个子组件Product
        const Product = {
          template: '#product',
          props: {
            src: String,
            title: String,
            price: Number
          }
        }
        // Vue实例
        const app = new Vue({
          el: '#app',
          data: {
            title: '这是最贵的小姐姐',
            price: 99,
            src: 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2151614847,425289411&fm=111&gp=0.jpg'
          },
            // 在实例中使用子组件 Product
          components: {
            Product
          }
        })
    </script>
    

    4.5 动态组件

    动态组件就是在不同组件之间进行动态切换,这在实际项目中是常见的。

    实现方法

    可以通过 Vue 的 <component> 元素加一个特殊的 is 特性来实现,这个is特性可以绑定父组件中data数据,然后通过点击时改变这个数据来达到动态切换

    示例:

     <template id="guonei">
        <div>华为手机要升级了</div>
      </template>
    
      <template id="guoji">
        <div>apple 倒闭了</div>
      </template>
    
      <div id="app">
        <div>
          <span @click="news = 'guonei'">国内新闻</span>
          <span @click="news = 'guoji'">国际新闻</span>
        </div>
        <!-- 这里直接使用component标签和它的is特性 -->
        <component :is="news"></component>
      </div>
    
      <script>
        const guonei= {
          template: '#guonei'
        }
        const guoji= {
          template: '#guoji'
        }
        const app = new Vue({
          el: '#app',
          data: {
            news: 'guoji'
          },
          components: {
            guonei,
            guoji
          }
        })
      </script>
    

    4.6 slot 插槽

    slot(插槽)放在template标签中占位置,在使用组件的时候,去决定是否需要某个DOM元素,需要的话就写在组件内部(如下图<hello>标签),在template标签里面的slot标签就会被这个dom元素自动替换。

    当写多个slot时,需要写上name属性,使用时添加属性 slot="slot标签的name值"就可以对应起来了。

    示例:

    <template id="hello">
        <div>
          <slot name="a"></slot>
          商品名称
          <slot name="b"></slot>
        </div>
    </template>
    
    <div id="app">
        <hello>
            <!-- slot 的值一一对应 slot标签的name值 -->
            <b slot="b">包邮</b>
            <b slot="a">打九折</b>
        </hello>
    </div>
    
    <script>
        const Hello = {
            template: '#hello'
        }
        const app = new Vue({
            el: '#app',
            components: {
                Hello
            }
        })
    </script>
    

    4.7 过渡 & 动画

    transtion

    4.7.1 概述

    Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。

    包括以下工具:

    • 在 CSS 过渡和动画中自动应用 class
    • 可以配合使用第三方 CSS 动画库,如 Animate.css
    • 在过渡钩子函数中使用 JavaScript 直接操作 DOM
    • 可以配合使用第三方 JavaScript 动画库,如 Velocity.js

    4.7.2 方法

    4.7.2.3 animate.css 动画库

    参考网站:https://daneden.github.io/animate.css/?

    这个是常用的外部工具,里面有很多动画效果,简单易用。使用时只需将文件引入,然后结合自定义过渡类名将属性名改为此工具中对应的属性名,就可以达到相应的动画效果了。

    4.7.2.4 过渡模式

    当同时生效的进入和离开的过渡不能满足所有要求,这时 Vue 提供了 过渡模式

    • in-out:新元素先进行过渡,完成之后当前元素过渡离开。
    • out-in:当前元素先进行过渡,完成之后新元素过渡进入。
    4.7.2.5 列表过渡

    transition过渡只能作用于一个元素;多个元素需要过渡时(列表过渡),需要使用 transition-group 组件,其他的和一般过渡一致。

    4.8 Vue 生命周期(lifecycle )

    ​ 所有的生命周期钩子自动绑定 this 上下文到实例中,因此可以直接访问数据,对属性和方法进行运算。

    注意不能使用箭头函数来定义一个生命周期方法 (例如 created: () => this.fetchTodos())。

    图示:[图片上传失败...(image-ebc822-1566829451674)]

    生命周期总体来说有四段

    1. create创建vue实例

      ​ beforecreate:创建之前

      ​ created:创建之后

    2. mount 将挂载

      mount 解析实例中的数据,通过插值表达式把数据渲染到DOM元素上(挂载到DOM元素上)。

      ​ beforemount:挂载之前

      ​ mounted:挂载之后

    3. update更新

      在updated处,根据虚拟DOM更新真实DOM(做数据更新)

      ​ beforeupdate:创建之前

      ​ updated:创建之后

    4. destroy销毁

      ​ beforedestroy:创建之前

      ​ destroyed:创建之后

    注意ajax 数据请求一般在 created或者 beforemount去发送。

    4.9 虚拟DOM

    ​ 基于真实dom,构建的一个虚拟的dom,数据操作时是对虚拟dom进行操作。它有一个脏检查,用来检查旧的数据和新的数据有什么区别,然后对旧的数据进行更新。

    原理

    1. 根据真实DOM构建一个虚拟DOM(js对象)。

    2. 当真实DOM要修改的时候;会先修改虚拟DOM;然后用修改之后的虚拟DOM跟真实的DOM进行脏检查(比对)。

    3. 把修改过后的那一部分重新渲染到真实DOM上。

      注意:脏检查运用的算法 — diff算法

    好处:虚拟DOM可以避免多次的DOM操作,提高性能。(频繁请求DOM影响性能)

    查询 super() 用法

    5. router 路由

    网址 :https://router.vuejs.org/zh/installation.html

    5.1 使用router的步骤

    1. 写一个 router.js 文件 引入需要配置的组件,再使用router ;

    ​ 得到一个router的实例,并导出 ;通过routers字段配置路由;

    ​ 跳转的路由路径,给组件起个名字,对应的组件

    // 定义路由,导出路由
    // 1. 引入核心模块(包)
    import Vue from 'vue'
    import Router from 'vue-router'
    
    // 2. 引入需要配置的组件
    import Home from './views/Home.vue'
    import About from './views/about.vue'
    
    // 3. 使用 router (类似于中间件)
    Vue.use(Router)
    // 4. new 一个router实例,并导出
    export default new Router({
    // 5. 通过routes字段配置路由
      routes: [
        {
          path: '/',       // 跳转的路由路径
          name: 'home',    // 给组件取个名字
          component: Home  // 这个路由对应的组件
        },
        {
          path: '/about',
          name: 'about',
          component: About
        }
      ]
    })
    
    

    2. main.js 引入router.js

    ​ 实例化vue的时候把router配置进来,我们#app这个实例中就可以使用配置好的router了。

    import Vue from 'vue'
    import App from './App.vue'
    // 引入了 router.js
    import router from './router'
    
    Vue.config.productionTip = false
    
    new Vue({
        // 实例化Vue 的时候吧router配置进来,我们#app这个实例里就能使用配置好的 router了
      router,
      render: h => h(App)
    }).$mount('#app')
    

    3. App.vue

    ​ <router-link to="组件名"/>会渲染成a标签,to就相当于href,就是要跳转的那个组件的path

    ​ <router-view/>必须的,组件跳转的显示位置,即点击home这儿就显示home组件

    <template>
      <div id="app">
        <div id="nav">
            <!-- router-link默认会渲染成 a标签,to 相当于 href,就是要跳转的那个组件的path -->
          <router-link to="/">Home</router-link> |
          <router-link to="/about">About</router-link>
        </div>
          <!-- router-view 必须写的!组件跳转的显示位置 作用:显示跳转组件的位置-->
           <!-- 点击home这儿就显示home组件。即点击谁就显示相对应的组件 -->
        <router-view/>
      </div>
    </template>
    

    嵌套路由

    ​ 在router.vue文件中配置路由时,当一个组件中还有其他组件视图,就需要进行路由嵌套。在当前配置路由的地方加上children属性,在其中配置子路由。

    5.2 router 组件跳转

    一级路由

    组件之间需要跳转时,就要用到路由来进行解决(利用路由进行跳转)。

    二级路由

    => 动态路由 + 传参 ,实现子组件跳转

    路由嵌套,

    传参方式: 传参方式: 1. to="/list/man" 这是通过path进行路由传参。只能传一个参数

    ​ 传参方式: 2. :to="{ name: 'category', params: {cateName: 'woman'}}" 这是通过绑定 to 后,给这个对象传组件名称,通过组件名来跳转,params 也是个对象,可以实现传多个参数。start这个参数未在路由内配置,但是能够被接收,这个叫做隐式传参。

    ​ 3. :to="{ name: 'Category', params: {cateName: 'kid', start: 0}, query: { end: 200 }} query传参,通过 ? 连接参数,显示在url上。

    跳转方式: router-link + to ,声明式

    ​ router.push({ path: '/' } }) 在js中编写, 编程式 (如:返回首页)

    router-view 命名视图

    重定向

    点击该路由,跳转到其他页面(非该路由对应页)去。

    const router = new VueRouter({
      routes: [
        { path: '/a', redirect: '/b' }
      ]
    })
    

    重定向也可以是一个命名路由

    const router = new VueRouter({
      routes: [
        { path: '/a', redirect: { name: 'foo' }}
      ]
    })
    

    也可以是一个方法,动态返回重定向目标

    const router = new VueRouter({
      routes: [
        { path: '/a', redirect: to => {
          // 方法接收 目标路由 作为参数
          // return 重定向的 字符串路径/路径对象
        }}
      ]
    })
    

    5.3 导航守卫

    5.3.1 全局配置导航守卫

    ​ 在每一次导航发生改变(路由跳转)之前,都会进入这个钩子函数,在这个函数里只有调用了 next 才会跳转。一般用于全局的权限验证。

    // router.beforeEach
    // 注册一个全局导航守卫
    const router = new VueRouter({ ... })
    router.beforeEach((to, from, next)=> {
        在进入 to 之前进行登录(权限)验证
        if(to.){
           
           } else {
            
        }
        
    })
    
    // router.afterEach
    // 注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身
    router.afterEach(()=> {
        if(){
           
           } else {
            
        }
        
    })
    

    ()中有三个参数,分别是:to from next

    解释: from表示当前路由路径

    ​ to表示即将跳转至的路由路劲

    ​ next()需要跳转时,必须调用

    注意beforeEach指路由跳转之前,这时this指向undifend

    ​ 在每一次导航发生之前都会进入这个钩子函数,在这个函数里只有调用了next才会跳转,一般用于全局 的权限验证(比如登录)。判断当前要跳转的那个组件是否需要权限;再验证是否已登录,没有登录就中断当前导航,进入新的导航;不需要权限验证就直接进入当前导航。

    补充:

    to和from是将要进入和将要离开的路由对象,路由对象指的是平时通过this.$route获取到的路由对象。

    next:Function 这个参数是个函数,且必须调用,否则不能进入路由(页面空白)。

    • next() 进入该路由。

    • next(false): 取消进入路由,url地址重置为from路由地址(也就是将要离开的路由地址)。

    • next 跳转新路由,当前的导航被中断,重新开始一个新的导航。

      我们可以这样跳转:next('path地址')或者next({path:''})或者next({name:''})
      且允许设置诸如 replace: true、name: 'home' 之类的选项
      以及你用在router-link或router.push的对象选项。

    5.3.2 路由独享导航守卫

    beforeEnter()

    参数:to from next (同上)

    // 路由配置上直接定义 beforeEnter 守卫
    const router = new VueRouter({
      routes: [
        {
          path: '/foo',
          component: Foo,
          beforeEnter: (to, from, next) => {
            // ...
          }
        }
      ]
    })
    

    5.3.3 组件内的守卫

    ​ 路由组件内直接定义以下路由导航守卫:

    • beforeRouteEnter
    • beforeRouteUpdate (2.2 新增)
    • beforeRouteLeave

    beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。

    在下列组件外层套一个组件。因为这个是组件内的守卫。

    <!-- 进入之前 -->
    <!-- 第一次进入使用 beforeRouteEnter 只是在进入时调用一次  -->
    beforeRouteEnter (to, from, next){
        // 在渲染该组件的对应路由被 confirm 前调用
        // 不能获取组件实例 this
        // 因为守卫执行前,组件实例还没有被创建
        
        // 在next 里可以传递一个回调函数,这个回调函数的第一个形参就是this,即VM = this
        next(vm => {
            
        })
    }
    
    <!-- 修改更新 之后每次修改更新都用 beforeRouteUpdate -->
    beforeRouteUpdate (to, from, next){
        // 在当前路由改变,但是该组件被复用时调用
        // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
        // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
        // 可以访问组件实例 `this`
    }
    
      beforeRouteLeave (to, from, next) {
        // 导航离开该组件的对应路由时调用
        // 可以访问组件实例 `this`
      }
    }
    

    5.4 路由懒加载

    ​ 路由懒加载 => 能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,更加高效。

    问题:当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。

    解决方法:

    ​ 结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载。

    1.通过注释语法,可以把添加相同注释语法的组件打包到一个js 文件里。

    7. Vuex

    网址:https://vuex.vuejs.org/zh/

    ​ Vuex 的状态存储是响应式的。Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态。全局状态管理Vuex.Store是一个单例

    状态自管理应用包含以下几个部分:

    • state,驱动应用的数据源;
    • view,以声明方式将 state 映射到视图;
    • actions,响应在 view 上的用户输入导致的状态变化。

    “单向数据流”理念的简单示意:

    img

    多个组件共享状态时,单向数据流的简洁性很容易被破坏:

    • 多个视图依赖于同一状态。
    • 来自不同视图的行为需要变更同一状态。

    7.1 vuex使用

    7.1.1 安装

    npm install vuex --save
    
    // 引入
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    

    7.1.2 创建 store

    安装 Vuex 之后,让我们来创建一个 store。创建过程直截了当——仅需要提供一个初始 state 对象和一些 mutation

    // 模块化环境中
    Vue.use(Vuex)
    
    const store = new Vuex.Store({
      state: {
        count: 0
      },
      mutations: {
        increment (state) {
          state.count++
        }
      }
    })
    

    新建一个store目录---创建index.js---编写内容state、getters、actions、mutations、modules

    提交一个mutation,这个mutation在store的实例中定义的 state只能在mutation中mutate

    只能传一个参数,可以传对象或数组。

    通过 store.state 来获取状态对象,以及通过 store.commit 方法触发状态变更:

    store.commit('increment')
    

    7.2 核心概念

    • state 数据源

    • mutation 修改数据,提交mutation修改

    • getter state 中派生出一些状态,相当于 store 的计算属性,根据state计算

    • action 类似mutation,mutation中只能写同步;action可以包含任意异步操作,action提交的是mutation,而不是直接变更状态

      参数:context,可以理解为store,通过commit提交mutation context.commit('方法')

      如果需要通过异步去修稿state,那么就需要在action中写异步代码,异步返回的时候再提交mutation,进行数据处理 。

    mapState 返回一个对象,可以将其映射到computed中
    
    ...mapState([‘count’])
    
    ...mapMutations(['count'])
    
    
    

    7.3 规则

    Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:

    1. 应用层级的状态应该集中到单个 store 对象中。
    2. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
    3. 异步逻辑都应该封装到 action 里面。

    8. 生命周期 !!!

    8.1 Vue的生命周期

    • create 创建

    • mount 挂载

    • update 更新

    • destroy 销毁

      在前面加上 before ,表示在 * *之前; 过去时态,表示在 * * 之后

    8.2 导航守卫的生命周期

    全局守卫:

    1. router.beforeEach 全局前置守卫 进入路由之前
    2. router.beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用
    3. router.afterEach 全局后置钩子 进入路由之后

    路由组件内的守卫:

    1. beforeRouteEnter 进入路由前
    2. beforeRouteUpdate (2.2) 路由复用同一个组件时
    3. beforeRouteLeave 离开当前路由时

    8.3 keep-alive 生命周期

    Vue提供了一个内置组件keep-alive缓存组件内部状态,避免重新渲染文档网址

    <keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。

    keep-alive大多数使用场景就是这种。

        <keep-alive>
          <component :is="view"></component>
        </keep-alive>
        
       // 或者 
        <keep-alive>
            <router-view></router-view>
        </keeo-alive>
    

    生命周期:

    在被keep-alive包含的组件/路由中,会在原有的Vue生命周期前提下,多出两个生命周期的钩子:activateddeactivated

    • activated在组件第一次渲染时会被调用,之后在每次缓存组件被激活时调用
    • deactivated:组件被停用(离开路由)时调用

    使用了keep-alive就不会调用 beforeDestroy (组件销毁前钩子)和destroyed(组件销毁),因为组件没被销毁,被缓存起来了。

    这个钩子可以看作beforeDestroy的替代。

    MVVM

    1 mvvm模式

    ​ MVVM是Model-View-ViewModel的简写,即模型-视图-视图模型。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI业务逻辑分开。这些事是 ViewModel自动处理的,viewmodel 可以在取出 Model 的数据同时帮忙处理 View 中需要涉及的业务逻辑。

    ​ 它有两个方向:一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。

    ​ 二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定

    2 MVVM模式的组成部分

    • 模型 (model)

      【模型】指的是后端传递的数据。模型 是指代表真实状态内容的领域模型(面向对象),或指代表内容的数据访问层(以数据为中心)。

    • 视图 (view)

      【视图】指的是所看到的页面。就像在MVCMVP模式中一样,视图是用户在屏幕上看到的结构布局外观(UI)

    • 视图模型 (viewModel)

      【视图模型】mvvm模式的核心,主要处理业务逻辑和获取数据,它是连接view和model的桥梁。视图模型 是暴露公共属性和命令的视图的抽象。MVVM没有MVC模式的控制器,也没有MVP模式的presenter,有的是一个绑定器。在视图模型中,绑定器在视图和数据绑定器之间进行通信

    • 绑定器

      声明性数据和命令绑定隐含在MVVM模式中。在Microsoft解决方案堆中,绑定器是一种名为XAML标记语言。绑定器使开发人员免于被迫编写样板式逻辑来同步视图模型和视图。在微软的堆之外实现时,声明性数据绑定技术的出现是实现该模式的一个关键因素。

    http://cn.vuejs.org/images/mvvm.png
    ViewModel是Vue.js的核心,它是一个Vue实例。Vue和React都是MVVM模式的框架。

    3 MVVM优点

    MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大优点:

    1. 低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。

    2. 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。

    3. 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xaml代码。

    4. 可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。

    4 MVVM模式的框架

    • Vue
    • React

    5 MVC与MVVM区别

    1. MVVM是MVC是改进版,MVVM中ViewModel存在目的在于抽离Controller中展示的业务逻辑,而不是替代Controller。MVVM实现的是业务逻辑组件的重用。
    2. 使用MVC的目的就是将M和V的代码分离。‘MVC是单向通信。也就是View跟Model,必须通过Controller来承上启下。

    相关文章

      网友评论

          本文标题:Vue整理--感谢穗儿同学

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