Vue CLI + Vue-router + Vuex

Vue CLI

什么是CLI?

Command-Line Interface 命令行界面,俗称脚手架
vue-cli 可以快速搭建Vue开发环境以及对应的webpack配置

  • 脚手架依赖webpack,而webpack运行需要node,所以要安装NodeJs
  • NPM : Node Package Manager 为node的包管理工具
    安装全局的Webpack
npm install webpack -g

安装Vue CLI

npm install @vue/cli -g

Vue CLI3 初始化

vue create 项目名

Vue Router

  1. vue-router 基本使用
  2. vue-router 嵌套路由
  3. vue-router 参数传递
  4. vue-router 导航守卫
  5. keep-alive
  6. https://router.vuejs.org/zh/

vue-router 基本使用

  1. 安装vue-router

    npm install vue-router --save
    
  2. 在模块工程中使用它

    2.1 导入路由对象,并调用Vue.use(VueRouter)
    2.2 创建路由实例,传入路由映射配置
    2.3 在Vue实例中挂载创建的路由实例
    
  3. 使用vue-router的步骤

    3.1 创建路由组件
    3.2 配置路由映射(组件和路径映射关系)
    3.3 使用路由(router-link,router-view)
    
/* src/router/index.js */
import Vue from 'vue'
import VueRouter from 'vue-router'

// 懒加载
const Home = () => import('../components/home')
const About = () => import('../components/about')

// 1.注入插件
Vue.use(VueRouter)

// 2.定义路由
const routes = [
    {
        path:'/',
        redirect:'/home'
    },
    {
        path:'/home',
        component:Home
    },
    {
        path:'/about',
        component:About
    }
]

// 3.创建router实例,默认使用URL的hash
const router = new VueRouter({
    routes,
    mode:'history',     // 使用HTML5的history模式 (localhost:8080/home)
    linkActiveClass:'active'    // 修改路由激活添加的类名
})

// 4.导出router实例
export default router



/* src/main.js */
import Vue from 'vue'
import App from './App'
import router from './router'

new Vue({
    el:'#app',
    router,  // 挂载到Vue实例中
    render:h=>h(App)
})



/* src/components/home.vue */
// 创建路由组件
<template>
    <div>home</div>
</template>

<script>
    export default {
        name:'home'
    }
</script>

<style scoped>   
</style>



/* src/App.vue */
<template>
    <div id='app'>
        <div>App start</div>
        <router-link to='/home'>home</router-link>
        <router-link to='/about'>about</router-link>
        <router-view></router-view>
        <div>App end</div>
    </div>
</template>

<script>
export default {
    name:'App'
}
</script>

<style>
</style>

router-link 补充

to:指定跳转路径

tag:指定渲染成什么元素

replace:replace不会留下history记录,所以在指定replace的情况下,后退键返回不能返回到上一个页面中

active-class:当 router-link对应的路由配对成功,会自动给当前元素设置一个router-link-active的class,设置active-class可以修改默认的名称

通过代码跳转路由

/* src/App.vue */
<template>
    <div id='app'>
        <div>App start</div>
      <div @click='toHome'>home</div>
      <div @click='toAbout'>about</div>
      <router-view></router-view>
      <div>App end</div>
    </div>
</template>

<script>
export default {
    name:'App',
    methods:{
        toHome(){
            this.$router.push('/home')
        },
        toAbout(){
            this.$router.push('/about')
        }
    }
}
</script>

<style>
</style>

动态路由

/* src/router/index.js */
{
    path: '/user/:aid',
    component: User
}



/* src/App.vue */
<router-link to='/user/abc'>user</router-link>



/* src/components/user.vue */
<div>{{$route.params.aid}}</div>    /* abc */

嵌套路由

/* src/components/new1.vue */
<div>new1</div>

/* src/components/new2.vue */
<div>new2</div>



/* src/router/index.js */
const New1 = () => import('../components/new1')
const New2 = () => import('../components/new2')

{
        path:'/home',
        component:Home,
        children:[
            {
                path:'',
                redirect:'new1'
            },
            {
                path:'new1',
                component:New1 
            },
            {
                path:'new2',
                component:New2 
            }
        ]
},


