vue 添加自定义属性不依赖data数据_Vue的难点解析

本文探讨了Vue中watch、computed和methods的区别,强调了计算属性的缓存特性。介绍了Vue的生命周期钩子函数及其应用场景,详细阐述了Vue的数据响应式原理。此外,文章还讲解了组件间通信的多种方式,包括props、自定义事件、eventBus和Vuex,并提及VueRouter的使用和路由守卫的概念。
摘要由CSDN通过智能技术生成

watch 和 computed 和 methods 区别是什么?

computed

计算属性,在模板中双向绑定一些数据或表达式时,如果表达式过长,或逻辑更为复杂,就会变得臃肿,难以维护和阅读

<div>
  {{text.split(',').reverse().join(',')}}
</div>

这里表达式包含3个操作,遇到复杂的逻辑时应该使用计算属性

所有的计算属性都以函数的形式写在 Vue 实例内的 computed 选项中,最终返回计算后的结果

计算属性可以依赖多个 Vue 实例的数据,只要其中任一数据变化,计算属性就会重新执行,视图也会更新,也可以依赖其他计算属性

上述例子,利用了 getter 来读取,当手动修改计算属性的值时,就会触发 setter 函数,执行一些操作

methods vs computed

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

在页面中调用方法,只要页面重新渲染,方法就会重新执行,不需要渲染,则不需要重新执行

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

计算属性是基于它的依赖缓存的,一个计算属性所依赖的数据发生变化时,它才会重新取值,所以 text 只要不改变,计算属性也就不更新

使用场景

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

watch

监听器,侦听一个特定的值,若该值发生变化时执行对应的函数,例如分页组件中,我们可以监听当前页码,当页码变化时执行对应的获取数据的函数。

和computed 的区别:

都是在依赖的值变化之后,去执行回调,

  1. 如果一个值依赖多个属性(多对一),用computed更加方便一些,如果一个值变化后会引起一系列操作,或者一个值的变化会引起一系列值得变化(一对多),用 watch 更加方便一些。
  2. watch的回调里面会传入监听属性的新旧值,通过这两个值可以做一些特定的操作。computed通常就是简单的计算。

有哪些生命周期钩子函数?分别有什么用?

在不同阶段被调用

beforeCreated()

第一个生命周期钩子,在 Vue 实例初始化后,创建组件前,立即被调用,(尚未设置计算属性,观察者,事件,数据属性和操作等内容)

created()

第二个生命周期钩子,在这个阶段,已经设置了计算属性,观察者,事件,数据属性和操作,但 Vue 实例尚未挂载到页面上

beforeMount()

这是在 DOM 上挂载实例之前的那一刻,模板已经编译(data 中的数据和模板生成 html),但无法操作 DOM

mounted()

挂载完成后(模板渲染到了页面中),请求数据一般也在这里进行,DOM 的操作放在这里

beforeUpdate()

数据更新前调用

updated()

当数据发生改变后,被调用

beforeDestroy()

在 Vue 实例被销毁之前,被调用

destroyed()

这是最后一个生命周期钩子,所有的子 Vue 实例都已经被销毁。

Vue 数据响应式(双向绑定)怎么做到的

使用Object.defineProperty把属性全部转为getter/setter ,受现代 JavaScript 的限制 (而且Object.observe也已经被废弃),Vue无法检测到对象属性的添加或删除,使用vm.$set,这也是全局Vue.set方法的别名 来解决

this.$set(this.someObject,'b',2)

如何实现组件间通信?

父子组件:使用 props 传递数据

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

这里涉及到 单向数据流 的概念,通过 props 传递数据是单向的,父组件中数据变化时会传递给子组件,但是反过来不行,其目的是解耦,避免子组件无意中修改了父组件的状态

父组件传递初始值进来,子组件将它作为初始值保存进来,在自己的作用域下可以随意使用和修改,这种情况可以在组件 data 内再声明一个数据,引用父组件的 prop

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

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

