vue 全家桶

知识回顾

vue基础

指令

生命周期

事件

MVVM(数据驱动视图)

组件

局部组件和全局组件

组件通信

        父子组件 props和$emits

        $bus 中央事件总线

        provide和inject

        $attrs和$listeners

        this.$parent 、ths.$children、 this.$slots...

组件设计

        如何更优雅地设计一款组件

render(h) jsx

vue性能优化的9个技巧

Element-ui /antd-design-vue || vant-ui/iview

awesome

axios是基于XMLHttpRequest promise

vue-xxx react-xxx 插件(github star 更新时间)


目录

vue-router的基础使用

vue-router 安装

main.js

 router/index.js

App.vue

  嵌套路由 views/User.vue

 views/Login.vue

  views/course/index.vue

命名视图

完整的导航解析流程

vuex基础state/getter/mutation/action

vuex导图 

安装vueX

store/index.js配置

 main.js

 组件views/About.vue

 App.vue

components/ProductList.vue

components/ShoppingCart.vue

store/modules/cart.js 

 store/modules/products.js 

src/api/products.js 

src/utils/request.js 

vue.config.js 


vue-router的基础使用

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌

vue-router 安装

npm i vue-router -S

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

 router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'


Vue.use(VueRouter)
// 路由管理表
const routes = [

    {
        path:'/',
        // 命名路由
        // redirect: '/home',
        name:'Home',
        component:HomeView
    },
        // 同一个路径可以匹配多个路由,匹配的优先级按照路由的定义顺序来匹配的
    {
        path: '/about',
        name: 'About',
        component: () => import( '@/views/AboutView.vue')
    },
    {//带参路径,user组件复用
        path:'/user:userName',
        name:'User',
        component:() =>import('@、views/User.vue')
    },
    {
        path: '/course',
        // name: 'Course',
        component: () => import('@/views/course'),
        //路由权限拦截
        meta: { requireAuth: true },
        //嵌套路由
        children: [
          {
            path: '',
            component: () => import('@/views/course/home'),
          },
          {
            path: 'front',
            component: () => import('@/views/course/front'),
          },
          {
            path: 'backend',
            component: () => import('@/views/course/backend'),
          },
        ],
   },
   {
     path: '/login',
     name: 'Login',
     component: () => import('@/views/login'),
   },

   {//放到最后
     path:'*',
     component:() =>import('@/views/404.vue')
   }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

// 全局守卫
router.beforeEach((to, from, next) => {
  // 需要权限,在黑名单
  if (to.matched.some((record) => record.meta.requireAuth)) {
    // 用户是否有登录
    const userInfo = localStorage.getItem('userInfo')
    if (userInfo) {
      next()
    } else {
      next({
        path: '/login',
        query: {
          redirect: to.fullPath,
        },
      })
    }
  } else {
    next()
  }
})

export default router

 :同路径可以匹配多个路由,按照优先顺序匹配,重名路由将选取靠前那个

        path:* 必须放到最后面,直接跳转404页面

        路由权限拦截 meta: { requireAuth: true },

        全局路由守卫

        router.beforeEach((to, from, next) => {
 
                  if (to.matched.some((record) => record.meta.requireAuth)) {... }

                  else{next()}

        }

App.vue

<template>
  <div id="app">
    <nav>
      <!-- router-link 内置组件 被渲染为a标签 to会被渲染成href属性 -->
      <router-link to="/">Home</router-link> |
      
      <router-link to="/about">About</router-link>|
      <router-link :to="{name:'Test'}">Test</router-link>|
      <router-link :to="{name:'User',params:{userName:'kiki'}}">User(kiki)</router-link>|
      <router-link :to="{name:'User',params:{userName:'xiaomage'}}">User(xiaomage)</router-link>|
      <router-link :to="{name:'Login'}">登录</router-link>|
      <router-link to="/course">课程</router-link>|
      
    </nav>
    <router-view/>
  </div>
</template>

 注动态路由匹配使用 :to ={name:'',params:{id:1}}

 <router-link :to="{name:'user',params:{id:1}}">User</router-link> |

  嵌套路由 views/User.vue

<template>
  <div>
    我是用户组件页面{{ name }}
    <router-link to="/">跳首页</router-link>
    <button @click="goHome">跳转到首页</button>
    <button @click="goBack">后退</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      name: '',
    }
  },
  created() {
    const { userName } = this.$route.params
    if (userName) {
      this.name = userName
    }
  },
  // watch监听路由参数的变化
  //   watch: {
  //     $route(to, from) {
  //       this.getUserInfo(to.params.userName)
  //     },
  //   },