/* src/components/home.vue */
<template>
    <div id='home'>
        <div>Home start</div>
        <router-link to='/home/new1'>new1</router-link>
        <router-link to='/about/new2'>new2</router-link>
        <router-view></router-view>
        <div>Home end</div>
    </div>
</template>


传递参数

params:(/router/abc)

配置路由的格式:/router/:id

传递的方式:在path后面跟上对应的值

query:(/router/id=123)

配置路由的格式:/router

传递的方式:query的key作为传递方式

/* src/App.vue */
// 两种传参方式
<template>
    <div id='app'>
        <div>App start</div>
        <router-link
            :to="{
                path:'/home/' + 'abc',
                query:{name:'kevin',age:18}
            }"
        >home</router-link>
        <router-link to='/about'>about</router-link>
        <router-view></router-view>
        <div>App end</div>
    </div>
</template>

/* 代码传参 */
<script>
export default {
    name:'App',
    methods:{
        toHome(){
            this.$router.push({
                path:'/home/' + 'abc',
                query:{name:'kevin',age:18}
            })
        },
        toAbout(){
            this.$router.push('/about')
        }
    }
}
</script>

<style>
</style>

获取参数

  • 使用了vue-router的应用中,路由对象会被注入到每个组件中,赋值为this.$route,并且当路由切换时,路由对象会被更新
/* src/components/home.vue */
<template>
    <div id='home'>
        <div>params:{{$route.params}}</div>     // params:{"id":"abc"}
        <div>query:{{$route.query}}</div>       // query:{"name":"kevin","age":18}
    </div>
</template>


导航守卫

vue-router 提供的导航守卫用于监听路由的进入和离开

全局守卫(钩子函数)

beforeEach:路由即将改变前触发(前置钩子)

afterEach:路由改变后触发(后置钩子)

https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E8%B7%AF%E7%94%B1%E7%8B%AC%E4%BA%AB%E7%9A%84%E5%AE%88%E5%8D%AB

/* 使用beforeEach修改标题 */
/* src/router/index.js */
const routes = [
    {
        path:'/home',
        compontent:Home,
        meta:{
            title:'首页'
        }
    },
    {
        path:'/about',
        compontent:About,
        meta:{
            title:'关于'
        }
    }
]

const router = new VueRouter({...})
                              
/**
 * to:即将要进入的目标对象
 * from:当前导航即将要离开的路由对象
 * next:调用该方法,才能进入下一个钩子,
 * afterEach不需要调用next方法
 */                     
router.beforeEach((to,from,next)=>{
    window.document.title = to.meta.title
    next()
})                              

补充

keep-alive 是 Vue 内置组件,可以使被包含的组件保留状态,或避免重新渲染

include:字符串/正则表达式,只有匹配的组件会被缓存

exclude:字符串/正则表达式,匹配的组件不会被缓存

<keep-alive>
    <router-view>
        <!-- 所有路径匹配到的组件都会缓存 -->
    </router-view>
</keep-alive>

Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式

单页面的状态管理

State:状态数据集合

View:视图层,针对State的变化,显示不同的信息

Actions:提交数据,更改State

/* src/store/index.js */

import Vuex from 'vuex'
import Vue from 'vue'

Vue.use(Vuex)

const store = new Vuex.Store({
    state:{
        publicData:{name:'liang',age:18}
    },
    mutations:{
        showData(state){
            console.log(state.publicData)
        }
    }
})

export default store



/* main.js */

import store from './store'

new Vue({
    el: '#app',
    store,
    render: h => h(App)
})

  • 其他组件,通过 this.store.state.属性** 的方式来访问状态,通过 **this.store.commit('mutation中方法') 来修改状态
  • 注意:我们通过提交mutation的方式,而非直接改变store.state.count。这样Vuex可以更准确的追踪状态的变化,所以不要直接改变store.state.count的值。
image.png
  • state:存储状态
  • getters:可以理解为state的计算属性,在组件中使用$sotre.getters.fun()
  • mutations:修改状态,同步的,在组件中使用$store.commit('fname',params),和自定义事件类似。
  • actions:异步操作。在组件中使用是$store.dispath('')
  • modules:store的子模块,方便状态管理而使用的。用起来和上面的一样。

