vue之other

2019-06-06  本文已影响0人  一条IT

Vuex

Vuex是vue官方的一款状态管理工具,什么是状态呢?我们在前端开发中有一个概念:数据驱动,页面中任意的显示不同,都应该有一条数据来控制,而这条数据又叫做state,状态。

在vue中。组件间进行数据传递、通信很频繁,而父子组件和非父子组件的通信功能也比较完善,但是,唯一困难的就是多组件间的数据共享,这个问题由vuex来处理

vue提供的一个全局的状态管理工具,主要处理项目中多组件间状态共享

Vuex的使用:
  1. 创建store:
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)


  1. 设置state

state就是一个纯对象,上面有一些状态挂载

import state from './state'
//可以设置store管理的state/getter,mutations,actions
const store = new Vuex.Store({
    state
})
  1. 在根实例里配置store

这样,我们就可以在任意的组件中通过this.$store来使用关于store的api

import store from './store'
new Vue({
  el: '#app',
  router,
  store,
  template: '<App/>',
  components: { App }
})
  1. 在组件中使用state

因为在组件中可以通过this.来访问所以我们也可以通过store来访问store,所以我们也可以通过this.store.state来使用state中管理的数据

 data(){
    return {
        num:this.$store.state.num
    }
},

但是我们发现,这样使用的话,当state的数据更改的时候,vue组件并不会重新渲染

也就是说,如果想要在组件中响应式的使用的时候,我们需要通过计算属性(computed)来使用

computed:{
    num(){
        return this.$store.state.num
    }
}

这样的写法很无趣,而且如果使用的状态较多会产生冗余的感觉,所以vuex提供了mapState辅助函数,帮助我们在组件中获取并使用vuex的store中保存的状态

所以我们可以这样写:

computed:mapState(['num']),

但是如果组件中已经有了num这个数据了,而state中的数据名字也叫num就会照成冲突,这个时候我们可以在组件使用state的时候,给状态起个别名:

computed:mapState({
    // _num:'num',//键名为别名,值字符串代表的是真正的状态
    _num(state){//方法名为别名,函数体里还可以对真正的状态做出一些处理
        return state.num
    } //简写为  _num:state=>state.num
}),

但是,有的时候我们在组件中还有自己的业务逻辑需要用到计算属性:

computed:{
    a(){
        return num+1
    },
    ...mapState({
        // _num:'num',//键名为别名,值字符串代表的是真正的状态
        _num(state){//方法名为别名,函数体里还可以对真正的状态做出一些处理
            return state.num
        }
    }),
},
  1. getters

有的时候,我们需要根据state中的某一个状态派生出一个新的状态,例如,我们state中有一个num,在某些组件中需要用到是num的二倍的一个状态,我们就可以通过getters来创建

const getters = {
    doubleNum(state){
        return state.num*2
    }
}

computed:{
    ...mapGetters(["doubleNum"])
}

创建了之后,在组件中通过this.$store.getters.doubleNum来获取里面的数据

当然vuex也提供了mapGetters辅助函数来帮助我们在组件中使用getters里的状态,且,使用的方法和mapState一模一样

  1. 使用mutations更改state

我们不能直接在组件中更改state:this.$store.state.num=2,而是需要使用mutations来更改,mutations也是一个纯对象,里面包含很多更改state 的方法,这些方法的形参接收到state,在函数体里更改,这时,组件用到的数据也会更改,实现响应式。

但是我们也不能直接调用mutations 的方法,需要使用this.$store.commit来调用,第一个参数为调用的方法名,第二げ参数为传递参数

const mutations = {
    increment(state){
        state.num++
    }
}

vuex提供了mapMutations方法来帮助我们在组件中调用mutations 的方法,使用方法和mapState、mapGetters一样

  1. 使用actions来处理异步操作

Action 类似于 mutation,不同在于:

Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。

也就是说,如果有这样的需求:在一个异步处理之后,更改状态,我们在组件中应该先调用actions,来进行异步动作,然后由actions调用mutation来更改数据

const actions = {
    getNumFromBackEnd({commit}){
        setTimeout(() => {
            let num = Math.floor(Math.random()*10)
            //调用mutations的方法
            commit(CHANGE_NUM,num)
        }, 1000);
    }
}