//路由守卫deforeRouteUpdate(to,from,next){} ,当路由更新时触发
  beforeRouteUpdate(to, from, next) {
    this.getUserInfo(to.params.userName)
    next()
  },
  methods: {
    goBack() {
      this.$router.go(0)
    },
    getUserInfo(username) {
      // 发起ajax 获取当前用户的数据
      setTimeout(() => {
        this.name = username
      }, 1000)
    },
    goHome() {
      //   编程式导航
      // this.$router.push('/')
      this.$router.push({
        name: 'Home',
        query: {
          id: 1,
        },
        // params:{}
      })
    },
  },
}
</script>

        路由守卫deforeRouteUpdate(to,from,next){} ,当路由更新时触发

        编程式导航this.$router.push({ ...})      历史跳转 this.$router.go(-1)          

 views/Login.vue

<template>
  <div>
    <h2>登录页面</h2>
    <input type="text" v-model="form.user" />
    <input type="password" v-model="form.pwd" />
    <button @click="handleLogin">登录</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      form: {
        name: '',
        pwd: '',
      },
    }
  },
  methods: {
    handleLogin() {
      // 获取用户名和密码
      setTimeout(() => {
        const { user, pwd } = this.form
        const data = {
          user,
          pwd,
        }
        // 保存到本地
        localStorage.setItem('userInfo', JSON.stringify(data))
        // 跳转到课程页面
        this.$router.push({
          //   path: '/course',
          path: this.$route.query.redirect,
        })
      }, 1000)
    },
  },
}
</script>

 注:路由重定向

        this.$router.push({ path:  this.$route.query.redirect })

  views/course/index.vue

<template>
    <div>
        <router-link to="/course">全部</router-link> |
        <router-link to="/course/front">前端</router-link> |
        <router-link to="/course/backend">后端</router-link> |

        <!-- 渲染全部 前端 后端 -->
        <router-view></router-view>
    </div>
</template>

<script>
    export default {
        
    }
</script>

 <router-view></router-view> 进行渲染 

        /course会默认进入index.vue

命名视图

非嵌套多视图

router/index.js

{
    path: '/',
    name: 'Home',
    // component: HomeView
    components:{
      default:HomeView,
      //懒加载
      Main:() => import('../views/Main.vue'),
      Sidebar:() => import('../views/Sidebar.vue'),
    }
  },

App.vue

    <router-view name="Main" />
    <router-view/>
    <router-view name="Sidebar"/>

完整的导航解析流程

  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 的回调函数。


vuex基础state/getter/mutation/action

详细介绍vuex基本介绍

vuex是专门用来管理vue.js应用程序中状态的一个插件。

作用将应用中的所有状态都放在一起,集中式来管理

需要声明的是,这里所说的状态指的是vue组件中data里面的属性

vuex导图 

  1. state: 统一定义公共数据(类似于data(){return {a:1, b:2,xxxxxx}})
  2. mutations : 使用它来修改数据(类似于methods)更改state中的数据必须提交(commit) mutations来进行更改
  3. getters: 类似于computed(计算属性,对现有的状态进行计算得到新的数据-------派生 )
  4. actions: 发起异步请求
  5. modules: 模块拆分

安装vueX

 或者在新建脚手架时选中vuex

vue add vuex 

store/index.js配置

        引入并使用vuex

import Vuex from 'vuex'
// 2.使用当前的插件
Vue.use(Vuex)

        new Vuex.Store 创建store