Getters

const store = mew Vue.Store({
    state:{
        numArr = [1,2,3,4,5,6,7,8,9]
    },
    getters:{
        getany: state => {
            return state.numArr.filter(num=>num > 3)   
       }
    }
})


// 利用callback传递参数
getters:{
    getany: state => {
        return (a,b) =>{
            state.numArr.filter(num=>(num + a) * b)   
        }
    }
}


Mutation

注意:只能通过 提交Mutation 来更新store的状态

Mutation 不建议使用异步方法: (如果异步,devtools将不能很好的追踪这个操作什么时候会被完成)

const store = mew Vue.Store({
    state:{
        numArr = [1,2,3,4,5,6,7,8,9]
    },
    mutations:{
        // 1. 定义函数
        change(state){
            state.numArr = ['a','b','c','d','e']
        }
    }
})


// 2. 其他组件, 提交函数
changArr(){
    this.$store.commit('change')
}



/*------------------传递参数(payload)------------------*/
mutations:{
    // 1. 定义函数
    change(state,payload){
        console.log(payload)
        state.numArr = ['a','b','c','d','e']
    }
}

// 2. 其他组件, 提交函数
changArr(){
    // 1.提交方式1
    this.$store.commit('change',something)
    // 2.提交方式2
    this.$store.commit({
        type: 'change',
        key: value
    })
}



/*------------------store添加新属性------------------*/
// 1.使用 Vue.set(obj,'addKey',value)
// 2.用新对象给旧对象重新赋值
const store = new Vue.Store({
    state:{
        numArr = [1,2,3,4,5,6,7,8,9],
        info:{
            name: 'zhangsan',
            age: '18'
        }
    },
    mutations:{
        addInfo(state,payload){
            //0.错误的赋值方法(使用该方法页面做不到响应式)
            // state.info['hobby'] = payload.hobby    错误
            //1.使用 Vue.set(obj,'addKey',value)
            Vue.set(state.info,'hobby',payload.hobby)
            // 2.用新对象给旧对象重新赋值
            state.info = {...state.info,'hobby': payload.hobby}
        }
    }
})


Action

用于Vuex 处理异步操作,类似 Mutation

其他组件通过 dispatch 提交 action,也支持payload

使用 Promise 进行异步操作

const store = mew Vue.Store({
    state:{
        numArr = [1,2,3,4,5,6,7,8,9],
        info:{
            name: 'zhangsan',
            age: '18'
        }
    },
    mutations:{
        addInfo(state,payload){
            //0.错误的赋值方法(使用该方法页面做不到响应式)
            // state.info['hobby'] = payload.hobby    错误
            //1.使用 Vue.set(obj,'addKey',value)
            Vue.set(state.info,'hobby',payload.hobby)
            // 2.用新对象给旧对象重新赋值
            state.info = {...state.info,'hobby': payload.hobby}
        }
    },
    actions:{
        /* add(context.payload){
            // context 是和 store对象具有相同方法和属性的对象
            setTimeout(()=>{
                context.commit('change',payload)
            },2000)
        }*/
        add(content){
            return new Promise((resolve,reject) => {
                setTimeout(()=>{
                    context.commit('change',payload)
                    resolve()
                },2000)
            })
        }
    }
})



// 其他组件
addInfo(){
    // this.$store.dispatch('add',{'hobby' : "coding"})
    this.$store.dispatch('add',{'hobby' : "coding"}).then(res =>{
        console.log("更新成功")
    }).catch(err =>{
        console.log(err)
    })
}

Module

使用 Module 来管理store(将store分成几个模块进行管理)

const moduleA = {
    state:{...},
    getters:{...},
    mutations:{...},
    actions:{...}
}
               
const moduleB = {
    state:{...},
    getters:{...},
    mutations:{...},
    actions:{...}
}
               
const store = new Vuex.Store({
    modules:{
        a:moduleA,
        b:moduleB
    }        
})
             
             
// 参数

const moduleA = {
    actions:{
        add({state,getters,rootState},payload){
            console.log(state,getters,rootState)
            console.log(payload)
        }
    }
}
END
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342