loading...

1

vue爬坑之路-起航

其他读完大概需要53分钟

  • 发布时间:2017-08-06 13:31 星期日
  • 刘伟波
  • 425
  • 更新于2018-03-29 17:35 星期四

一 安装

1.cnpm install -g vue-cli

2.用vue-cli脚手架默认是生成vue 2.x的版本,但可以通过修改命令,来生成1.0的版本。

vue init webpack#1.0 my-project


npm install -g vue-cli                       //全局安装vue-cli
vue init webpack projectName        //生成项目名为projectName的模板,这里的项目名projectName随你自己写
cd projectName                              
npm install                                      //初始化安装依赖

这样子项目就安装完了。生成的项目下面的目录是这样的
Vue.js:使用vue-cli快速构建项目

然后执行

npm run dev                

在浏览器打开http://localhost:8080,则可以看到欢迎页了。



二 v-for

数组变化检测(Array Change Detection)

变化数组方法(Mutation Methods)

Vue 将观察数组(observed array)的变化数组方法(mutation method)包裹起来,以便在调用这些方法时,也能够触发视图更新。这些包裹的方法如下:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

可以打开控制台,然后对前面示例中的 items 数组调用变化数组方法。例如:example1.items.push({ message: 'Baz' })。

替换一个数组(Replacing an Array)

变化数组方法(mutation method),顾名思义,在调用后会改变原始数组。相比之下,还有非变化数组方法(non-mutating method),例如 filter(), concat() 和 slice(),这些方法都不会直接修改操作原始数组,而是返回一个新数组。当使用非变化数组方法时,可以直接将旧数组替换为新数组:

example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})

你可能会认为这将导致 Vue 丢弃现有 DOM 并重新渲染(re-render)整个列表 - 幸运的是,情况并非如此。Vue 实现了一些智能启发式方法(smart heuristic)来最大化 DOM 元素重用(reuse),因此将一个数组替换为包含重叠对象的另一个数组,会是一种非常高效的操作。

注意事项(Caveats)

由于 JavaScript 的限制,Vue 无法检测到以下数组变动:

  1. 当你使用索引直接设置一项时,例如 vm.items[indexOfItem] = newValue
  2. 当你修改数组长度时,例如 vm.items.length = newLength

为了解决第 1 个问题,以下两种方式都可以实现与 vm.items[indexOfItem] = newValue 相同的效果,但是却可以通过响应式系统出发状态更新:

// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice
example1.items.splice(indexOfItem, 1, newValue)

为了解决第 2 个问题,你可以使用 splice:

example1.items.splice(newLength)

https://www.vuefe.cn/v2/guide/list.html#数组变化检测-Array-Change-Detection


三 简写(shorkhands)

  

v-bind 简写

<!-- 完整语法 -->
<a v-bind:href="url"></a>
<!-- 简写 -->
<a :href="url"></a>

v-on 简写

<!-- 完整语法 -->
<a v-on:click="doSomething"></a>
<!-- 简写 -->
<a @click="doSomething"></a>


四 v-model

v-model


五 本地模拟线上数据

    ①

1.dev-server.js

const jsonServer = require('json-server')
const apiServer = jsonServer.create()
const apiRouter = jsonServer.router('db.json')
const middlewares = jsonServer.defaults()
apiServer.use(middlewares)
apiServer.use('/api', apiRouter)
apiServer.listen(port + 1, () => {
console.log('JSON Server is running')
})

2.config下的index

设置代理
proxyTable: {
'/api/': 'http://localhost:8081/'
},

3.前台页面调用路由

created () {
this.$http.post('api/getList',{userId:123})
.then(function (data) {
console.log(data)
},function (err) {
console.log(err)
})
},

4.访问

http://localhost:8080/api/getNewsList

var apiServer = express()
var bodyParser = require('body-parser')
apiServer.use(bodyParser.urlencoded({ extended: true }))
apiServer.use(bodyParser.json())
var apiRouter = express.Router()
var fs = require('fs')
apiRouter.route('/:apiName')
.all(function (req, res) {
fs.readFile('./db.json', 'utf8', function (err, data) {
if (err) throw err
var data = JSON.parse(data)
if (data[req.params.apiName]) {
res.json(data[req.params.apiName])
}
else {
res.send('no such api name')
}

})
})


