Vue规模化——vue-router、vuex

一、路由vue-router

后端路由:对于普通的网站,所有的超链接都是URL地址,URL地址对应服务器上的资源;
前端路由:对於单页面应用程序,主要通过URL中的hash(#)来实现页面跳转,HTTP请求中不会包含hash相关的内容。

插件下载:https://github.com/vuejs/vue-routerhttps://unpkg.com/vue-router/dist/vue-router.js

在Vue后面加载vue-router,它会自动安装。

<script src="lib/vue.js"></script>
<script src="lib/vue-router.js"></script>

1、路由的基本使用

<div id="app">
  <!-- 点击a链接,修改url地址,Vue实例上的router监听到url地址的改变,展示对应组件 -->
  <!-- <a href="#/foo">Go To Foo</a> -->
  <!-- <a href="#/bar">Go To Bar</a> -->
  
  <!-- <router-link>默认会被渲染成一个<a>标签,通过传入to属性指定链接地址 -->
  <router-link to="/foo">Go To Foo</router-link>
  <router-link to="/bar">Go To Bar</router-link>
  
  <!-- 路由出口,路由匹配到的组件将渲染在这里 -->
  <router-view></router-view>
</div>

<script>
  // 1.定义(路由)组件
  const Foo={template:'<div>foo</div>'};
  const Bar={template:'<div>bar</div>'};

  // 2.定义路由
  // path:监听的路由链接地址。component:要展示的组件,是一个模板对象,不能是组件名
  const routes=[
    {path:'/foo',component:Foo},
    {path:'/bar',component:Bar}
  ];

  // 3.创建router实例,配置路由
  const router=new VueRouter({
    routes // 相当于routes:routes
  });

  // 4.创建Vue实例,注册路由
  const vm=new Vue({
    el:'#app',
    router // 注册路由,监听url地址的变化,展示对应组件
  });
</script>

2、重定向和别名

重定向:当用户访问/a时,url将会被替换成/b,然后匹配路由为/b,如用于使根路径重定向为显示某个组件。重定向通过routes配置来完成。

const routes=[
  {path:'/',redirect:'/foo'}, // 重定向
  {path:'/foo',component:Foo}
];

别名:/a的别名是/b意味着,当用户访问/b时,url保持为/b,但路由匹配为/a,和访问/a一样。 

const routes=[
  {path:'/a',component:A,alias:'/b'}
];

3、<router-link>

tag:使用tag属性指定router-link渲染的标签类型,默认值'a'。还是会监听点击,触发导航。

linkActiveClass:这是路由构造函数中的选项,设置链接激活时使用的CSS类名,默认值"router-link-active"。通过该类名可设置路由高亮的样式。

4、编程式导航

除了使用<router-link>创建a标签来定义导航链接,还可以借助router的实例方法,通过编写代码来实现。

想要导航到不同的URL,使用router.push方法(在Vue实例内部使用this.$router.push),点击<router-link>时,该方法会在内部调用。

router.push('home') // 字符串

router.push({path:'home'}) // 对象

router.push({name:'user',params:{userId:123}}) // 命名的路由

router.push({path:'register',query:{plan:'private'}}) // 带查询参数,变成 /register?plan=private

router.push方法会向history栈添加一个新的记录,当用户点击浏览器后退按钮时,则回到之前的URL。 

router.go(n)方法的参数是一个整数,表示在history记录中向前或者后退多少步,类似window.history.go(n)。

5、路由组件传参

(1)? & $route.query

使用查询字符串给路由传递参数,不需要修改路由规则的path属性。

<router-link to="/foo?id=10&name=cong">Go To Foo</router-link>
const foo={
  template:'<div>Foo--{{$route.query.id}}--{{$route.query.name}}</div>',
  created(){
    console.log(this.$route.query.id);
  }
}

(2)/ : $route.params

<router-link to="/foo/10/cong">Go To Foo</router-link>
const foo={
  template:'<div>Foo--{{$route.params.id}}--{{$route.params.name}}</div>',
  created(){
    console.log(this.$route.params.id);
  }
}
const routes=[
  {path:'/foo/:id/:name',component:foo}
];

 (3)props

6、嵌套路由

<div id="app">
  <router-link to="/user">User</router-link>
  <router-view></router-view>
</div>

<template id="user">
  <div>
    <h3>最高级路由</h3>
    <router-link to="/user/profile">Profile</router-link> <!-- 嵌套<router-link> -->
    <router-view></router-view>                           <!-- 嵌套<router-view> -->
  </div>
</template>
<script>
  const User={
    template:'#user'
  };

  const Profile={ // 嵌套路由的组件
    template:'<div>被嵌套的路由</div>'
  };

  const router=new VueRouter({
    routes:[
      {
        path:'/user',
        component:User,
        children:[ // 用children定义嵌套路由
          {path:'profile',component:Profile} // 没有/,以/开头的嵌套路径会被当作根路径
        ]
      }
    ]
  });

  const vm=new Vue({
    el:'#app',
    router
  });
</script>

7、命名视图

有时想同级展示多个视图,而不是嵌套展示。可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果router-view没有设置名字,默认为default。

一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。使用components配置(带上s)。

<div id="app">
  <router-view></router-view>
  <router-view name="left"></router-view>
  <router-view name="main"></router-view>
</div>
<script>
  const router=new VueRouter({
    routes:[
      {path:'/',components:{
        default:header,
        left:leftBox,
        main:mainBox
        }
      }
    ]
  });
</script>

二、状态管理vuex

中文官网:https://vuex.vuejs.org/zh/   GitHub:https://github.com/vuejs/vuex

1、状态管理模式

Vuex是一个专为Vue.js应用程序开发的状态管理模式(公共数据管理工具)。它采用集中式存储管理应用的所有组件的状态(共享的数据),并以相应的规则保证状态以一种可预测的方式发生变化(整个程序中的任何组件直接获取或修改公共数据)。

// 组件
new Vue({
  // state
  data(){
    return {
      count:0
    }
  },
  // view
  template:`<div>{{count}}</div>`,
  // actions
  methods:{
    increment(){
      this.count++
    }
  }
})

状态自管理应用(组件)包含:state,驱动应用的数据源;view,以声明方式将state映射到视图;actions,响应在view上的用户输入导致的状态变化。但是,当应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏,如多个视图依赖于同一状态(传参繁琐)、来自不同视图的行为需要变更同一状态。

把组件的共享状态抽取出来,以一个全局单例模式管理,任何组件都能获取状态或者触发行为。

虽然Vuex可以帮助管理共享状态,但也附带了更多的概念和框架。如果不打算开发大型单页应用,使用Vuex可能是繁琐冗余的,一个简单的store模式就足够了。但如果需要构建一个中大型单页应用,更好地在组件外部管理状态则需要Vuex 。

2、安装与创建store

在Vue之后引入vuex会进行自动安装。

Vuex依赖Promise,如果浏览器并没有实现Promise(如IE),可以使用一个polyfill的库(es6-promise),可以通过CDN将其引入,之后window.Promise会自动可用。

<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>

<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"></script>

每一个Vuex应用的核心是store(仓库),基本上是一个容器,包含着应用中大部分的状态 (state)。Vuex使用单一状态树,用一个对象就包含了全部的应用层级状态,作为一个“唯一数据源 (SSOT)”而存在。每个应用仅包含一个store实例。

Vuex和单纯的全局对象不同,vuex的状态存储是响应式的,若store中的状态发生变化,相应的组件也会得到高效更新;改变store中的状态的唯一途径是显式地提交(commit)mutation,为了更明确地追踪到状态的变化。

创建一个store,仅提供一个初始state对象和一些mutation、getters。

在根实例中注册store选项,可将状态从根组件注入到每一个子组件中(需调用Vue.use(Vuex)),子组件通过this.$store访问。

const store=new Vuex.Store({
  state:{
    count:0
  },
  mutations:{
    increment(state){
      state.count++
    }
  },
  getters:{
    optCount:state=>{
      return 'count值是:'+state.count
    }
  }
})

const vm=new Vue({
  el:"#app",
  store // 将store挂载到vm实例,任何组件都可以使用store存储访问数据
})

console.log(store.state.count);
store.commit('increment')
console.log(store.getters.optCount);

3、核心概念

(1)state

store.state获取状态对象。由于store中的状态是响应式的,在组件中调用store中的状态仅需要在计算属性中返回即可,当然也可以用在函数中,等。

mapState辅助函数:用于一个组件获取多个状态,可省略store。单独构建的版本中辅助函数为Vuex.mapState。

import {mapState} from 'vuex'

export default{
  computed:mapState({
    count:state=>state.count,
    // 简写为count:'count'
    // 简写为'count' 计算属性名称与state的子节点名称相同时,给mapState传一个字符串即可
    // 传字符串参数 'count' 等同于 `state => state.count`

    // 为了使用this获取局部状态,必须使用常规函数,不能简写
    countPlusLocalState(state){
      return state.count+this.localCount
    }
  })
}

对象展开运算符:mapState函数返回的是一个对象,如果需要与局部计算属性混合使用,可使用对象展开运算符。

computed:{
  localComputed(){},
  ...mapState({ // 使用对象展开运算符将此对象混入到外部对象中
    // ...
  })
}

(2)mutation

mutation非常类似于事件,每个mutation都有一个字符串的事件类型和一个回调函数。回调函数进行状态更改,接受state作为第一个参数。第二个参数可选,是mutation的载荷,应该是一个对象,可以包含多个字段且更易读。

store.commit('事件类型')方法触发状态变更。

store.commit('increment',{ // 方式1
  amount:10
})
store.commit({ // 方式2
  type:'increment',
  amount:10
})

(3)getter

在store中定义getter,可以认为是store的计算属性,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

Getter接受state作为其第一个参数,可以接受其它getter作为第二个参数。

通过store.getters对象,可以以属性的形式访问这些值,作为Vue的响应式系统的一部分缓存其中。在对store里的数组进行查询时,也可以通过让getter返回一个函数实现给getter传参,通过方法访问时,每次都会去进行调用,而不会缓存结果。

getters:{
  // ...
  getTodoById:(state)=>(id)=>{
    return state.todos.find(todo=>todo.id===id)
  }
}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

(4)action

(5)module 

三、服务端渲染

待更新。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章