const store = new Vuex.Store({
  plugins: [createLogger()],
  state: { //当前的状态
    count: 0,
    username: 'kiki'
  },

  getters: {
    evenOrOdd(state) {
      return state.count % 2 === 0 ? '偶数' : '奇数';
    }
  },

  mutations: { //声明同步的方法
    increment(state) {
      // 修改状态
      state.count++
    },
    decrement(state) {
      state.count--
    },
    incrementAsync(state,amount) {
      state.count+=amount;
    }
  },

  actions: { //声明异步的方法
    // commit mutations中声明的方法
    // 修改状态的唯一方法是提交mutation
    incrementAsync({ commit },{amount}) {
      setTimeout(() => {
        commit('incrementAsync',amount)
      }, 1000);
    }
  },

//模板
  modules: {
    cart,
    products
  }
})

//导出store
export default store;

 main.js

导入创建的store进行挂载
import store from './store'

import Vue from 'vue'
import App from './App.vue'
import router from './router'
// 导入创建的store
import store from './store'
Vue.config.productionTip = false
// 注册全局组件的方式
import ShoppingCart from '@/components/ShoppingCart';
Vue.component(ShoppingCart.name, ShoppingCart)
// 全局注册过滤器
Vue.filter('currency',(value)=>{
  return '$' + value;
})

new Vue({
  router,
  //一定要挂载
  store,
  render: h => h(App)
}).$mount('#app')

 组件views/About.vue

<template>
  <div class="about">
    <h1>This is an about page</h1>
    {{myCount}} - {{user}}
    {{evenOrOdd}}
    <button @click="increment">+1</button>
    <button @click="decrement">-1</button>
    <button @click="incrementAsync">+1异步</button>
    <ProductList></ProductList>
    <hr>
    <!-- <ShoppingCart></ShoppingCart> -->
    <shopping-cart></shopping-cart>

  </div>
</template>
<script>
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
import ProductList from '@/components/ProductList'
// import ShoppingCart from '@/components/ShoppingCart'
export default {
  components: {
    ProductList,
    // ShoppingCart
  },
  computed: {
    // count() {
    //   return this.$store.state.count;
    // },
    // username(){
    //   return this.$store.state.username;
    // }
    // ...mapState(['count','username'])
    ...mapState({
      myCount: "count",
      user: "username"
    }),
    // evenOrOdd() {
    //   return this.$store.getters.evenOrOdd;
    // }
    ...mapGetters(['evenOrOdd'])
  },
  methods: {
    incrementAsync() {
      // 在组件内部提交数据 载荷形式分发
      // this.$store.dispatch('incrementAsync',{
      //   amount:10
      // });
      this.$store.dispatch({
        type:'incrementAsync',
        amount: 10
      })
    },
    // ...mapActions(['incrementAsync']),

    /* increment() {
      // dispatch触发actions中声明的方法(异步)
      // this.$store.dispatch('increment');
      this.$store.commit("increment");
    },
    decrement() {
      // this.$store.dispatch('decrement');
      this.$store.commit("decrement");
    } */
    ...mapMutations(['increment','decrement'])
  }
};
</script>

 App.vue

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link>|
      <router-link to="/about">About</router-link>
      {{$store.state.count}}
      {{getCount}}
    </div>
    <router-view/>
  </div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
  computed: {
    ...mapGetters('cart',['getCount'])
  }
};
</script>

components/ProductList.vue

<template>
  <div>
    <h2>我的商铺</h2>
    <ul>
      <li
        v-for="(product) in products"
        :key="product.id"
      >{{product.title}} - {{product.price | currency}} - {{product.inventory}}
       <br>
      <button :disabled='!product.inventory' @click='addProductToCart(product)'>加入购物车</button>
      </li>
     
    </ul>
  </div>
</template>

<script>
import { mapState,mapActions } from "vuex";
export default {
  computed: {
    ...mapState("products", ["products"])
  },
  created() {
    this.$store.dispatch("products/getAllProducts");
  },
  methods: {
    ...mapActions('cart',['addProductToCart'])
  },
  
};
</script>

components/ShoppingCart.vue

