vue项目细节解读

1.典型组件模板




2.路由

/user/foo /user/foo/profile /user/foo/posts

const User = { template: `

User {{ $route.params.id }}

` } const UserHome = { template: '
Home
' } const UserProfile = { template: '
Profile
' } const UserPosts = { template: '
Posts
' } const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ // UserHome will be rendered inside User's // when /user/:id is matched { path: '', component: UserHome }, // UserProfile will be rendered inside User's // when /user/:id/profile is matched { path: 'profile', component: UserProfile }, // UserPosts will be rendered inside User's // when /user/:id/posts is matched { path: 'posts', component: UserPosts } ] } ] })
Paste_Image.png

页面跳转

// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})

(同级)展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar(侧导航) 和main(主内容) 两个视图,这个时候命名视图就派上用场了




Named Views

  • /
  • /other
const Foo = { template: '
foo
' } const Bar = { template: '
bar
' } const Baz = { template: '
baz
' } const router = new VueRouter({ mode: 'history', routes: [ { path: '/', // a single route can define multiple named components // which will be rendered into s with corresponding names. components: { default: Foo, a: Bar, b: Baz } }, { path: '/other', components: { default: Baz, a: Bar, b: Foo } } ] }) new Vue({ router, el: '#app' })

导航钩子
(1)全局钩子

const router = new VueRouter({ ... })

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

每个钩子方法接收三个参数:
**to: Route
**: 即将要进入的目标 路由对象

**from: Route
**: 当前导航正要离开的路由

**next: Function
**: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next
方法的调用参数。

**next()
**: 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 **confirmed** 
(确认的)。

**next(false)
**: 中断当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),
那么 URL 地址会重置到 from 路由对应的地址。

**next('/')
 或者 next({ path: '/' })
**: 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。

(2)某个路由独享的钩子
你可以在路由配置上直接定义 beforeEnter 钩子:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

(3)组件内的钩子
最后,你可以使用 beforeRouteEnter 和 beforeRouteLeave,在路由组件内直接定义路由导航钩子,

const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) => {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当钩子执行前,组件实例还没被创建
  },
  beforeRouteLeave (to, from, next) => {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}

beforeRouteEnter 钩子 不能 访问 this,因为钩子在导航确认前被调用,因此即将登场的新组件还没被创建。
不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。

beforeRouteEnter (to, from, next) => {
  next(vm => {
    // 通过 `vm` 访问组件实例
  })
}

可以 在 beforeRouteLeave 中直接访问 this。这个 leave 钩子通常用来禁止用户在还未保存修改前突然离开。可以通过 next(false) 来取消导航。

路由元信息,用于登录验证

定义路由的时候可以配置 meta 字段:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      children: [
        {
          path: 'bar',
          component: Bar,
          // a meta field
          meta: { requiresAuth: true }
        }
      ]
    }
  ]
})

下面例子展示在全局导航钩子中检查 meta 字段:

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    // this route requires auth, check if logged in
    // if not, redirect to login page.
    if (!auth.loggedIn()) {
      next({
        path: '/login',
        query: { redirect: to.fullPath }
      })
    } else {
      next()
    }
  } else {
    next() // 确保一定要调用 next()
  }
})

动态路由的一个demo

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const Home = {
  template: `
    

Home

hello

` } const Parent = { data () { return { transitionName: 'slide-left' } }, // dynamically set transition based on route change watch: { '$route' (to, from) { const toDepth = to.path.split('/').length const fromDepth = from.path.split('/').length this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left' } }, template: `

Parent

` } const Default = { template: '
default
' } const Foo = { template: '
foo
' } const Bar = { template: '
bar
' } const router = new VueRouter({ mode: 'history', base: __dirname, routes: [ { path: '/', component: Home }, { path: '/parent', component: Parent, children: [ { path: '', component: Default }, { path: 'foo', component: Foo }, { path: 'bar', component: Bar } ] } ] }) new Vue({ router, template: `

Transitions

  • /
  • /parent
  • /parent/foo
  • /parent/bar
` }).$mount('#app')

假设我们有一个 Post 组件,需要基于 $route.params.id 获取文章数据:
导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示『加载中』之类的指示。

导航完成之前获取:导航完成前,在路由的 enter
钩子中获取数据,在数据获取成功后执行导航。


export default {
  data () {
    return {
      loading: false,
      post: null,
      error: null
    }
  },
  created () {
    // 组件创建完后获取数据,
    // 此时 data 已经被 observed 了
    this.fetchData()
  },
  watch: {
    // 如果路由有变化,会再次执行该方法
    '$route': 'fetchData'
  },
  methods: {
    fetchData () {
      this.error = this.post = null
      this.loading = true
      // replace getPost with your data fetching util / API wrapper
      getPost(this.$route.params.id, (err, post) => {
        this.loading = false
        if (err) {
          this.error = err.toString()
        } else {
          this.post = post
        }
      })
    }
  }
}

在导航完成前获取数据

export default {
  data () {
    return {
      post: null,
      error: null
    }
  },
  beforeRouteEnter (to, from, next) {
    getPost(to.params.id, (err, post) => 
      if (err) {
        // display some global error message
        next(false)
      } else {
        next(vm => {
          vm.post = post
        })
      }
    })
  },
  // 路由改变前,组件就已经渲染完了
  // 逻辑稍稍不同
  watch: {
    $route () {
      this.post = null
      getPost(this.$route.params.id, (err, post) => {
        if (err) {
          this.error = err.toString()
        } else {
          this.post = post
        }
      })
    }
  }
}

路由信息对象的属性
$route.path
类型: string

字符串,对应当前路由的路径,总是解析为绝对路径,如 "/foo/bar"

$route.params
类型: Object

一个 key/value 对象,包含了 动态片段 和 全匹配片段,如果没有路由参数,就是一个空对象。

$route.query
类型: Object

一个 key/value 对象,表示 URL 查询参数。例如,对于路径 /foo?user=1
,则有$route.query.user == 1
,如果没有查询参数,则是个空对象。

$route.hash
类型: string

当前路由的 hash 值 (不带 #
) ,如果没有 hash 值,则为空字符串。

$route.fullPath
类型: string

完成解析后的 URL,包含查询参数和 hash 的完整路径。

$route.matched
类型: Array

一个数组,包含当前路由的所有嵌套路径片段的 路由记录 。路由记录就是 routes
配置数组中的对象副本(还有在 children
数组)。

const router = new VueRouter({
  routes: [
    // 下面的对象就是 route record
    { path: '/foo', component: Foo,
      children: [
        // 这也是个 route record
        { path: 'bar', component: Bar }
      ]
    }
  ]
})

当 URL 为 /foo/bar,$route.matched
将会是一个包含从上到下的所有对象(副本)。

$route.name
当前路由的名称,如果有的话。(查看 命名路由)

你可能感兴趣的:(vue项目细节解读)