Vue 的基本知识 注意点

发布于 2025-01-27 17:45:27 字数 12660 浏览 8 评论 0

生命周期 created 钩子可以用来在一个实例被创建之后执行代码,生命周期钩子的 this 上下文指向调用它的 Vue 实例

模板表达式都被放在沙盒中,只能访问 全局变量的一个白名单 ,如 Math 和 Date 。你不应该在模板表达式中试图访问用户定义的全局变量

动态参数: <a v-bind:[attributeName]="url"> ... </a><a v-on:[eventName]="doSomething"> ... </a> 。attributeName 会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果你的 Vue 实例有一个 data 属性 attributeName,其值为 "href",那么这个绑定将等价于 v-bind:href。动态参数预期会求出一个字符串,异常情况下值为 null。这个特殊的 null 值可以被显性地用于移除绑定。任何其它非字符串类型的值都将会触发一个警告。 需要避免使用大写字符来命名键名,因为浏览器会把 attributeName 名全部强制转为小写。

任何复杂逻辑,你都应当使用计算属性 computed。计算属性的 getter 函数是没有副作用 (side effect) 的,这使它更易于测试和理解。方法和计算属性两者不同在于计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。

用 key 管理可复用的元素

<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 属性即可:

现在,每次切换时,输入框都将被重新渲染。 <label> 元素仍然会被高效地复用,因为它们没有添加 key 属性

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

由于 JavaScript 的限制,Vue 不能检测以下数组的变动 :

当你利 用索 引直接设置一个数组项 时,例如:vm.items[indexOfItem] = newValue

当你 修改数组的长度 时,例如:vm.items.length = newLength

为了解决第一类问题,以下两种方式:

 // Vue.set
 Vue.set(vm.items, indexOfItem, newValue)
 // Array.prototype.splice
 vm.items.splice(indexOfItem, 1, newValue)

你也可以使用 vm.$set 实例方法,该方法是全局方法 Vue.set 的一个别名:

 vm.$set(vm.items, indexOfItem, newValue)

为了解决第二类问题,你可以使用 splice:

 vm.items.splice(newLength)

由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除 :

可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式属性。

你还可以使用 vm.$set 实例方法,它只是全局 Vue.set 的别名: vm.$set(vm.userProfile, 'age', 27)

有时你可能需要为已有对象赋值多个新属性,比如使用 Object.assign() _.extend() 。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性, 不要像这样

Object.assign(vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

你应该这样做

vm.userProfile = Object.assign({}, vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化,所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的。例如:

var vm = new Vue({
  data:{
    a:1
  }
})
// `vm.a` 是响应式的
vm.b = 2
// `vm.b` 是非响应式的

prop 类型

字符串数组 形式列出的 prop:

props: ['title', 'likes', 'isPublished', 'commentIds', 'author']

但是,通常你希望每个 prop 都有指定的值类型。这时,你可以以对象形式列出 prop,这些属性的名称和值分别是 prop 各自的名称和类型:

 // 这不仅为你的组件提供了文档,还会在它们遇到错误的类型时从浏览器的 JavaScript 控制台提示用户
 props: {
   title: String,
   likes: Number,
   isPublished: Boolean,
   commentIds: Array,
   author: Object,
   callback: Function,
   contactsPromise: Promise // or any other constructor
 }

自定义组件的 v-model

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的 event,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于 不同的目的 。model 选项可以用来避免这样的冲突:

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})

现在在这个组件上使用 v-model 的时候: <base-checkbox v-model="lovingVue"></base-checkbox>

这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的属性将会被更新。

访问根实例 :每个 new Vue 实例的子组件中,其根实例可以通过 $root 属性进行访问。所有的子组件都可以将这个实例作为一个全局 store 来访问或使用。对于 demo 或非常小型的有少量组件的应用来说这是很方便的。不过这个模式扩展到中大型应用来说就不然了。因此在绝大多数情况下,我们强烈推荐使用 Vuex 来管理应用的状态。

访问父级组件实例$parent 属性可以用来从一个子组件访问父组件的实例。它提供了一种机会,可以在后期随时触达父级组件,以替代将数据以 prop 的方式传入子组件的方式

$refs 只会在组件渲染完成之后生效,并且它们不是响应式的。这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs

强制更新 :通过 $forceUpdate 来做这件事

组件里面 data 使用 图片路径 是要用 require('./../mm.png') 才能正确访问图片,这样才能够被 webpack 正确解析

如果 在组件渲染时出现运行错误 ,错误将会被传递至全局 Vue.config.errorHandler 配置函数 (如果已设置)。利用这个钩子函数来配合错误跟踪服务是个不错的主意。比如 Sentry ,它为 Vue 提供了 官方集成

为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样 回调函数将在 DOM 更新完成后被调用 。在组件内使用 vm.$nextTick() 实例方法特别方便,因为它不需要全局 Vue,并且回调函数中的 this 将自动绑定到当前的 Vue 实例上

<script>
Vue.component('example', {
  template: '<span></span>',
  data: function () {
    return {
      message: '未更新'
    }
  },
  methods: {
    updateMessage: function () {
      this.message = '已更新'
      console.log(this.$el.textContent) // => '未更新'
      this.$nextTick(function () {
        console.log(this.$el.textContent) // => '已更新'
      })
    }
  }
})
</script>