<template>
  <div>
    <h2>我的购物车</h2>
    <ul>
      <li
        v-for="(item,index) in getCartList"
        :key="index"
      >{{item.title}} - {{item.price | currency}} x {{item.quantity}}</li>
    </ul>
    总价格:{{cartTotalPrice | currency}}
  </div>
</template>

<script>
import { mapGetters } from "vuex";
export default {
  name: "ShoppingCart", //组件名  注册全局组件时使用,
  computed: {
    ...mapGetters("cart", ["getCartList", "cartTotalPrice"])
  }
};
</script>

使用modules 

store/modules/cart.js 

namespaced: true,

export default {
    namespaced: true,
    state: {
        cartList: [],
        count: 0
    },
    getters: {
        getCount(state) {
            return state.count
        },
        // 获取购物车的数据
        getCartList(state, getters, rootState) {
            return state.cartList.map(({ id, quantity }) => {
                const product = rootState.products.products.find(item => item.id === id);
                return {
                    title: product.title,
                    price: product.price,
                    quantity
                }
            })
        },
        cartTotalPrice(state, getters) {
            return getters.getCartList.reduce((total, product) => {
                return total + product.price * product.quantity
            }, 0);
        }


    },
    mutations: {
        // 第一此添加该商品到购物车
        pushProductToCart(state, { id, quantity }) {
            state.cartList.push({
                id,
                quantity
            })
        },
        // 购物车中已有数据 只改变当前的数量
        incrementCartItemQuantity(state, { id }) {
            const product = state.cartList.find(item => item.id === id);
            product.quantity++;
        }
    },
    actions: {
        addProductToCart({ commit, state }, product) {
            if (product.inventory > 0) { //   有库存
                const cartItem = state.cartList.find(item => item.id === product.id);
                console.log(cartItem);

                if (!cartItem) {
                    //   购物车无数据 新添加到购物车
                    commit('pushProductToCart', { id: product.id, quantity: 1 })
                } else {
                    //购物车中已有数据
                    commit('incrementCartItemQuantity', { id: product.id });
                }
                // 如果想提交另一个模块中的方法,那么需要第三个参数{root:true}
                commit('products/decrementProductInventory', { id: product.id },{root:true})
            }

        }
    }
}

 store/modules/products.js 

import Axios from 'axios'
export default {
    namespaced: true,
    state: {
        products: []
    },
    getters: {

    },
    mutations: {
        getAllProducts(state, products) {
            state.products = products
        },
        decrementProductInventory(state, { id }) {
            const product = state.products.find(item => item.id === id);
            product.inventory--;
        }
    },
    actions: {
        async getAllProducts({ commit }) {
            // 发送请求 获取数据 提交mutation
            try {
                const res = await Axios.get('/api/products');
                const results = res.data.results
                commit('getAllProducts', results);

            } catch (error) {
                console.log(error);

            }
        }

    }
}

src/api/products.js 

import request from '@/utils/request'
export const getProducts = (paramter) => {
  return request({
    url: '/products',
    method: 'get',
    params: paramter,
    // data:paramter
  })
}

src/utils/request.js 

import axios from 'axios'
const request = axios.create({
  baseURL: '/api',
  timeout: 5000,
})
// 添加请求拦截器
request.interceptors.request.use(
  function (config) {
    // 在发送请求之前做些什么
    return config
  },
  function (error) {
    // 对请求错误做些什么
    return Promise.reject(error)
  }
)

// 添加响应拦截器
request.interceptors.response.use(
  function (response) {
    // 对响应数据做点什么
    return response.data
  },
  function (error) {
    // 对响应错误做点什么
    return Promise.reject(error)
  }
)
export default request

vue.config.js 

const products = [
    { id: 1, title: 'iphone11', price: 800, inventory: 10 },
    { id: 2, title: 'iphone11 pro', price: 1200, inventory: 15 },
    { id: 3, title: 'iphone11 max', price: 1500, inventory: 5 },
]
module.exports = {
    devServer: {
        before(app, serve) {
            app.get('/api/products', (req, res) => {
                res.json({
                    results: products
                })
            })
        }
    }
}


 


介绍 | vue-element-admin

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值