子组件用 $emit() 来触发事件,父组件用 $on() 来监听子组件的事件(利用了观察者模式)

  1. 自定义事件
  2. 在子组件中用 $emit() 来触发事件,第一个参数是事件名,后面的参数是要传递的数据
  3. 在自定义事件中用一个参数来接收
//模板
<div id="app">
  <p>您的余额是{{total}}</p>
  <btn-component @change="handleTotal"></btn-component>
</div>

//逻辑
var app = new Vue({
    el: '#app',
    data: {
      total: 0
    },
    components: {
      'btn-component': {
        template: '<div>
          <button @click="handleIncrease">+1</button> 
          <button @click="handleReduce">-1</button> 
        </div>',
        data: function() {
          return {
            count: 0
          }
        },
        methods: {
          handleIncrease: function() {
            this.count++
            //触发 change 对应的方法,this.count 为参数
            this.$emit('change',this.count)
          },
          handleReduce: function() {
            this.count--
            this.$emit('change',this.count)
          }
        }
      }
    },
    methods: {
      //参数 total 为 传递过来的 this.count
      handleTotal: function(total) {
        this.total = total
      }
    }
  })

非父组件间的通信

使用 bus = new Vue() 来通信,eventBus.$on 和 eventBus.$emit 是主要API

根组件创建 bus

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

子组件

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

使用 Vuex 通信

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

获取状态

  1. 引入 vuex, 并通过 use 方法使用它
  2. 创建状态仓库
  3. 通过 this.$store.state.xxx 直接拿到需要的数据
   import Vuex from 'vuex'
   Vue.use(Vuex) 
   //创建状态仓库
    var store = new Vuex.Store({
      state: {
        XXX: xxx
      }
    })
    //直接通过 this.$store.state.xxx 拿到全局状态

改变状态

  1. 通过 mutations
    //创建状态仓库
    var store = new Vuex.Store({
      state: {
        XXX: xxx
      },
      mutations: {
        //定义状态改变函数,直接改变 state
        a: function (state) {
          //xxxx
        }
      }
    })
    //调用改变状态的函数
    //this.$store.commit('a')

2. 通过 actions

actions 提交的是 mutation, 而不是直接变更状态

    //创建状态仓库
    var store = new Vuex.Store({
      state: {
        XXX: xxx
      },
      mutations: {
        //定义状态改变函数,直接改变 state
        a: function (state) {
          //xxxx
        }
      },
      actions: {
        b: function (context) {
          //只能对 mutation 进行操作
          context.commit('a')
        }
      }
    })
    //调用 actions 中的方法
    //this.$store.dispatch('b')

为啥要用 actions 呢

actions 中可以包含异步操作,但是 mutation 中只能包含同步操作

3. getters

对数据进行处理(点击数据减少,最小为0)

      ...
      getters: {
        c(state) {
          //对 state 中的数据做处理(最小为0,不能为负数)
        }
      }
    //调用 getters 中的方法
    //this.$store.getters.c

VueRouter 怎么使用

Vue Router 是 Vue.js 官方的路由管理器

History 模式

这种模式充分利用history.pushStateAPI 来完成 URL 跳转而无须重新加载页面。

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

当你使用 history 模式时,URL 就像正常的 url,例如http://yoursite.com/user/id,也好看!

导航/路由守卫

https://zhuanlan.zhihu.com/p/59889754

https://www.jianshu.com/p/dcf5ce5f3ed7

场景:有些页面必须要登录才能操作,例如登录状态下才能编辑/创建博客

路由元信息,配置路由时,加一个 meta以及导航守卫去控制路由对应组件的入口,

路由懒加载

常用API

router-link: 支持用户在具有路由功能的应用中 (点击) 导航,通过to属性指定目标地址

router-view: <router-view>组件是一个 functional 组件,渲染路径匹配到的视图组件

this.$router.push:

  • 想要导航到不同的 URL,使用这个方法,这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。
  • 当你点击<router-link>(声明式)时,这个方法会在内部调用,所以说,点击<router-link :to="...">等同于调用router.push(...)(编程式)。

this.$router.replace: 跟router.push很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。

this.$route.params:获取到路径路径参数及所对应的值({路径参数:值})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值