如上,actions的方法中可以进行异步的动作,且形参会接收store,从中取出commit方法用以调用mutations的方法

在组件中通过this.$store.dispatch方法调用actions的方法

当然也可以使用mapMutations来辅助使用

组件使用数据且通过异步动作更改数据的一系列事情:

1.生成store,设置state
2.在根实例中注入store
3.组件通过计算属性或者mapState来使用状态
4.用户产生操作,调用actions的方法,然后进行异步动作
5.异步动作之后,通过commit调用mutations的方法
6.mutations方法被调用后,更改state
7.state中的数据更新之后,计算属性重新执行来更改在页面中使用的状态
8.组件状态被更改...创建新的虚拟dom......
9.组件的模板更新之后重新渲染在dom中

vuex的使用:
目前市场上有两种使用vuex的情况,

第一种:将需要共享、需要管理的状态放入vuex中管理,也就是说在必要时使用

第二种:将所有的数据都交由vuex管理,由vuex来承担更多的责任,组件变得更轻量级,视图层更轻


自定义指令

在实现回到顶部功能的时候,我们写了一个backTop组件,接下来需要通过监听window.scroll事件来控制这个组件显示隐藏

写了一个v-back-top指令,就是将回到顶部功能做成一个指令,哪个组件或者dom需要使用到回到顶部,就加上这个指令就可以,设置不同的参数来控制在不同的情况下触发

Vue的组件库

组件库就是通用组件的集合

pc:element-ui iview

mobile: mint-ui

nextTick

当我们在使用一些插件的时候,经常需要在dom更新完成后进行必要操作,但是在vue中提供的api只有updated钩子函数,而在这个函数里,任意数据的变化导致的dom更新完成都会触发,所以很可能会造成无关数据的影响,而使用监听的话只能监听到数据的变化,此时dom还没有更新,我们只能强行使用setTimeout来处理

这里推荐大家使用nextTick全局方法:
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

eq:
getBillBoards(){
    axios.get(this.$root.config.host+'mz/v4/api/billboard/home',{
        params:{__t:Date.now()}
    }).then(res => {
        console.log(res.data.data.billboards)
        this.billboards = res.data.data.billboards

        //当数据更新,dom循环完成后,执行回调
        Vue.nextTick(function () {
            new Swiper('.app-home-banner',{
                loop:true
            }) 
        })
    })
}

Vue试题分析

  1. v-for可以实现数据遍历显示,不仅可以遍历数组,也可以遍历对象,还可以从数值中取值:

v-for='n in 10' n会打印1-10

  1. vue的生命周期钩子:

通用:beforeCreate/created/beforeMount/mounted/beforeUpdate/updated/beforeDestroy/destroyed

路由守卫:beforeRouteEnter/beforeRouteUpdate (2.2 新增)/beforeRouteLeave

  1. v-if v-show

v-if是真正的条件渲染,会确保在切换中条件块内的事件监听、子组件都会适当的被销毁和重建

v-show总是将节点渲染在dom中,只是基于css:display来控制节点的显示和隐藏

v-if有更高的切换开始,v-show有更高的初始渲染开销

v-if是惰性的,初始条件为假,就不会渲染

  1. axios相关

axios请求的时候不会带上cookie,不会影响带宽,可以通过withCredentials:true来设置

对axios 的请求头进行设置:

axios.defaults.headers = {'Content-Type':'...'}

vue2.0不在更新维护vue-resource,官方推荐使用axios

  1. 组件实例的作用域是孤立的,意味着不能(不应该)在子组件模板里直接引用父组件的数据,要让子组件使用父组件数据的话,需要通过props来将父组件的数据传递给子组件,子组件不能也不应该修改父组件传入的数据,但是可以通过传入引用类型的数据来实现数据共享

6.为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为内容分发 (即 Angular 用户熟知的“transclusion”)。Vue.js 实现了一个内容分发 API,参照了当前 Web Components 规范草案,使用特殊的 <slot> 元素作为原始内容的插槽。

a-template:

<p>hello world</p>
<b>
    <h1>hello world</h1>
</b>

b-template:

