zoukankan      html  css  js  c++  java
  • Vue开发者必会的基础知识盘点


    下面是Vue的一些基本知识点相关学习跟应用,差缺补漏吧。Vue.js官网好好看一遍还是很香的。

    Vue中的数据和DOM已经被关联起来,所有的东西都是响应式的。注意我们不再和HTML直接交互。一个Vue应用会将其挂载到DOM元素上然后对齐进行完全的控制,那个HTML是我们的入口,但是其他的都会发生在新创建的Vue实例内部。详情可见MVVM原理极其实现

     

    Vue实例

    1、实例声明周期钩子函数

    8个声明周期函数

     

    模板语法

    1、插值

    ①、 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。

    ②、可以使用js表达式但是不能使用语句和流控制(if判断语句)

     
    1 {{ ok ? 'YES' : 'NO' }}
    2  {{ message.split('').reverse().join('') }}
    3  ​
    4  <!-- 这是语句,不是表达式 -->
    5  {{ var a = 1 }}
    6  <!-- 流控制也不会生效,请使用三元表达式 -->
    7  {{ if (ok) { return message } }}

     

    2、指令

    ①、动态参数 -2.60新增

    可以使用动态参数为一个动态的事件名绑定处理函数:

    约束:为某些字符,如空格和引号,放在 HTML attribute 名里是无效的。会触发警告。

    1  <a v-on:[eventName]="doSomething"> ... </a>

    当 eventName 的值为 "focus" 时,v-on:[eventName] 将等价于 v-on:focus

     

    3、修饰符

    在移动端最好的应用就是

    ①、 .stop 阻止事件冒泡

    ②、 .prevent (@touchmove.prevent 禁止底层页面滑动)

     

    计算属性和侦听器

    模板中不应该放入过多的逻辑,会让模板过重且难以维护,所以对于任何复杂逻辑,都应该使用计算属性

    基础例子

     

     
     1 <div id="example">
     2    <p>Original message: "{{ message }}"</p>
     3    <p>Computed reversed message: "{{ reversedMessage }}"</p>
     4  </div>
     5  var vm = new Vue({
     6    el: '#example',
     7    data: {
     8      message: 'Hello'
     9    },
    10    computed: {
    11      // 计算属性的 getter
    12      reversedMessage: function () {
    13        // `this` 指向 vm 实例
    14        return this.message.split('').reverse().join('')
    15      }
    16    }
    17  })
    18  // Original message: "Hello"
    19 20  // Computed reversed message: "olleH"

    我们声明了一个计算属性 reversedMessage。Vue 知道 vm.reversedMessage 依赖于 vm.message,因此当 vm.message 发生改变时,,所有依赖 vm.reversedMessage 的绑定也会更新。

     

    计算属性缓存 vs 方法

    我们通过表达式中调用方法可以同样达到效果:

    1  <p>Reversed message: "{{ reversedMessage() }}"</p>
    2  // 在组件中
    3  methods: {
    4    reversedMessage: function () {
    5      return this.message.split('').reverse().join('')
    6    }
    7  }

    两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存。只在相关响应依赖发生改变时它们才会重新计算求值。这就意思只要message还没有改变,多次访问reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数

    注:这也同样意味着下面的计算属性将不再更新,因为 Date.now() 不是响应式依赖:

     
    1 computed: {
    2    now: function () {
    3      return Date.now()
    4    }
    5  }

    如你不希望有缓存,请用方法来替代。

     

    计算属性 vs 侦听属性

    Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性

    但是有些时候可以使用computed代替watch

     

    计算属性的 setter

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

     1  computed: {
     2    fullName: {
     3      // getter
     4      get: function () {
     5        return this.firstName + ' ' + this.lastName
     6      },
     7      // setter
     8      set: function (newValue) {
     9        var names = newValue.split(' ')
    10        this.firstName = names[0]
    11        this.lastName = names[names.length - 1]
    12      }
    13    }
    14  }

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

    侦听器

    当数据变化要执行异步或者开销较大的操作,watch 是最有用的选择。

     

    Class于Style绑定

    绑定HTML Class

    对象语法

    ①、我们可以传给 v-bind:class 一个对象,以动态地切换 class:

     
    1 <div v-bind:class="{ active: isActive }"></div>

    是否渲染取决于isActive是 true或false

     

    ②、你可以在对象中传入更多字段来动态切换多个 class。此外,v-bind:class 指令也可以与普通的 class attribute 共存。当有如下模板:

     1  <div
     2    class="static"
     3    v-bind:class="{ active: isActive, 'text-danger': hasError }"
     4  ></div>
     5  6  // data定义如下
     7  data: {
     8    isActive: true,
     9    hasError: false
    10  }
    11 12  // 渲染结果
    13  // <div class="static active"></div>

     

    ③、绑定的数据对象不必内联定义在模板里:

     
    1 <div v-bind:class="classObject"></div>
    2  data: {
    3    classObject: {
    4      active: true,
    5      'text-danger': false
    6    }
    7  }

     

    ④、这是一个常用且强大的模式,我们也可以在这里绑定一个返回对象的计算属性

     <div v-bind:class="classObject"></div>
     data: {
       isActive: true,
       error: null
     },
     computed: {
       classObject: function () {
         return {
           active: this.isActive && !this.error,
           'text-danger': this.error && this.error.type === 'fatal'
         }
       }
     }

     

    数组语法

    ①、我们可以把一个数组传给 v-bind:class,以应用一个 class 列表:

    1  <div v-bind:class="[activeClass, errorClass]"></div>
    2  data: {
    3    activeClass: 'active',
    4    errorClass: 'text-danger'
    5  }
    6  // 渲染为:
    7  // <div class="active text-danger"></div>

     

    ②、 数组语法中也可以使用对象语法:

    1  <div v-bind:class="[{ active: isActive }, errorClass]"></div>

     

    用在组件上

    当在一个自定义组件上使用 class 时,这些 class 将被添加到该组件的根元素上面。这个元素上已经存在的 class 不会被覆盖。

    你声明了这个组件:

     
    1 Vue.component('my-component', {
    2    template: '<p class="foo bar">Hi</p>'
    3  })
    4  <!-- 在使用它的时候添加一些 class: -->
    5  <my-component class="baz boo"></my-component>
    6 7  <!-- HTML 将被渲染为: -->
    8  <p class="foo bar baz boo">Hi</p>

     

     

    绑定内联样式

    对象语法

    v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名:

     
     1 <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
     2  3  <!-- 直接绑定到一个样式对象通常更好,这会让模板更清晰: -->
     4  <div v-bind:style="styleObject"></div>
     5  data: {
     6    activeColor: 'red',
     7    fontSize: 30
     8  }
     9 10  // 绑定对象
    11  data: {
    12    styleObject: {
    13      color: 'red',
    14      fontSize: '13px'
    15    }
    16  }

    同样的,对象语法常常结合返回对象的计算属性使用。

    多重值

    从 2.3.0 起你可以为 style 绑定中的 property 提供一个包含多个值的数组,常用于提供多个带前缀的值,例如:

    1  <div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

     

    条件渲染

    <template>元素上使用v-if条件渲染分组

    因为 v-if 是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 <template> 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 <template> 元素。

    1  <template v-if="ok">
    2    <h1>Title</h1>
    3    <p>Paragraph 1</p>
    4    <p>Paragraph 2</p>
    5  </template>

    v-else-if v-else

    类似于 v-elsev-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。

     

    用key可以管理可复用的元素

    Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:

     
    <template v-if="loginType === 'username'">
       <label>Username</label>
       <input placeholder="Enter your username">
     </template>
     <template v-else>
       <label>Email</label>
       <input placeholder="Enter your email address">
     </template>

    那么在上面的代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,<input> 不会被替换掉——仅仅是替换了它的 placeholder

     

    这样也不总是符合实际需求,所以 Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key attribute 即可:

     
    <template v-if="loginType === 'username'">
       <label>Username</label>
       <input placeholder="Enter your username" key="username-input">
     </template>
     <template v-else>
       <label>Email</label>
       <input placeholder="Enter your email address" key="email-input">
     </template>

    现在,每次切换时,输入框都将被重新渲染。

    v-for和v-if

    永远不要把 v-ifv-for 同时用在同一个元素上。

    一般我们在两种常见的情况下会倾向于这样做:

    • 为了过滤一个列表中的项目 (比如 v-for="user in users" v-if="user.isActive")。在这种情形下,请将 users 替换为一个计算属性 (比如 activeUsers),让其返回过滤后的列表。

    • 为了避免渲染本应该被隐藏的列表 (比如 v-for="user in users" v-if="shouldShowUsers")。这种情形下,请将 v-if 移动至容器元素上 (比如 ulol)。

    1  <ul>
    2    <li
    3      v-for="user in users"
    4      v-if="user.isActive"
    5      :key="user.id"
    6    >
    7      {{ user.name }}
    8    </li>
    9  </ul>

    当 Vue 处理指令时v-forv-if 具有更高的优先级,哪怕我们只渲染出一小部分用户数据的元素,也得在每次重新渲染的时候遍历整个列表,不论活跃用户是否发生变化,应该使用计算属性

     

    列表渲染

    v-for

    在v-for中,既可以使用数组也可以使用对象

     

    状态维护

    当Vue正在更新使用v-for渲染列表时,它默认使用“就地更新策略”。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每一个元素,并确保它们在每个位置索引位置正确渲染。

    不要使用对象或数组之类的非基本类型值作为v-for的key。请用字符串或数值型的值。

    key的特殊主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes。如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用key时,它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素

     

     

    事件处理

    内联处理器的方法

    有时也需要在内联语句处理器中访问原始的DOM事件。可以使用特殊变量$event把它传入方法:

     <button v-on:click="warn('Form cannot be submitted yet.', $event)">
       Submit
     </button>
     // ...
     methods: {
       warn: function (message, event) {
         // 现在我们可以访问原生事件对象
         if (event) {
           event.preventDefault()
         }
         alert(message)
       }
     }

     

    事件修饰符

    以上方法虽然可以实现,但是更好的方式是:方法只有纯粹的数据逻辑,而不是去处理DOM事件细节。为了解决这个问题,Vue提供了事件修饰符。

     

     .stop  // 等同于js中的event.stopPropagation(),防止事件冒泡 
     .prevent // 取消默认事件,比如a标签的链接跳转
     .caputer // 捕获事件,点击子节点,由外到内父节点->子节点触发点击事件(不加是由内到外)
     .self // 只触发自己范围内的事件,不会包含子元素
     .once // 只执行一次点击
     .passive

    【浏览器只有等内核线程执行到事件监听器对应的JavaScript代码时,才能知道内部是否会调用preventDefault函数来阻止事件的默认行为,所以浏览器本身是没有办法对这种场景进行优化的。这种场景下,用户的手势事件无法快速产生,会导致页面无法快速执行滑动逻辑,从而让用户感觉到页面卡顿。】

    通俗点说就是每次事件产生,浏览器都会去查询一下是否有preventDefault阻止该次事件的默认动作。我们加上passive就是为了告诉浏览器,不用查询了,我们没用preventDefault阻止默认动作。

     

     

    表单输入绑定

    修饰符

    .lazy

    在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 。你可以添加 lazy 修饰符,从而转为在 change 事件之后进行同步:

     <!-- 在“change”时而非“input”时更新 -->
     <input v-model.lazy="msg">
     
     <!--注:ElementUI的input输入框不支持 `v-model` 修饰符-->

     

    number

    可以自动将用户输入的值转换成数值类型:

    只有这个值无法被 parsenFloat()解析,则会返回原始的值

     <input v-model.number="age" type="number">

     

    .trim

    过滤用户输入的收尾空白字符:

     
    1 <input v-model.trim="msg">

     

     

    组件基础

    通过Prop向子组件传递数据

    传入一个对象的所有property

    如果想将一个对象的所有property都作为prop传入,可以不用每个参数分别使用v-bind

     
    1 post: {
    2    id: 1,
    3    title: 'My Journey with Vue'
    4  }

    下面的模板

     
    1 <blog-post v-bind="post"></blog-post>
    2 3  <!-- 等价于 -->
    4  <blog-post
    5    v-bind:id="post.id"
    6    v-bind:title="post.title"
    7  ></blog-post>

     

    单向数据流

    所有的prop传值都让父子prop之间形成一个单行下行绑定。每次父组件发生变更时,子组件中所有的prop都将会刷新为最新的值,这说明你不应该在子组件内部改prop(强行做,Vue会有警告)

    注:JavaScript中数组和对象是通过引用传入的,对于一个数组或对象类型的prop来说,在子组件中改变变更这个对象的本身将会影响父组件的状态

     

    Prop验证

     1  Vue.component('my-component', {
     2      props: {
     3          // 基础的类型检查('null' 和 'undefined'会通过任何类型的验证
     4          propA: Number,
     5          // 多个类型
     6          propB: [Number, String]
     7          // 必填字符串
     8          propC: [
     9              type: String,
    10              required: true
    11          ]
    12      }
    13  })

     

    自定义事件

    始终使用 kebab-case 的事件名

     

    插槽

    编译作用域

    父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

    具名插槽

    作用域插槽

     

     

    混入

    基础

    混入(mixin)提供了一种非常灵活的方式,来分发Vue组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项

    选项合并

    当组件和混入对象有同名选项是, 数据对象在内部会进行递归合并,并且在发生冲突时以组件数据优先

     
     1 var mixin = {
     2      data() {
     3          return {
     4              message: 'hello',
     5              foo: 'abc'
     6          }
     7      }
     8  }
     9 10  new Vue({
    11      mixin: [mixin],
    12      data() {
    13          return {
    14              message: 'goodbye',
    15              bar: 'def'
    16          }
    17      },
    18      created() {
    19          console.log(this.$data)
    20          // => {message: 'goodbye', foo:'adc', bar: 'def'}
    21      }
    22  })

     

    同名钩子函数将合并为一个数组,因此都将被调用。只是混入对象的钩子将在组件自身钩子之前调用

    值为对象的选项,例如methods、components和directives,将别合并成同一个对象。两个对象键名冲突时,取组件对象的键值对

     

    自定义选项合并策略

    自定义选项将使用默认策略,即简单地覆盖已有值。如果想要自定义选项以自定义逻辑合并,可以向 Vue.config.optionMergeStrategies添加一个函数

     

    自定义指令

    钩子函数

    钩子函数参数

    动态指令参数

    对象字面量

    如果指令需要多个值,可以传入一个JavaScript对象字面量。指令函数可以接受所有合法的JavaScript表达式

    1  <div v-demo="{ color: 'white', text: 'hello!' }"></div>
    2  Vue.directive('demo', function (el, binding) {
    3    console.log(binding.value.color) // => "white"
    4    console.log(binding.value.text)  // => "hello!"
    5  })

     

     

    渲染函数 & JSX

    看懂百分之30%,过段时间再看

     

    路由

    编程式导航和声明式导航

     1  //  声明式
     2  <router-link :to="....">
     3  4  // 编程式
     5  router.push(...)
     6  // ex:       
     7  // 字符串
     8  router.push('home')
     9  // 对象
    10  router.push({ path: 'home' })
    11  // 命名的路由
    12  router.push({ name: 'user', params: { userId: '123' }})
    13  // 带查询参数,变成 /register?plan=private
    14  router.push({ path: 'register', query: { plan: 'private' }})

     

    导航守卫

    全局前置守卫

    router.beforeEach

    全局解析守卫

    router.beforeResolve

    全局后置钩子

     router.afterEach((to, from) => {
       // ...
     })

    路由独享守卫

      beforeEnter: (to, from, next) => {
             // ...
      }

     

    组件内的守卫

    ① beforeRouteEnter

    ② beforeRouteUpdate

    ③ beforeRouteLeave

     
     1  beforeRouteEnter (to, from, next) {
     2      // 在渲染该组件的对应路由被 confirm 前调用
     3      // 不!能!获取组件实例 `this`
     4      // 因为当守卫执行前,组件实例还没被创建。
     5       next(vm => {
     6           // 通过`vm`访问组件实例
     7       })
     8    },
     9    beforeRouteUpdate (to, from, next) {
    10      // 在当前路由改变,但是该组件被复用时调用
    11      // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转       的时候,
    12      // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调       用。
    13      // 可以访问组件实例 `this`
    14    },
    15    beforeRouteLeave (to, from, next) {
    16      // 导航离开该组件的对应路由时调用
    17      // 可以访问组件实例 `this`
    18    }

    完整的导航解析流程

    1.导航被触发。 2.在失活的组件里调用 beforeRouterLeave守卫。 3.调用全局的 beforeEach守卫。 4.在重用的组件里调用 beforeRouterUpdate守卫。 5.在路由配置里调用 beforeEnter 6.解析异步路由组件。 7.在被激活的组件里调用 beforeRouterEnter 8.调用全局的 beforeResolve守卫。 9.导航被确认。 10.调用全局 afterEach钩子。 11.触发DOM更新。 12.用创建好的实例调用 beforeRouteEnter 守卫中传给 next的回调函数。

     

    Vuex

    State

    state 提供唯一的公共数据源。所有共享的数据要统一放到Store的State中进行储存

    组件访问State中数据的第一种方式:

    1  this.$store.state.全局数据名称

    组件访问State中数据的第二种方式:

     
    1 // 1.从Vuex中按需导入`mapState`函数
    2  import { mapState } from 'vuex'
    3 4  // 2.将全局数据,映射为当前组件的计算属性
    5  computed: {
    6      ...mapState(['count'])
    7  }

     

    Mutation

    Mutation用于变更Store中的数据。

    ① 只能通过muntation变更Store数据,不可以直接操作Store中的数据。

    ② 通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。

     
     1 // 定义motation
     2  mutations: {
     3      add(state) {
     4          // 变更状态
     5          state.count++
     6      },
     7      // 传参
     8      addN(state,n) {
     9          state.count+=n
    10      }
    11  }
    12 13  //组件中触发mutation
    14  methods: {
    15      handle() {
    16          // 触发mutations 的第一种方式
    17          this.$store.commit('add')
    18          // 触发mutations传参
    19          this.$store.commit('addN', 3)
    20      }
    21  }

     

    this.$store.commit()是触发mutations的第一种方式,触发mutations的第二种方式:

     

    1  // 1.从vuex中按需导入`mapMutations`函数
    2  import { mapMutations } from 'vuex'
    3 4  // 2.将指定的 mutations函数,映射为当前组件的 methods函数
    5  methods: {
    6      ...mapMutations(['add','addN'])
    7  }

     

    Action

    Action用于处理异步任务。

    如果通过异步变更数据,必须通过Action,而不能使用Mutation,但是在Action中还是要通过触发Mutation的方式间接变更数据。

     
    // 定义Action
     actions: {
         // context 第一个形参可以理解为当前new 的实例
         addAsync(context,n) {
             setTimeout(() => {
                 context.commit('addN',n)
             },1000)
         }
     }
     ​
     // 触发Action
     methods: {
         handle: {
             // 触发actions 的第一种方式
             // 携带参数
             this.$store.dispath('addAsync', 5)
         }
     }

     

    this.$store.dispatch()是触发actions的第一种方式,触发actions的第二种方式

    1  // 1.从vuex中按需导入`mapActions`函数
    2  import { mapActions } from 'vuex'
    3 4  // 2.将指定的actions函数,映射为当前组件的methods函数
    5  methods: {
    6      ...mapActions(['addAsync', 'addNAsync'])
    7  }

     

    Getter

    Getter用于对Store中的数据进行加工处理形成新的数据。

    ① Getter可以对Store中已有的数据加工处理之后形成新的数据,类似Vue的计算属性

    ② Store中数据发生变化,Getter的数据也会跟着变化。

     
     1 // 定义Getter
     2  const strore = new Vuex.Store({
     3      state: {
     4          count: 0
     5      },
     6      getters: {
     7          showNum: state => {
     8              return '当前最新的数量是【'+ state.count +'】'
     9          }
    10      }
    11  })

    使用getters的第一种方式:

     
    1 this.$store.getters.名称

    使用getters的第二种方式:

     
    1 import { MapGetters } from 'vuex'
    2 3  computed: {
    4      ...mapGetters(['showNum'])
    5  }

     

    namespaced

    这个属性是用来解决不同模块命名冲突的问题:

    1  // 不同页面引入getter、actions、mutations时,要加上模块名
    2  // ex
    3  ...mapGetters('BadInfo', ['DialogDate'])
    4 5  // 第二种写法
    6  this.$store.commit('XXX/SETXXX',sth);
    7  this.$store.getters['XXX/getXXX'];

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    前端构建工具gulpjs的使用介绍及技巧(转载)
    jq checked 设置问题
    JavaScript面向对象及相关知识
    github 操作指南
    WebStorm常用快捷键
    Windows下Scala环境搭建
    For与Function进阶实战、Lazy的使用笔记总结
    第3课 Scala函数式编程彻底精通及Spark源码阅读笔记
    第2课 Scala面向对象彻底精通及Spark源码SparkContext,RDD阅读总结
    第1课 Scala入门与实战笔记总结
  • 原文地址:https://www.cnblogs.com/dingxingxing/p/13338330.html
Copyright © 2011-2022 走看看