apiServer.use('/api', apiRouter);
apiServer.listen(port + 1, function (err) {
if (err) {
console.log(err)
return
}
console.log('Listening at http://localhost:' + (port + 1) + '\n')
})


六 props $emit

①props子组件向父组件传递属性

props: {
slides: {
type: Array,//属性类型
default: [ { label:'test', value:0 } ] //属性默认值
},
inv: {
type: Number,
default: 1000
}
},

②$emit向父组件传递事件

methods: {
goto (index) {
this.isShow = false
setTimeout(() => {
this.isShow=true
this.nowIndex=index
this.$emit('onchange', index) //向父组件传递事件
},10)
},

③父组件调用

<slide-show :slides="slides" :inv="slideSpeed" @onchange="doSomethingSlideChange"></slide-show>
methods: {
doSomethingSlideChange (index) {
console.log("doSomethingSlideChange run!"+index); //拿到子组件传递来的参数
}
}


七 slot 插槽   $refs

弹窗一样内容不一样

import Dialog from './base/dialog.vue'
import LogForm from './logForm.vue'
import RegForm from './regForm.vue'
export default {
components:{MyDialog: Dialog,LogForm,RegForm},
<my-dialog :isShow="isShowLogDialog" @on-close="closeDialog('isShowLogDialog')">
<log-form @has-log="onSuccessLog"></log-form>
</my-dialog>
<my-dialog :isShow="isShowRegDialog" @on-close="closeDialog('isShowRegDialog')">
<reg-form></reg-form>
</my-dialog>
<my-dialog :isShow="isShowAboutDialog" @on-close="closeDialog('isShowAboutDialog')">
<p>本报的发展态势和面临的问题。报企事业单位和社会各界提供决策依据。</p>
</my-dialog>

这里在父组件演示了三个弹窗,两个组件(LogForm,RegForm)为插槽,但内容不同,组件里面的为插槽,子组件为

<transition name="drop">
<div class="dialog-content" v-if="isShow" >
<p class="dialog-close" @click="closeMyself">x</p>
<slot>empty</slot>
</div>
</transition>
methods: {
closeMyself () {
this.$emit('on-close')
}
}


refs    dom元素接口

<div class="slider-group" ref="sliderGroup">
<slot>
</slot>
</div>


this.$refs.sliderGroup  为当前dom元素                 
this.$refs.sliderGroup.children   他的子集


八 嵌套路由 children

main.js

{
path: '/detail',
component: DetailPage,
redirect:'/detail/analysis',
children: [
{
path: 'analysis',
component:DetailAnaPage
},
{
path: 'count',
component:DetailConPage
},
{
path: 'forecast',
component:DetailForPage
},
{
path: 'publish',
component:DetailPubPage
}
]
}

默认重定向'/detail/analysis',嵌套路由用children,不能有斜杠,要不然会回到主页面。


detail.vue

<img :src="productIcon">
<ul>
<router-link v-for="item in products"
:to="{path:item.path} " tag="li" active-class="active">
{{ item.name }}
</router-link>
</ul>

img不在遍历的范围内,要映射路由

export default {
data () {
return {
imgMap: {
'/detail/count': require("../assets/images/1.png"),
'/detail/forecast': require("../assets/images/2.png"),
'/detail/analysis': require("../assets/images/3.png"),
'/detail/publish': require("../assets/images/4.png")
}
}
},
computed: {
productIcon () {
return this.imgMap[this.$route.path]
}
}
}


九 watch mounted


子组件通过input框的动态数据监听,并且发送监听事件和参数

watch:{
number () {
this.$emit('on-change',this.number)
}
},


父组件通过绑定on-change事件处理数据和参数$event

$event就是val的值,第一个参数给默认值赋值


<v-mul-chooser :selections="versionList" @on-change="onParamChange('versions', $event)"></v-mul-chooser>



onParamChange (attr, val) {
this[attr] = val
this.getPrice()
},


mouted页面加载完成发送一次服务器请求

getPrice () {
let reqParams = {
buyNumber: this.buyNum,
buyType: this.buyType.value,
period: this.period.value,
version: this.versions.join(',')
}
this.$http.post('/api/getPrice', reqParams)
.then((res) => {
this.price = res.data.amount
console.log(reqParams )
})
}


十 内部通过点击的方法进入其他路由


toOrderList () {
this.$router.push({path:'/orderList'})
}


十一  非父子组件通信


新建eventBus.js

import Vue from 'vue'

const eventBus =new Vue()

export { eventBus }


全局layout.vue文件

<template>
<div @click="resetComponent">


import {eventBus } from '../eventBus'



resetComponent () {
eventBus.$emit('reset-component')
}


selection组件


import {eventBus} from '../../eventBus'



mounted(){
eventBus.$on('reset-component',()=>{
this.isDrop=false
})
},

https://www.vuefe.cn/v2/guide/components.html#非父子组件通信-Non-Parent-Child-Communication


十二  vuejs的.vue文件中的style标签中的css样式,背景图路径不对


如果你用了vue-cil,那么在build目录下找到utils.js中的ExtractTextPlugin.extract({}),里面添加下面这个属性就完美解决了publicPath: '../../',

输出空白页:conf文件夹下index build 添加一个点    assetsPublicPath: './',

style 也可以引入文件 添加scoped

<style src="../../static/css/flexslider.css" ></style>
<style src="../../static/css/index.css" scoped></style>


十三  代理跨域解决

proxyTable: { '/list': { target: 'http://api.xxxxxxxx.com', changeOrigin: true, pathRewrite: { '^/list': '/list' } } }


作者:almon123
链接:http://www.jianshu.com/p/95b2caf7e0da
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这样我们在写url的时候,只用写成/list/1就可以代表api.xxxxxxxx.com/list/1.
那么又是如何解决跨域问题的呢?其实在上面的'list'的参数里有一个changeOrigin参数,接收一个布尔值,如果设置为true,那么本地会虚拟一个服务端接收你的请求并代你发送该请求,这样就不会有跨域问题了,当然这只适用于开发环境。增加的代码如下所示:




十四  axios配置


man.js

配置post请求处理数据

http://www.cnblogs.com/Upton/p/6180512.html

import Qs from 'qs'
import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.prototype.$http=axios;
var axios_instance = axios.create({
// baseURL:'http://localhost',
transformRequest: [function (data) {
console.log(data);
data = Qs.stringify(data);
return data;
}],
headers:{'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'}
})
Vue.use(VueAxios, axios_instance)


axios请求数据接口,遇到困难的时候需要伪装


请求qq音乐全部歌单接口,增加headers已达到欺骗目的为自己所用

express后端配置

var app = express()

var apiRoutes = express.Router()

apiRoutes.get('/getDiscList', function (req, res) {
var url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg'
axios.get(url, {
headers: {
referer: 'https://c.y.qq.com/',
host: 'c.y.qq.com'
},
params: req.query
}).then((response) => {
res.json(response.data)
}).catch((e) => {
console.log(e)
})
})
app.use('/api', apiRoutes)


前端请求

const url = '/api/getDiscList'

const data = {
g_tk: 1928093487,
inCharset: 'utf-8',
outCharset: 'utf-8',
notice: 0,
format: 'json',
platform: 'yqq',
hostUin: 0,
sin: 0,
ein: 29,
sortId: 5,
needNewCode: 0,
categoryId: 10000000,
rnd: Math.random(),
}
axios.get(url, {
params: data
}).then((res) => {
console.log(res);
})

十五  配置sass

最新版本 "vue": "^2.5.2"   配置sass

npm install node-sass --save-dev 

npm install sass-loader --save-dev 


<style lang="scss">



十六 查看详细文档

v-once

也可以通过使用 v-once 指令,执行一次性插值,也就是说,在数据改变时,插值内容不会随之更新。但是请牢记,这也将影响到同一节点上的所有绑定:

<span v-once>这里的值永远不会改变:{{ msg }}</span>

修饰符(Modifiers)

修饰符(modifier)是以 . 表示的特殊后缀,表明应当以某种特殊方式绑定指令。例如,.prevent 修饰符告诉 v-on 指令,在触发事件后调用 event.preventDefault():

<form v-on:submit.prevent="onSubmit"></form>

computed 缓存 vs method 方法

不使用 computed 属性,而是在 methods 中定义一个相同的函数。对于最终结果,这两种方式确实恰好相同。然而,细微的差异之处在于,computed 属性会基于它所依赖的数据进行缓存。每个 computed 属性,只有在它所依赖的数据发生变化时,才会重新取值(re-evaluate)。这就意味着,只要 message 没有发生变化,多次访问 computed 属性 reversedMessage,将会立刻返回之前计算过的结果,而不必每次都重新执行函数。

这也同样意味着,如下的 computed 属性永远不会更新,因为 Date.now() 不是一个响应式的依赖数据

为什么我们需要将依赖数据缓存起来?假设一种场景,我们有一个高性能开销(expensive)的 computed 属性 A,在 computed 属性的 getter 函数内部,需要遍历循环一个巨大数组,并进行大量计算。然后还有其他 computed 属性直接或间接依赖于 A。如果没有缓存,我们将不可避免地多次执行 A 的 getter 函数,这远多余实际需要执行的次数!然而在某些场景下,你可能不希望有缓存,请使用 method 方法替代。

使用 v-for 遍历组件

现在,在 2.2.0+ 版本,当对组件使用 v-for 时,必须设置 key 属性。

然而,这里无法自动向组件中传入数据,这是因为组件有自己的独立作用域。为了将组件外部的迭代数据传入组件,我们还需要额外使用 props:

<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>


事件修饰符


<!-- 阻止单击事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件侦听器时使用事件捕获模式 -->
<!-- i.e. an event targeting an inner element is handled here before being handled by that element -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat">...</div>

2.1.4+ 新增
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>

按键修饰符

在监听键盘事件时,我们经常需要监测常见的键值。 Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

<!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
<input v-on:keyup.13="submit">

记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:

<!-- 同上 -->
<input v-on:keyup.enter="submit">
<!-- 缩写语法 -->
<input @keyup.enter="submit">

全部的按键别名:

  • .enter
  • .tab
  • .delete (捕获 “删除” 和 “退格” 键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

可以通过全局 config.keyCodes 对象自定义按键修饰符别名

// 可以
使用 v-on:keyup.f1
Vue.config.keyCodes.f1 = 112

修饰符

.lazy

在默认情况下, v-model 在 input 事件中同步输入框的值与数据 (除了 上述 IME 部分),但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步:

<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >

.number

如果想自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 number 给 v-model 来处理输入值:

<input v-model.number="age" type="number">

这通常很有用,因为在 type="number" 时 HTML 中输入的值也总是会返回字符串类型。

.trim

如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入:

<input v-model.trim="msg">







vue:2.5.13


vue实例属性


// console.log(app.$data)
// console.log(app.$props)
// console.log(app.$el)
// console.log(app.$options)
// app.$options.render = (h) => {
// return h('div', {}, 'new render function')
// }
// console.log(app.$root === app)
// console.log(app.$children)
// console.log(app.$slots)
// console.log(app.$scopedSlots)
// console.log(app.$refs)
// console.log(app.$isServer) 服务端渲染

方法

// const unWatch = app.$watch('text', (newText, oldText) => {
// console.log(`${newText} : ${oldText}`)
// })
// setTimeout(() => {
// unWatch()
// }, 2000)

// app.$once('test', (a, b) => {
// console.log(`test emited ${1} ${b}`)
// })
// app.$emit('test',1,2)

// setInterval(() => {
// app.$emit('test', 1, 2)
// }, 1000)

// app.$forceUpdate() app.$set(app.obj,'a',i) app.$delete() 防止内存泄漏




1.vue-loader配置


高级功能:自定义loader    doc-loader.js    增加每个组件的文档说明
module.exports = function (source, map) {
this.callback(null, 'module.exports = function(Component) {Component.options.__docs = ' +
JSON.stringify(source) +
'}', map)
}

在每个组件可以增加   <docs>test</docs>  功能类似于<style><script><template>
cssmodule配置
// const docsLoader = require.resolve('./doc-loader');

module.exports = (isDev) => {
return {
preserveWhitepace: true,
extractCSS: !isDev,//上线环境不提取每个vue的css,开发环境进行热加载
cssModules: {
localIdentName: isDev ? '[path]-[name]-[hash:base64:5]' : '[hash:base64:5]', //生成另外一个自定义class
camelCase: true //将css中的-变成js中的与驼峰命名,在组件的style标签增加一个module属性,就会按照这个执行
},
// hotReload: false, // 组件热重载功能根据环境变量生成
// loaders:{
// 'docs':docsLoader
// }
}
}//调用 在app.vue中console.log(Header.__docs)



{
loader:'css-loader',
options:{
module:true,
localIdentName: isDev ? '[path]-[name]-[hash:base64:5]' : '[hash:base64:5]',
}
},




const merge = require('webpack-merge')//帮助合并config文件
const ExtractPlugin = require('extract-text-webpack-plugin') //抽离css文件



const devServer = {
port: 8000,
host: '0.0.0.0',
overlay: {
errors: true,
},
hot: true,//热加载 修改某个页面,就只重新渲染这个页面 增加 config.plugins.push
// open:true 默认打开浏览器
// historyFallback:{}
}




config = merge(baseConfig, {
devtool: '#cheap-module-eval-source-map', //帮助调试




plugins:defaultPluins.concat([ //顺序不能变
new ExtractPlugin('styles.[contentHash:8].css'),
new webpack.optimize.CommonsChunkPlugin({ //抽离稳定的内库文件
name: 'vendor'
}),
new webpack.optimize.CommonsChunkPlugin({ //webpack新的模块
name: 'runtime'
})
])









eslint自动修复


"lint": "eslint --ext .js --ext .jsx --ext .vue client/",
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue client/" //修复eslint的问题

"babel-eslint": "^8.2.1",

"eslint": "^4.16.0",
"eslint-config-standard": "^11.0.0-beta.0",
"eslint-loader": "^1.9.0",
"eslint-plugin-html": "^4.0.1",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-node": "^5.2.1",
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-standard": "^3.0.1",

.eslitrc
{
"extends": "standard",
"plugins": [
"html"
],
"parser": "babel-eslint",
"rules": {
"no-new": "off"
}
}

webpack.config.js 增加
module: {
rules: [
{
test: /\.(vue|js|jsx)$/,
loader: 'eslint-loader',
exclude: /node_modules/,
enforce: 'pre' //预处理 post之后
},


"precommit": "npm run lint",  //依赖这个npm包 在git commit的时候检查代码风格

"husky": "^0.14.3",



路由


全局导航守卫


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

 2.5.0+ 你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。


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


路由独享的守卫

你可以在路由配置上直接定义 beforeEnter 守卫:

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

组件内的守卫

最后,你可以在路由组件内直接定义以下路由导航守卫:

  • beforeRouteEnter
  • beforeRouteUpdate (2.2 新增)
  • beforeRouteLeave


const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}

beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。

不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。

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

完整的导航解析流程

  1. 导航被触发。
  2. 在失活的组件里调用离开守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter。
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter。
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。



mapState 辅助函数

cnpm i babel-preset-stage-1 -D     

"presets": [
"stage-1"
],

当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性,让你少按几次键:

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭头函数可使代码更简练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',

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


严格模式

开启严格模式,仅需在创建 store 的时候传入 strict: true:

const store = new Vuex.Store({
  // ...
  strict: true
})

在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。

开发环境与发布环境

不要在发布环境下启用严格模式!严格模式会深度监测状态树来检测不合规的状态变更——请确保在发布环境下关闭严格模式,以避免性能损失。

类似于插件,我们可以让构建工具来处理这种情况:

const store = new Vuex.Store({
  // ...
  strict: process.env.NODE_ENV !== 'production'
})



命名空间

默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。

如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为命名空间模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。例如:

const store = new Vuex.Store({
  modules: {
    account: {
      namespaced: true,

      // 模块内容(module assets)
      state: { ... }, // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响
      getters: {
        isAdmin () { ... } // -> getters['account/isAdmin']
      },
      actions: {
        login () { ... } // -> dispatch('account/login')
      },
      mutations: {
        login () { ... } // -> commit('account/login')
      },

      // 嵌套模块
      modules: {
        // 继承父模块的命名空间
        myPage: {
          state: { ... },
          getters: {
            profile () { ... } // -> getters['account/profile']
          }
        },

        // 进一步嵌套命名空间
        posts: {
          namespaced: true,

          state: { ... },
          getters: {
            popular () { ... } // -> getters['account/posts/popular']
          }
        }
      }
    }
  }
})

启用了命名空间的 getter 和 action 会收到局部化的 getter,dispatch 和 commit。换言之,你在使用模块内容(module assets)时不需要在同一模块内额外添加空间名前缀。更改 namespaced 属性后不需要修改模块内的代码。













你可能感兴趣的文章

    发表评论

    评论支持markdown,评论内容不能超过500字符,如果内容过多或者要及时回复,建议去 平台,一般一天之内就会回复。
    关于技术问题或者有啥不懂的都可以留言,我会定期回复答 疑,推荐最新仓库 前端知识体系, 感謝支持!