<slot></slot>

  1. 注册方式:

全局:Vue.component(name,Vue.extend({}))

局部:{ components:{name:Vue.extend({})} }

  1. 事件总线实现非父子组件通信
//创建bus

let bus = new Vue()

//a

new Vue({
    template:'...',
    mounted(){
        bus.$on('emit-a',function(){
            alert(1)
        })
    }
})

//b

new Vue({
    template:'...',
    methods:{
        emitA(){
            bus.$emit('emit-a')
        }
    }
})
//当b组件的emitA方法被调用的时候,A组件就会执行alert(1)
  1. methods和计算属性的区别

假设我们有一个数据为num,还希望拥有一个数据为doublenum,而且希望doublenum的值永远都是num的二倍

方法:

* 因为是直接显示在模板中,也就是说,我们可以来一个doublenum的方法,这个方法返回num的二倍,将这个方法放到模板中的某个地方执行 {{doublenum()}}
  但是,当无关的例如一个str的数据更改的时候,组件会重新创建虚拟dom树,与上一次的虚拟dom树对比之后重新渲染,这个时候在重新渲染模板的时候doublenum函数会被再次的调用,造成不必要的性能浪费
  
* 创建一个doublenum数据,使其初始值为num的二倍,然后利用watch来监听这两个数据,在改变的时候更改对应的数据,但是需要初始的为doublenum赋值为num的二倍,如果num是动态获取到的,doublenun赋值会更繁琐

* computed计算数据,我们可以利用computed来创建一条新的doublenum数据。并且设置它的getter和setter,并与num建立关系,且computed会缓存,在重新渲染的时候,不会重新执行getter和setter
    computed:{
        doublenum:{
            get(){
                return this.num*2
            },
            set(val){
                this.num = val/2
            }
        }
    }
  1. 绑定class的对象语法和数组语法
<a :class="{a:true,b:false,c:1}"> => </a> => <a class='a c'></a>
    
data(){
    return {
        c:'c'
    }
}
<a :class = '["a","b",c]'></a> => </a> => <a class='a b c'></a>
  1. 单向数据流

prop是单向绑定的,父组件属性变化,传递给子组件,但是,子组件数据变化,不能直接传递给父组件,也就是数据的流行是从父组件流向子组件的,为了防止子组件修改父组件的数据(会让应用的数据流变的更难开发、更新、维护)

使用了vuex工具的时候,store中数据在组件中使用的过程也是单向数据流,state->vue component->actions->mutations->state->vue component

  1. this.$router.push/replace({name:'user',params:{userId:1})

    this.$router.push/replace({path:'/register',query:{plan:private})

key相关

当数据改变之后,vue会创建新的虚拟dom来和原来的虚拟dom做对比,在创建新的虚拟的dom的时候,会根据key来查找在原来的虚拟dom中有没有某个部分,如果原来的有,这次的也需要,就会实现复用,而且在做diff对比的时候,如果有key会加快对比的查找速度,提高性能

尽量循环的时候不要将key设置为数组的索引,因为当删除某一个元素的时候,就会导致删除位置下面的所有元素的key值都与上一次虚拟dom的key值不同,导致复用失败,这个时候我们最好使用关键的唯一的,例如id这样的数据作为key

如果数据变化只是值的变化而不是条数和位置的变化,可以使用索引作为key

Vue.use()

Vue.use会查找插件对象里的install方法去执行,并且给install方法里传入Vue对象


var a = {
    install(Vue){
        Vue.component("my-a",{...})
    }
}

Vue.use(a)

进入域后根据不同的情况显示不同的页面(PC/MOBILE)

很多情况下,一个应用会有PC和移动端两个版本,而这两个版本因为差别大,内容多,所以不能用响应式开发但是单独开发,而域名只有一个,用户进入域后直接返回对应设备的应用,做法主要有两种:

  1. 前端判断并跳转

    进入一个应用或者一个空白页面后,通过navigator.userAgent来判断用户访问的设备类型,进行跳转

  2. 后端判断并响应对应的应用

    用户地址栏进入域的时候,服务器能接收到请求头上包含的userAgent信息,判断之后返回对应应用

上一篇下一篇

猜你喜欢

热点阅读