IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Vue源码分析(状态管理&&路由) -> 正文阅读

[JavaScript知识库]Vue源码分析(状态管理&&路由)

状态管理

前端以前是没有状态管理的,直到Fackbook提出一个叫Flux的概念,才有了状态管理。

以前前端是通过MVC模式管理代码,但后来我们使用例如Vue、React、Angular这类通过声明式开发的框架,发现状态很难管理,容易出现状态被任意修改。当应用越来越大,这种不确定性会导致系统不稳定,而且定位bug也变得困难。

Vue2的状态管理使用的是vuex,在正常开发中,我们都知道应该做到低耦合,数据不应该在多组件间相互影响,因为这样会难以维护。但是如果项目中确实需要一批数据在多组件中进行操作,且会互相影响。我们就需要使用vuex

让我们来实现一个简单的vuex的mutation

简单的mutation

首先我们要知道的是,我们new一个Vue会自动产生响应式,接下来就可以进行vuex的编写了

// { state, mutations }解构
function createStore ({ state, mutations }) {
  return new Vue({
    data: {
      state
    },
    methods: {
        // 对commit传入mutations中定义好的函数进行调用
      commit (mutation) {
        if (!mutations.hasOwnProperty(mutation)) {
          throw new Error('Unknown mutation')
        }
          // 调用mutations中的函数
        mutations[mutation](state)
      }
    }
  })
}

实际上,上面的内容就是核心原理,接下来我们创建一个vuex实例

const store = createStore({
  state: { count: 0 },
  mutations: {
    inc (state) {
      state.count++
    }
  }
})

接下来使用即可

获取值

const Counter = {
  render (h) {
    return h('div', store.state.count)
  }
}

修改值

  methods: {
    inc () {
      store.commit('inc')
    }
  }

路由

在vue中我们经常会使用到路由,路由有hash和history两种模式,二者的实现思路基本相同,为了简便,我们以hash模式为例

监听路由变化的事件,修改data中的url,再通过动态组件变化,这样就实现了一个最基本的路由。

<div id="app">
  <component :is="url"></component>
  <a @click="routeTo('#foo')" href="#foo">foo</a>
  <a @click="routeTo('#bar')" href="#bar">bar</a>
</div>

<script>
window.addEventListener('hashchange', () => {
  app.url = window.location.hash.slice(1)
})

const app = new Vue({
  el: '#app',
  data: {
    url: 'foo'
  },
  components: {
    foo: { template: `<div>foo</div>`},
    bar: { template: `<div>bar</div>`},
  },
  methods: {
    routeTo (route) {
      window.location.hash = route
    }
  }
})
</script>

当然,上面的路由都是写死的,如何做一个可配置的路由呢

可配置路由

接收一个路由表routeTable,监听路由变化并修改vue实例中的url,使用计算属性得出当前的组件名,再动态显示

<div id="app">
  <component :is="matchedComponent"></component>
  <a href="#foo">foo</a>
  <a href="#bar">bar</a>
</div>

<script>
// '#/foo' -> Foo
// '#/bar' -> Bar
// '#/404' -> NotFound

const Foo = { template: `<div>foo</div>` }
const Bar = { template: `<div>bar</div>` }
const NotFound = { template: `<div>not found!</div>` }

const routeTable = {
  foo: Foo,
  bar: Bar
}

window.addEventListener('hashchange', () => {
  app.url = window.location.hash.slice(1)
})

const app = new Vue({
  el: '#app',
  data: {
    url: 'foo'
  },
  computed: {
    matchedComponent () {
      return routeTable[this.url] || NotFound
    }
  }
})
</script>

动态路由

我们使用第三方库path-to-regexp用于路由规则匹配

<script src="../node_modules/vue/dist/vue.js"></script>
<script src="./path-to-regexp.js"></script>

<div id="app"></div>

<script>
// '#/foo/123' -> foo with id: 123
// '#/bar' -> Bar
// '#/404' -> NotFound

// path-to-regexp usage:
// const regex = pathToRegexp(pattern)
// const match = regex.exec(path)

const Foo = {
  props: ['id'],
  template: `<div>foo with id: {{ id }}</div>`
}
const Bar = { template: `<div>bar</div>` }
const NotFound = { template: `<div>not found!</div>` }

const routeTable = {
  '/foo/:id': Foo,
  '/bar': Bar
}

const compiledRoutes = []
// 遍历路由表
Object.keys(routeTable).forEach(key => {
  const dynamicSegments = []
  const regex = pathToRegexp(key, dynamicSegments)
  const component = routeTable[key]
  // 存储组件信息、正则、动态参数
  compiledRoutes.push({
    component,
    regex,
    dynamicSegments
  })
})

window.addEventListener('hashchange', () => {
  app.url = window.location.hash.slice(1)
})

const app = new Vue({
  el: '#app',
  data: {
    url: window.location.hash.slice(1)
  },
  render (h) {
    const path = '/' + this.url

    let componentToRender
    let props = {}

    compiledRoutes.some(route => {
      const match = route.regex.exec(path)
      componentToRender = NotFound
      if (match) {
        componentToRender = route.component
        route.dynamicSegments.forEach((segment, index) => {
          props[segment.name] = match[index + 1]
        })
        return true
      }
    })

    return h('div', [
      h(componentToRender, { props }),
      h('a', { attrs: { href: '#foo/123' }}, 'foo 123'),
      ' | ',
      h('a', { attrs: { href: '#foo/234' }}, 'foo 234'),
      ' | ',
      h('a', { attrs: { href: '#bar' }}, 'bar'),
      ' | ',
      h('a', { attrs: { href: '#garbage' }}, 'garbage')
    ])
  }
})
</script>
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-08 20:32:10  更:2022-10-08 20:34:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 17:18:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码