因为 $nextTick() 返回一个 Promise 对象 ,所以你可以使用新的 ES2017 async/await 语法完成相同的事情:

<script>
methods: {
  updateMessage: async function () {
    this.message = '已更新'
    console.log(this.$el.textContent) // => '未更新'
    await this.$nextTick()
    console.log(this.$el.textContent) // => '已更新'
  }
}
</script>

路由参数解耦

一般在组件内使用路由参数(不好):

<script>
methods: {
    getParamsId() {
        return this.$route.params.id
    }
}
</script>

正确的做法是通过 props 解耦:

const router = new VueRouter({
    routes: [{
        path: '/user/:id',
        component: User,
        props: true
    }]
})

将路由的 props 属性设置为 true 后,组件内可通过 props 接收到 params 参数:

export default {
    props: ['id'],
    methods: {
        getParamsId() {
            return this.id
        }
    }
}

还可以通过函数模式来返回 props:

const router = new VueRouter({
    routes: [{
        path: '/user/:id',
        component: User,
        props: (route) => ({
            id: route.query.id
        })
    }]
})

函数式组件

函数式组件是无状态,它无法实例化,没有任何的生命周期和方法。创建函数式组件也很简单,只需要在模板添加 functional 声明即可。 一般适合只依赖于外部数据的变化而变化的组件 ,因其轻量,渲染性能也会有所提高。

组件需要的一切都是通过 context 参数传递 。它是一个上下文对象,具体属性查看文档。这里 props 是一个包含所有绑定属性的对象。

<template functional>
<div class="list">
    <div class="item" v-for="item in props.list" :key="item.id" @click="props.itemClick(item)">
        <p></p>
        <p></p>
    </div>
    </div>
</template>

父组件使用:

<template>
<div>
    <List :list="list" :itemClick="item => (currentItem = item)" />
    </div>
</template>
<script>
    import List from '@/components/List.vue'
    export default {
        components: {
            List
        },
        data() {
            return {
                list: [{
                    title: 'title',
                    content: 'content'
                }],
                currentItem: ''
            }
        }
    }
</script>

样式穿透

在开发中修改第三方组件样式是很常见,但由于 scoped 属性的样式隔离,可能需要去除 scoped 或是另起一个 style 。这些做法都会带来副作用(组件样式污染、不够优雅), 样式穿透在 css 预处理器中使用才生效

使用 >>>/deep/ 解决这一问题:

<style scoped>
    外层 >>> .el-checkbox {
        display: block;
        font-size: 26px;
        .el-checkbox__label {
            font-size: 16px;
        }
    }
</style>
<style scoped>
    /deep/ .el-checkbox {
        display: block;
        font-size: 26px;
        .el-checkbox__label {
            font-size: 16px;
        }
    }
</style>

事件参数$event

$event 是事件对象的特殊变量,在一些场景能给我们实现复杂功能提供更多可用的参数

原生事件

在原生事件中表现和默认的事件对象相同:

<template>
<div>
    <input type="text" @input="inputHandler('hello', $event)" />
    </div>
</template>
<script>
    export default {
        methods: {
            inputHandler(msg, e) {
                console.log(e.target.value)
            }
        }
    }
</script>

自定义事件

在自定义事件中表现为捕获从子组件抛出的值

<!-- my-item.vue :-->
<script>
   export default {
       methods: {
           customEvent() {
               this.$emit('custom-event', 'some value')
           }
       }
   }
</script>

<!--App.vue: -->
<template>
<div>
   <my-item v-for="(item, index) in list" @custom-event="customEvent(index, $event)">
   </my-list>
   </div>
</template>
<script>
   export default {
       methods: {
           customEvent(index, e) {
               console.log(e) // 'some value'
           }
       }
}
</script>

自定义组件双向绑定

组件 model 选项 :允许一个自定义组件在使用 v-model 时定制 prop event

默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event ,但是一些输入类型比如单选框和复选框按钮可能想使用 value prop 来达到不同的目的。使用 model 选项可以回避这些情况产生的冲突。

input 默认作为双向绑定的更新事件,通过 $emit 可以更新绑定的值:

<my-switch v-model="val"></my-switch>                
export default {
    props: {
        value: {
            type: Boolean,
            default: false
        }
    },
    methods: {
        switchChange(val) {        
            this.$emit('input', val)
        }
    }
}

修改组件的 model 选项,自定义绑定的变量和事件:

   <my-switch v-model="num" value="some value"></my-switch>
   export default {
       model: {
           prop: 'num',
           event: 'update'
       },
       props: {
           value: {
               type: String,
               default: ''
           },
           num: {
               type: Number,
               default: 0
           }
       },
       methods: {
           numChange() {
               this.$emit('update', this.num++)
           }
       }
   }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

夜灵血窟げ

暂无简介

文章
评论
29 人气
更多

推荐作者

十二

文章 0 评论 0

飞烟轻若梦

文章 0 评论 0

OPleyuhuo

文章 0 评论 0

wxb0109

文章 0 评论 0

旧城空念

文章 0 评论 0

-小熊_

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文