• ④ vue


    目录

    1 MongoDB在NodeJS中操作

    • 驱动:mongodb mongoose

    1.1 document的操作

    1.1.1 增

    • insertOne(Object)

    • insertMany(Array)

    1.1.2 删

    • deleteOne(query)

    • deleteMany(query)

    1.1.3 改

    • updateOne(query,{$set:data})

    • updateMany(query,{$set:data})

    • save(document)

    1.1.4 查

    • find(query)

    • findOne(query)

    1.1.5 条件与筛选

    1.2 封装(重点)

    • async & await

    2 了解VUE

    • Vue.js 是一个基于 MVVM 模式的一套渐进式框架。它是以数据驱动和组件化的思想构建的,采用自底向上增量开发的设计。

    2.1 前端框架发展史

    1. Jquery(2006):节点操作简单易用,浏览器兼容

    2. Angular(2009):MVC模式,双向数据绑定,依赖注入

    3. React(2013):高性能(虚拟DOM)

    4. Vue(2014):综合angular与react的优点,MVVM模式,是一款高性能高效率的框架

    2.2 架构模式

    复杂的软件必须有清晰合理的架构,更容易开发、维护和测试

    2.2.1 MVC

    MVC 模式的意思是,软件可以分成三个部分。

    • 模型Model:数据处理

    • 视图View:数据展示

    • 控制器Controller:业务逻辑处理(M和V之间的连接器)

    MVC

    1. View 传送指令到 Controller(用户发送指令)

    2. Controller 完成业务逻辑后,要求 Model 改变状态

    3. Model 将新的数据发送到 View,用户得到反馈

    • 缺点:依赖复杂
      • View 依赖 Controller 和 Model
      • Controller 依赖 View 和 Model

    2.2.2 MVP

    MVP 架构模式是 MVC 的改良模式(改进Controller, 把Model和View完全隔离开)

    • Model

    • View

    • Presenter 可以理解为松散的控制器,其中包含了视图的 UI 业务逻辑,所有从视图发出的事件,都会通过代理给 Presenter 进行处理;同时,Presenter 也通过视图暴露的接口与其进行通信。

    MVP

    2.2.3 MVVM

    MVP 模式演变而来

    • Model

    • View

    • ViewModel 类似与MVP中的 Presenter,唯一的区别是,它采用__双向绑定__:View的变动,自动反映在 ViewModel,反之亦然

    MVVM

    • 核心思想:关注Model的变化,让MVVM框架利用自己的机制去自动更新DOM,从而把开发者从操作DOM的繁琐中解脱出来!

    2.3 学习 Vue 需要改变关注点

    • jquery和原生js的关注点:节点

    • Vue中的关注点:数据

    3 使用VUE

    3.1 实例化new Vue()

      var data = { name: 'zhoutest' }
      var vm = new Vue({
        el: '#app',
        data: data
      });
    
    

    3.2 常用配置选项

    3.2.1 关于DOM节点

    el(类型:Selector|Element)

    Vue实例的挂载目标(实例中所有的属性/方法可直接在el中直接使用),挂载元素会被 Vue 生成的 DOM 替换

    template(类型:String)

    模板,如果不指定则以ele所在元素作为模板

    • Selector:提取内容到template标签,并指定选择器
    render(类型:Function)

    template 的代替方案,允许你发挥 JavaScript 最大的编程能力。该渲染函数接收一个 createElement(tagName,props,children) 方法作为第一个参数用来创建 VNode

    • 优先级:render > template > el.outerHTML
      new Vue({
        //...
        el:'#app',
        template:`<div>{{username}}</div>`,
        render:createElement=>{
          return createElement('h1',{title:'标题',class:'title'},'文章标题')
        }
      })
    

    3.2.2 关于数据

    data(类型:Object|Function)

    Vue 实例化时,它将 data 中所有的属性添加到__响应式系统__中,当这些数据改变时,视图会进行重渲染

    computed(类型:Object)

    对于需要复杂逻辑或运算才能得到的值,应当使用计算属性

    methods(类型:Object)

    一般用于编写公共方法、事件处理函数等,方法中的this指向实例,所以不应该使用箭头函数来定义 method 函数

    watch(Object)

    监听属性(Function),监听的值被修改时会自动调用函数,当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的

      watch: {
        username: function (val, oldVal) {
          console.log('new: %s, old: %s', val, oldVal)
        }
      }
    

    3.3 实例属性&方法

    Vue 实例化时,会遍历 data/computed/methods 中所有属性/方法,并写入Vue的实例

    3.3.1 属性特性

    1. 值属性(有自己的值的属性)
    • configurable 可配置性(属性特性总开关)

    • enumerable 可枚举性(是否可遍历)

    • writable 可写性

    • value

    2. 存储器属性(本身没有值,一般用于代理其他数据)
    • configurable 可配置性(属性特性总开关)

    • enumerable 可枚举性(是否可遍历)

    • get 监听读取操作

    • set 监听写入操作

    3. 设置属性特性
    • Object.defineProperty(obj,key,descriptor)

    • Object.defineProperties(obj,descriptors)

      Object.defineProperties(user,{
        age:{
          configurable:true
          value:18
        },
        password:{}
      })
    
    4. 获取属性特性
    • Object.getOwnPropertyDescriptor(obj,key)

    • Object.getOwnPropertyDescriptors()

    3.3.2 响应式属性

    • Vue在实例化时,会自动遍历data下的所有属性,并通过Object.defineProperty()把他们变成存储器属性,并写入Vue的实例

    • 特点:对属性的修改UI会自动更新

    • 原理:getter&setter

        let data = {
            username:'zhoutest',
            age:18,
            password:123456
        }
        let vm = new Vue({
            el:'#app'
            data
        })
    
    设置响应式属性
    • 设置初始化数据 data

    • Vue.set(target,key,val) 向__响应式系统__中的对象添加属性并自动渲染视图

      注意:target 对象不能是 Vue 实例,或者 Vue 实例的根数据对象

    • 数组变异方法

    3.3.3 内置属性

    除了数据属性,Vue 实例还提供了一些有用的实例属性与方法。它们都有前缀$,以便与用户定义的属性区分开来

    • $data: 同 data

    • $el: 同 el节点

    • $refs

    • $parent

    • $children

    • $root

    3.3.4 内置方法

    • 数据data

      • $watch():监听数据变化,同watch配置选项

      • $set():Vue.set()的别名

    • 事件event

      • $on():监听当前实例上的自定义事件

      • $off():移除自定义事件监听器

      • $emit():触发当前实例上的事件

    • 生命周期函数

    3.4 指令 directive

    • 指令是带有 v-* 前缀的特殊属性,格式:v-指令名:参数.修饰符="值"

    3.4.1 内置指令

    1. 数据绑定
    单向数据绑定
    • {{}}:插值表达式

      差值表达式中应当放置一些简单的运算(data中的数据、函数执行、三元运算等),对于任何复杂逻辑,你都应当使用计算属性操作完成后再写入插值表达式

    • v-text:显示文本

    • v-html:显示html内容

    • v-bind

    1. 可绑定任意属性

         <img v-bind:src="imgurl">
         <!-- 简写  -->
         <img :src="imgurl">
      
    2. 对style与class的绑定

      在将 v-bind 用于 class 和 style 时,Vue做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组

      <div class="static"
           v-bind:class="{ active: isActive, 'text-danger': hasError }"
           v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">
      </div>
      <script>
          new Vue({
              data: {
                  isActive: true,
                  hasError: false,
                  activeColor: 'red',
                  fontSize: 30
              }
          })
      </script>
      <!-- 最终结果:<div class="static active" style="color:red;font-size:30px"></div> -->
      
    3. v-bind无参数绑定对象

          <div v-bind="{username:'laoxie',age:18,gender:'男'}"></div>
          <!-- 等效于 -->
          <div v-bind:username="laoxie" v-bind:age="18" v-bind:gender="男"></div>
      
    v-model双向数据绑定

    v-model一般用于表单元素,会忽略所有表单元素的 value、checked、selected 特性的初始值而总是将 Vue 实例的数据作为数据来源

    • v-model值绑定到value属性

      • 单行文本框text

      • 多行文本框textarea

      • 单选框radio

      • 选择框select(无value属性则与内容绑定)

      • 复选框checkbox

        • 初始值为数组,与value属性绑定

        • 初始值为其他,与checked属性绑定(true,false)

        • true-value:设置选中时的值

        • false-value:设置补选中时的值

    • 修饰符

      • lazy:input触发改成change触发

      • number:输出值为number类型

      • trim:自动清楚前后空格

    • 双向数据绑定原理

      • Model -> View:响应式属性

      • View -> Model:事件

    • v-model的原理(替代方案)

      • v-bind:value="val"

      • v-on:input="val=$event.target.value"

        组件中使用v-model等效于:v-on:input="val=arguments[0]"

    列表渲染
    • v-for

      可遍历Array | Object | number | string | Iterable

      • 遍历数组

            <li v-for="(value, index) in arr">{{value}}</li>
        
      • 遍历对象

            <tr v-for="(value, key, index) in obj">
                <td>{{index+1}}</td>
                <td>{{key}}-{{value}}</td>
            </tr>
        
      • key:Vue 识别DOM节点的一个通用机制(用于diff算法)

        • Vue对相同的元素进行展示排序等操作时,遵循“就地复用”原则,因为这样更加高效,性能更好

        • 但对于依赖子组件状态或临时 DOM 状态 (如:表单输入值、复选框选中等)的列表,会出现操作混乱的问题

        • 指定key属性后,意为去掉“就地复用”特性(建议尽可能在使用 v-for 时提供 key)

    2. 显示隐藏
    • v-show(频繁显示隐藏)

      通过display属性控制元素的显示隐藏

    • v-if | v-else | v-else-if(不频繁的显示隐藏)

      通过创建/移除的方式控制元素的显示隐藏

    影响页面性能几大因素
    • 节点的频繁操作

    • 事件绑定数量

    • ....

    Virtual DOM

    一个结构类似与真实DOM节点的js对象

    • 优化方式

      • 优化节点操作

      • 优化事件处理

      • ....

    • 虚拟DOM是怎么优化性能的:背后有一套强大的算法:diff算法

    • key:唯一且稳定

        // 虚拟DOM大概样子
        {
            type:'div',
            attrs:{},
            children:[{
                type:'h1',
                children:'2021'
            },{
                type:'ul',
                children:[{
                    type:'li',
                    children:'1111'
                }.{
                    type:'li',
                    children:'2222'
                },{
                    type:'li',
                    children:'3333'
                }]
            }]
        }
    
    3. 事件绑定

    格式:v-on:事件类型.修饰符="事件处理函数"

    事件修饰符
    • stop

    • prevent

    • capture

    • self:只当在 event.target 是当前元素自身时触发处理函数(e.target === e.currentTarget)

    • once 事件将只会触发一次

    • 按键修饰符

      1. 直接使用键码来作为按键修饰符

            <!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` -->
            <input v-on:keyup.13="submit">
        
      2. 使用别名作为按键修饰符

        • left up right down
        • enter
        • tab
        • esc
        • space

    3.4.2 自定义指令

    1. 全局指令
    • 格式:Vue.directive(name, option)

    • 参数

      • name:指令名字,使用格式:v-name

      • option

        • Object:放钩子函数

        • Function:默认为bind和update的钩子函数

    2. 局部指令
    • 格式:directives: {}
        // 使用指令:v-zhoutest
        Vue.directive('zhoutest', {
            bind: function (el, binding, vnode) {
            //binding参数如下
            el.innerHTML =
              'name: ' + JSON.stringify(binding.name) + '<br>' + //指令名
              'value: ' + JSON.stringify(binding.value) + '<br>' + //指令值
              'expression: ' + JSON.stringify(binding.expression) + '<br>' + //字符串形式的指令表达式
              'arg: ' + JSON.stringify(binding.arg) + '<br>' + //指令参数,
              'modifiers: ' + JSON.stringify(binding.modifiers) + '<br>' //指令修饰符
          }
        });
    

    3.5 生命周期函数

    beforeCreate()

    • 初始化完成,但为往实例添加属性

    • 应用:可以在这加个loading事件

    created()

    • 应用:在这结束loading,还做一些初始化,实现函数自执行

    beforeMount()

    • 可以获取节点,但数据未渲染

    • 应用:在这发起ajax请求,拿回数据,配合路由钩子做一些事情

    mounted()

    实例挂载到 DOM

    • 应用:节点操作

    beforeUpdate()

    • 数据有更新但未更新节点

    updated()

    • 更新节点完毕

    beforeDestroy()

    destroyed()

    执行destroy()后,不会改变已生成的DOM节点,但后续就不再受vue控制了

    • 应用:清除定时器、延迟器、取消ajax请求等

    3.6 过滤器

    Vue允许你自定义过滤器,可被用于一些常见的文本格式化。

    • 过滤器可以用在两个地方:双花括号插值v-bind
        <!-- 在双花括号中 -->
        {{ message | capitalize }}
    
        <!-- 在 `v-bind` 中 -->
        <div v-bind:id="rawId | formatId"></div>
    

    全局过滤器

    格式:Vue.filter(name, definition)

    局部过滤器

    格式: filters属性

        // 首字母大写
        Vue.filter('capitalize', function (value) {
          if (!value) return ''
          value = value.toString()
          return value.charAt(0).toUpperCase() + value.slice(1)
        })
    

    3.7 mixin 混入

    混入一般用于组件选项的复用,并以一定的合并规则混入到组件中

    全局mixin:Vue.mixin(options)

    全局注册一个混入,会影响后面所有创建的每个 Vue 实例/组件(影响较大,一般用于插件编写)

      Vue.mixin({
        created: function () {
          // created生命周期函数会混入到下面的Vue实例中,且不会影响原来的选项
          console.log('global mixin:', this.username)
        }
      });
    
      new Vue({
        data:{
          username:'zhoutest'
        },
        created(){
          console.log('app.username', this.username)
        }
      });
    

    局部mixins:mixins:[mymixin]

    一般用于提取多个组件的公有部分配置

      var mixin = {
      data: function () {
        return {
          message: 'hello',
          foo: 'abc'
        }
      }
    }
    
    new Vue({
      mixins: [mixin],
      data: function () {
        return {
          message: 'goodbye',
          bar: 'def'
        }
      },
      created: function () {
        console.log(this.$data);// => { message: "goodbye", foo: "abc", bar: "def" }
      }
    })
    
    

    3.8 开发插件

    插件可以是一个对象(必须提供 install 方法),也可以是一个函数,它会被作为 install 方法,并把 Vue 作为参数传入

    3.8.1 插件类型

    • 添加全局方法或者属性,如: vue-custom-element

    • 添加全局资源:指令/过滤器/过渡等,如 vue-touch

    • 通过全局 mixin 方法添加一些组件选项,如: vue-router

    • 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。

    • 一个库,提供自己的 API,同时提供上面提到的一个或多个功能,如 vue-router

      MyPlugin.install = function(Vue, options) {
        // 1. 添加全局方法或属性
        Vue.myGlobalMethod = function() {
          // 逻辑...
        }
    
        // 2. 添加全局资源
        Vue.directive('my-directive', {
          bind (el, binding, vnode, oldVnode) {
            // 逻辑...
          }
          ...
        })
    
        // 3. 注入组件(影响后面定义的所有组件)
        Vue.mixin({
          created: function () {
            // 逻辑...
          }
          ...
        })
        Vue.component('mycomponent',{
          // 继承mixin中的created等配置
        })
    
        // 4. 添加实例方法
        Vue.prototype.$myMethod = function (methodOptions) {
          // 逻辑...
        }
      }
    

    3.8.2 使用

    通过全局方法 Vue.use() 使用插件。它需要在你调用 new Vue() 启动应用之前完成

      Vue.use(MyPlugin);//会自动调用MyPlugin中的install方法
    
      new Vue({
        //... options
      })
    
    

    4 组件 Component

    • 优点:代码复用 & 便于维护

    4.1 组件定义和使用

    组件是可复用的 Vue 实例,带有一个名字,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等(el选项除外)

    4.1.1 组件要求

    • data 必须为 Function 类型

    • 每个组件必须只有一个根元素,否则报错

    • 注册时组件名可以是 kebab-casePascalCase ,但在html页面上使用时,必须写成遵循W3C 规范中的自定义组件名 (字母全小写且必须包含一个连字符)

    4.1.2 定义

    1. 全局组件
    • Vue.component(name, options),所有的Vue实例都可以使用

    • 类似于new Vue(options)

        Vue.component('my-component', {
          // ... options ...
          template:'<p>我是全局组件</p>'
        })
    
    2. 局部组件
    • 在某个Vue实例中通过 components 属性注册的组件为局部组件,只有当前实例能使用
        var Child = {
            data() {
                return {
                    name: '我是局部组件'
                }
            },
            template: '<h1>hello, {{name}}</h1>'
        }
         
        // 创建根实例
        new Vue({
          el: '#app',
          components: {
            Child
          }
        });
    

    4.1.3 使用

    • 使用组件时,组件 template 中的内容会替换调组件所在位置
        <div id="app">
          <my-component></my-component>
          <child></child>
        </div>
    
    • 注意:由于 Vue 只有在浏览器解析和标准化 HTML 后才能获取模板内容,所以把组件嵌套在某些特定的元素(如 table, ul, ol, select 等)上时,会导致解析错误
      <!-- table为已经存在html页面上的元素 -->
      <table>
        <my-row></my-row>
      </table>
    
      Vue.component('my-row',{
        template:'<tr><td>test</td></tr>'
      });
    
    • 以上解析的结果为,tr被解析到了table外面,解决方式也很简单,利用特殊的 is 属性实现
      <table>
        <tr is="my-row"></tr>
      </table>
    

    4.2 组件通讯

    原则:谁的数据谁修改

    4.2.1 父组件 -> 子组件:props

    • 组件实例的作用域是孤立的。

    • 要让子组件使用父组件的数据,需要通过子组件的 props 选项

    1. 步骤
    1. 在子组件上定义属性,并传递数据

    2. 在子组件中通过 props 配置参数接收数据

    接收到的数据会自动称为子组件的属性

    2. props 声明属性
    • 声明的属性会自动成为组件实例的属性(可通过 this.xx 访问)

    • prop 传递是单向的,当父组件的属性变化时,将传导给子组件,但是不会反过来

        <blog-post mytitle="静态数据"></blog-post>
    
        Vue.component('blog-post', {
          props: ['mytitle'],
          template: '<h3>{{ mytitle }}</h3>'
        })
    
       <blog-post :msg="message"></blog-post>
        <!-- 传入一个对象 -->
       <blog-post v-bind:author="{ name: 'zhoutest', age:18 }"></blog-post>
    
        Vue.component('blog-post', {
          props: ['msg','author'],
          template: '<h3>{{ msg }}</h3>'
        });
    
        let vm = new Vue({
          data:{
            message:'hello zhoutest'
          }
        })
    
    3. 非props属性
    • 此类属性会自动成为组件根节点的属性(可通过 {inheritAttrs: false} 关闭)
    4. prop 数据验证

    对传入的 prop 属性进行校验,如:数据类型、必填、默认值等

      Vue.component('my-component', {
        props: {
          // 基础的类型检查 (`null` 匹配任何类型)
          propA: Number,
          // 多个可能的类型
          propB: [ String, Number ],
          // 必填的字符串
          propC: {
            type: String,
            required: true
          },
          // 带有默认值的数字,无prop属性传入时,默认得到100
          propD: {
            type: Number,
            default: 100
          },
          // 带有默认值的对象
          propE: {
            type: Object,
            // 对象或数组默认值必须从一个工厂函数获取
            default: function () {
              return { message: 'hello' }
            }
          },
          // 自定义验证函数
          myscore: {
            validator: function (value) {
              // 这个值必须大于等于60,否则报错
              return val >= 60
            }
          }
        }
      })
    

    4.2.2 子组件 -> 父组件:自定义事件 + $emit

    • Vue 遵循__单向数据流__原则,不允许在子组件中直接修改 props 传入的父组件数据,可以通过自定义事件系统,利用 $emit() 方法触发父组件函数来达到修改的效果
    1. 方法①
    1. 在子组件上定义一个事件 v-on:additem

    2. 在子组件内部触发这个自定义事件:$emit()

    2. 方法②
    1. 可以利用 v-bind:xx.sync 修饰符(如下color属性)

    2. 子组件调用 this.$emit('update:xx',val) 触发更新

      <div id="app">
        <p :style="{fontSize:fontSize+'px'}">字体大小:{{fontSize}}</p>
    
        <btn-change :font-size="fontSize" @bigger="updateFontSize" :color.sync="color"></btn-change>
      </div>
    
      <template id="myButton">
        <button @click="changeSize">改变字体大小</button>
        <button @click="changeColor">改变字体颜色</button>
      </template>
    
      <script>
        new Vue({
          el:'#app',
          data:{
              fontSize:16,
              color:'red'
          },
          components:{
            btnChange:{
              props:['fontSize'],
              template:'#myButton',
              methods:{
                changeSize(){
                  this.initFontSize++;
                  // 手动触发自定义事件并传递修改后的值
                  this.$emit('bigger',this.fontSize+1);
                },
                changeColor(){
                  this.$emit('update:color','#58bc58');
                }
              }
            }
          },
          methods:{
            updateFontSize(val){
              // 触发自定义事件的事件处理函数,并修改字体大小
              this.fontSize = val;
            }
          }
        })
      </script>
    

    4.2.3 兄弟组件通信

    • 组件A -> 父组件 -> 组件B

    4.2.4 多层级组件通讯

    • 利用一个 Vue 实例作为中间桥梁实现传参
    事件总线 Bus
    1. 自定义事件

      接收方自定义事件 $on()

    2. 触发自定义事件

      发送方触发事件 $emit()

        // 定义中间桥梁bus
        let bus = new Vue();
    
        //组件A
        let comA = {
            data(){
                return {
                  msg:'I am A'
                }
            },
            template:`<div>
                <p>{{msg}}</p>
                <button @click="send">传数据到B组件</button>
            </div>`,
            methods:{
                send(){
                    bus.$emit('data',this.msg);
                }
            }
        }
    
        // 组件B
        let comB = {
            data:()=>({
                msg:'I am B'
            }),
            mounted(){
                bus.$on('data',val=>this.msg = val)
            },
            template:`<div><p>{{this.msg}}</p></div>`
        }
    
        // 创建实例,并注册子组件
        new Vue({
            el:'#app',
            components:{
                comA,
                comB
            }
        });
    

    4.3 内置组件

    <component> 动态组件

    • is:指定渲染的组件
      <component v-bind:is="currentTabComponent"></component>
    

    <keep-alive> 缓存组件

    把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染可以添加一个 keep-alive
    包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们,主要用于保留组件状态或避免重新渲染

    • include(String/Regexp):指定缓存组件名

    • exclude(String/Regexp):指定不缓存的组件名

      <keep-alive>
         <component v-bind:is="currentTabComponent"></component>
      </keep-alive>
    

    <slot> 内容分发

    4.4 插槽

    • 内容通讯:插槽 slot

    4.4.1 利用组件内容进行通讯(组件外 -> 组件内)

    • 在组件模板中利用内置组件 <slot></slot> 来承载组件内容,否则它的内容都会被忽略
    默认插槽:<slot>
      <!-- 使用组件 -->
      <nav-link url="/home">首页</nav-link>
    
      <!-- 定义组件 -->
      <script>
        Vue.component('nav-link',{
          props:['url']
          template:`<a :href="url"><slot></slot><span>Home</span></a>`
        });
      </script>
    
    具名插槽:<slot name="xx">
    • 模板内容:给<slot/>组件命名(设置name属性)

    • 组件内容:设置 slot 属性 v-slot:name,实现内容精准显示到模板具体位置

      <!-- 组件模板内容 -->
      <template id="myTest">
        <div>
          <slot name="header">这是拥有命名的slot的默认内容</slot>
          <slot>这是拥有命名的slot的默认内容</slot>
          <slot name="footer">这是拥有命名的slot的默认内容</slot>
        </div>
      </template>
    
      <!-- 使用组件 -->
      <my-component>
        <template v-slot:header>这里的内容显示到name为header的插槽</template>
        <span>这里的内容显示到默认插槽</span>
        <template v-slot:footer>这里的内容显示到name为footer的插槽</template>
      </my-component>
    

    4.4.2 作用域插槽(组件内 -> 组件外)

    1. 把需要传递的参数写入 slot 属性

    2. v-slot="scope" (scope为写入solt的所有属性组成的对象)

      <!-- mynav组件模板 -->
      <div class="box">
        <slot :msg="msg" :username="username">{{username}}, {{msg}}</slot>
        <slot name="footer" title="播放器" :player="player">{{player}}</slot>
      </div>
    
      <!-- 组件内容 -->
      <mynav>
        <!-- props为传过来的数据组成的对象 -->
        <div slot-scope="props">{{props.msg}}, {{props.username}}</div>
    
        <!-- Vue2.6+用法 -->
        <div v-slot:default="props">{{props.msg}}, {{props.username}}</div>
        <div v-slot:footer="foot">{{foot.title}}, {{foot.player}}</div>
      </mynav>
    

    5 模块系统

    5.1 前言

    常规的定义组件的方法在复杂的项目中存在以下缺点

    • 全局定义 强制要求每个 component 中的命名不得重复

    • 字符串模板 缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的

    • 不支持 CSS 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏

    • 没有构建步骤 限制只能使用 HTML 和 ES5 JavaScript, 而不能使用预处理器,如 Pug (formerly Jade) 和 Babel

    5.2 vue单文件组件

    • Vue__单文件组件__(扩展名为 .vue),由于浏览器不支持.vue文件, 和ES6的模块化(import,export)开发, 必须利用babelwebpack工具来辅助实现编译成浏览器支持的格式

    • vue单文件优点

      • 完整语法高亮

      • CommonJS 模块

      • 组件作用域的 CSS

    5.3 vue单文件组件开发流程

    webpack打包

    5.3.1 安装必要模块

        "devDependencies": {
            "html-webpack-plugin": "^3.2.0",
            "vue": "^2.5.17",
            "vue-loader": "^15.4.2",
            "vue-template-compiler": "^2.5.17",
            "webpack": "^4.18.0",
            "webpack-cli": "^3.2.3"
        }
    

    5.3.2 设置webpack配置文件(webpack.config.js)

    5.3.3 应用入口文件(app.js)

        //ES6 引入其他模块(可以是js,css,vue单文件等)
        import Vue from 'vue';
        import App from './app.vue';
    
        new Vue({
            el:'#app',
    
            // render 函数若存在,则忽略 template 或 el 元素中的内容
            render(create){
                return create(App);
            }
        });
    

    5.3.4 单文件组件(app.vue)

        <template>
            <div class="container">
                <h1>Hello {{name}}</h1>
                <button class="btn btn-success">点击进入</button>
            </div>
        </template>
    
        <script>
            // 导出当前组件配置选项
            export default{
                data(){
                    return{
                        name:'Vue单文件组件'
                    }
                }
            }
        </script>
        
        <!-- 设置具有组件作用域的样式 -->
        <style scoped>
            h1{color:#58bc58;}
        </style>
    

    5.4 ES Module

    浏览器和服务器通用的模块解决方案,完全可以取代 CommonJSAMD 规范

    5.4.1 基本特点

    • 每一个模块只加载一次, 并执行一次,再次加载同一文件,直接从内存中读取

    • 每一个模块内声明的变量都是局部变量, 不会污染全局作用域

    • 通过 export 导出模块,通过 import 导入模块

    • ES6模块只支持静态导入和导出,只可以在模块的最外层作用域使用 importexport

    5.4.2 export

    • export 命令用于规定模块的对外接口,只允许导出最外层函数、类以及var、let或const声明的变量,可多次export,export出去后自动成为 模块对象的属性

    export后只能跟functionclassvarletconstdefault{}

    1. 基本用法
        //base.js
        var myName = 'laoxie';
        var age = 1995;
    
        // 多次export
        export { myName };
        export let gender = "男";
        export function show() { 
            console.log(666); 
        }
    
    2. as
    • 通常情况下,export 输出的变量就是本来的名字,但是可以使用 as 关键字重命名
        function show() {
            console.log('my name is show');
        }
        
        export { show as showName };
    
    3. default
    • 为模块指定默认输出,这样就可以在使用 import 指令的时候,不必知道所要加载的变量名或函数名
        export default {
            data:{
                path:'/src/'
            }
        }
    
    4. * 作为中转模块导出,把某个模块的所有相属性/方法导出
        export * from './md.js';
    

    5.4.3 import

    • import 命令用于导入其他模块提供的功能

    • 格式:import <module> from <url>

    1. url 支持格式
        // 支持
        import base from 'http://laoxie.com/js/base.js';
        import base from '/js/base.js';
        import base from './base.js';
        import base from '../base.js';
    
        // 不支持
        import base from 'base.js';
        import base from 'js/base.js';
    
    2. 基本用法
        //从模块对象中导入属性为default的值,并赋值给变量res,无则得到undefined
        import res from './base.js';
    
        //导入模块对象中属性为myName的值并赋值给变量myName
        import { myName } from './base.js';
    
    3. as 修改变量名
        //导入模块对象中属性为myName的值并赋值给变量username
        import { myName as username } from './base.js';
    
    4. * 导入整个模块对象
        //导入整个模块对象,并赋值给myModule变量
        import * as myModule from './base.js';
    

    5.5 在 html 中使用 ES Module

    浏览器支持 ES Module

    <script> 标签中指定 type="module"

        <script type="module">
            import res from './base.js';
            console.log(res)
        </script>
    
        <script type="module" src="js/base.js"></script>
    
    浏览器不支持ES Module

    利用 webpack 等工具转换成ES5后引入(推荐)

    6 过渡动画

    • <transition>
    • <transition-group>

    <transition>用于单个元素动画,<transition-group>用于多个元素并解析为一个标签(默认:span)

    6.1 属性

    • name: 过渡类名前缀(默认:v)

      如设置name="fade",过渡类名变成:fade-enter / fade-enter-active /fade-leave / fade-leave-active

    • css: boolean,是否使用 CSS 过渡类(默认:true)。设置为 false,将只通过组件事件触发注册的 JavaScript 钩子。

    自定义过渡类名(可配合animate.css框架实现过渡效果)

    • enter-class

    • enter-active-class

    • enter-to-class

    • leave-class

    • leave-active-class

    • leave-to-class

      <transition
        enter-active-class="bounceIn"
        leave-active-class="bounceOut"
      >
      </transition>
    

    6.2 触发动画场景

    Vue会自动检测是否设置 css动画JavaScript钩子,并在下列情形中添加进入/离开过渡效果(css过渡或js过渡)

    • 条件渲染 (使用 v-if)

    • 条件展示 (使用 v-show)

    • 动态组件

    • 组件根节点

    6.3 CSS过渡

    通过CSS过渡类名

    • v-enter:进入过渡的开始状态,元素被插入时生效,只应用一帧后立即删除

    • v-enter-active:进入过渡的结束状态,元素被插入时就生效,在过渡过程完成之后移除

    • v-leave:离开过渡的开始状态,元素被删除时触发,只应用一帧后立即删除

    • v-leave-active:离开过渡的结束状态,元素被删除时生效,离开过渡完成之后被删除

    6.4 JavaScript过渡

    通过内置事件实现过渡动画效果,可以利用第三方动画库(如:velocity.js,jquery等)实现动画效果

        <transition
          v-on:before-enter="beforeEnter"
          v-on:enter="enter"
          v-on:after-enter="afterEnter"
          v-on:enter-cancelled="enterCancelled"
          v-on:before-leave="beforeLeave"
          v-on:leave="leave"
          v-on:after-leave="afterLeave"
          v-on:leave-cancelled="leaveCancelled"
        >
        </transition>
    
        methods: {
          // 过渡进入
          // 设置过渡进入之前的组件状态
          beforeEnter: function (el) {
            // ...
          },
          // 设置过渡进入完成时的组件状态
          enter: function (el, done) {
            // ...
            done()
          },
          // 设置过渡进入完成之后的组件状态
          afterEnter: function (el) {
            // ...
          },
          enterCancelled: function (el) {
            // ...
          },
          // 过渡离开
          // 设置过渡离开之前的组件状态
          beforeLeave: function (el) {
            // ...
          },
          // 设置过渡离开完成时地组件状态
          leave: function (el, done) {
            // ...
            done()
          },
          // 设置过渡离开完成之后的组件状态
          afterLeave: function (el) {
            // ...
          },
          // leaveCancelled 只用于 v-show 中
          leaveCancelled: function (el) {
            // ...
          }
        }
    

    7 面试题

    • 响应式属性在哪个生命周阶段处理:创建阶段

    • 在父子组件通讯过程中,在哪个生命周期函数最先获取到父组件传入的数据

    • 在mounted生命周期函数中设置了定时器,组件销毁时定时器是否还在运行,如何清除

      • ajax请求 -> 如何取消ajax请求(xhr.abort())
  • 相关阅读:
    Windows 10 Universal App 开发记录
    Windows Phone 8.1 开发会用到的方法
    Android Activity设置全屏
    Android视频录制命令screenrecord
    Android ScrollView中嵌套ListView只显示一行的解决办法
    Android 4.4.4: java.lang.SecurityException: Package com.android.settings does not belong to 1001
    自定义Android spinner样式并添加监听事件
    GSON快速实现内部类
    android的Banner轮播图框架
    Okhttp与Okhttputils的用法及区别
  • 原文地址:https://www.cnblogs.com/pleaseAnswer/p/15010057.html
Copyright © 2020-2023  润新知