vue3+element-plus开发学习管理系统

一、 项目地址

学习管理系统地址: https://bushanjiangzi.gitee.io/vue3manage/#/

源码地址:https://gitee.com/bushanjiangzi/vue3-element-plus

二、新特性

1. 实例化

 1  1 import { createApp } from 'vue'
 2  2 import App from './App.vue'
 3  3 import router from './router'
 4  4 import store from './store'
 5  5 import ElementPlus from 'element-plus'
 6  6 import 'element-plus/lib/theme-chalk/index.css'
 7  7 import './assets/css/public.css'
 8  8 import './assets/css/reset.css'
 9  9 
10 10 createApp(App)
11 11   .use(store)
12 12   .use(router)
13 13   .use(ElementPlus)
14 14   .mount('#app')

2. reactive 和 ref 

  reactive 类似于vue2.x 中的 Vue.observable(),vue3.x的reactiveref取代了vue2.x中的data数据定义

 1 <template>
 2   <div class="home">
 3     <HelloWorld :propsMsg="propsMsg">
 4       <template #backBtn>
 5         <router-link to="/setup">
 6           <el-button type="primary" plain>Setup</el-button>
 7         </router-link>
 8       </template>
 9     </HelloWorld>
10     <h2>HelloWorld Input</h2>
11     <input v-model="myInput" />
12     <h2>Conputed String</h2>
13     <input v-model="firstInput" />
14     <input v-model="secondInput" />
15     <div>{{ state.total }}</div>
16     <h2>Conputed Object</h2>
17     <input v-model="state.first" />
18     <input v-model="state.second" />
19     <div>total:{{ state.total2 }}</div>
20     <div>doubleCount:{{ doubleCount }}</div>
21   </div>
22 </template>
23 
24 <script>
25 import HelloWorld from '@/components/HelloWorld.vue'
26 import { reactive, ref, watchEffect, watch, provide, computed } from 'vue'
27 import setupTest from '@/composition/setup'
28 
29 export default {
30   name: 'Home',
31   components: {
32     HelloWorld
33   },
34   setup() {
35     const { propsMsg, myInput } = setupTest()
36     propsMsg.name = ' World'
37     const firstInput = ref()
38     const secondInput = ref()
39     const state = reactive({
40       first: 0,
41       second: 0,
42       total: 0,
43       total2: 0
44     })
45     watchEffect(() => {
46       state.total = firstInput.value + secondInput.value
47       state.total2 = parseInt(state.first) + parseInt(state.second)
48     })
49     watch([firstInput, secondInput], (newValues, prevValues) => {
50       console.log(firstInput.value, secondInput.value, newValues, prevValues)
51     })
52     const doubleCount = computed({
53       get() {
54         return state.total2 * 2
55       },
56       set(newVal) {
57         state.total2 = newVal / 2
58       }
59     })
60     provide('provideData', 'provide data from home')
61     return {
62       propsMsg,
63       myInput,
64       firstInput,
65       secondInput,
66       state,
67       doubleCount
68     }
69   }
70 }
71 </script>

3. watch & watchEffect

  3.x中watch支持监听单个属性,也支持监听多个属性,相比2.x的watch更灵活,多个时第一个参数是要监听的数组,第二个参数是回调函数,返回参数是新值;3.x中watchEffect方法会返回一个方法(俗称副作用,只要返回函数里的依赖项发生变化就回执行回调函数),watchwatchEffect不同的地方在于,watchEffect注册后会立即调用,而watch默认不会,除非显示指定immediate=true,并且watchEffect可以停止监听

4. 计算属性 computed

2.x和3.x中的computed都支持getter和setter,写法一样,只是3.x中是组合函数式

5. provide和inject

父组件:provide('provideData', 'provide data from home')
子孙组件:inject('provideData')
 1 <template>
 2   <div class="hello">
 3     <h1 class="left">{{ propsMsg.msg }} {{ propsMsg.name }} {{ homeInput }}</h1>
 4     <div class="right">
 5       <el-button type="primary" plain @click="toElement">Element-Plus</el-button>
 6       <slot name="backBtn"></slot>
 7     </div>
 8   </div>
 9 </template>
10 
11 <script>
12 // eslint-disable-next-line
13 import { computed, inject, onMounted, getCurrentInstance } from 'vue'
14 import store from '@/store/index'
15 import router from '@/router/index'
16 import { ElMessage } from 'element-plus'
17 export default {
18   name: 'HelloWorld',
19   props: {
20     propsMsg: {
21       type: Object,
22       require: true
23     }
24   },
25   setup() {
26     const homeInput = computed(() => {
27       return store.state.homeInput
28     })
29     const toElement = () => {
30       router.push({ name: 'ElementIndex' })
31     }
32     ElMessage.success(inject('provideData'))
33     onMounted(() => {
34       // const { ctx } = getCurrentInstance()
35       // ctx.$message.success(inject('provideData'))
36       // console.log(inject('provideData'))
37     })
38     return {
39       homeInput,
40       toElement
41     }
42   }
43 }
44 </script>

6. getCurrentInstance获取当前组件实例

  import { getCurrentInstance } from 'vue'

  const { ctx } = getCurrentInstance()

7. 插槽slot

父组件:```

    <HelloWorld :propsMsg="propsMsg">
      <template #backBtn>
        <router-link to="/setup">
          <el-button type="primary" plain>Setup</el-button>
        </router-link>
      </template>
    </HelloWorld>

```

子组件:```

<template>
  <div class="hello">
    <h1 class="left">{{ propsMsg.msg }} {{ propsMsg.name }} {{ homeInput }}</h1>
    <div class="right">
      <el-button type="primary" plain @click="toElement">Element-Plus</el-button>
      <slot name="backBtn"></slot>
    </div>
  </div>
</template>

```

8. 生命周期

  3.x移除了2.x中的beforeCreatecreated钩子,通过setup方法代替

 1 import {
 2   onBeforeMount,
 3   onMounted,
 4   onBeforeUpdate,
 5   onUpdated,
 6   onBeforeUnmount,
 7   onUnmounted
 8 } from 'vue'
 9 
10 export default {
11   setup() {
12     onBeforeMount(() => {
13       console.log('onBeforeMount')
14     })
15     onMounted(() => {
16       console.log('onMounted')
17     })
18     onBeforeUpdate(() => {
19       console.log('onBeforeUpdate')
20     })
21     onUpdated(() => {
22       console.log('onUpdated')
23     })
24     onBeforeUnmount(() => {
25       console.log('onBeforeUnmount')
26     })
27     onUnmounted(() => {
28       console.log('onUnmounted')
29     })
30   }
31 }

三、Composition API及代码复用

  vue2.x中,所有的数据都在data方法中定义返回,方法定义在methods下面,并通过this调用vue3.x中,所有的代码逻辑将在setup方法中实现,包括datawatchcomputedmethodshooks,并且不再有this;vue3.x setup方法在组件生命周期内只执行一次,不会重复执行,相比vue2.x中基于OPTIONS配置的方式,vue3.x基于组合式API的方式语义没有2.x清晰,2.x中datamethodscomputedwatch等都通过不同的scope区分开,看起来很清晰,3.x都放在setup方法中,对代码组织能力会有更高的要求。

 代码复用:

 1 import { reactive, ref, getCurrentInstance } from 'vue'
 2 
 3 const setupTest = function() {
 4   const { ctx } = getCurrentInstance()
 5   const propsMsg = reactive({
 6     msg: 'Hello',
 7     name: 'Jiangzi',
 8     age: 18
 9   })
10   const myInput = ref()
11   const formRef = ref()
12 
13   return {
14     ctx,
15     propsMsg,
16     myInput,
17     formRef
18   }
19 }
20 
21 export default setupTest

 引入:

 1 <template>
 2   <div class="home">
 3     <HelloWorld :propsMsg="propsMsg">
 4       <template #backBtn>
 5         <router-link to="/">
 6           <el-button type="primary" plain>Home</el-button>
 7         </router-link>
 8       </template>
 9     </HelloWorld>
10     <h2>HelloWorld Input</h2>
11     <input v-model="myInput" />
12   </div>
13 </template>
14 
15 <script>
16 import setupTest from '@/composition/setup'
17 import HelloWorld from '@/components/HelloWorld.vue'
18 import { provide } from 'vue'
19 export default {
20   name: 'Setup',
21   components: {
22     HelloWorld
23   },
24   setup() {
25     // const formRef = ref()
26     const {
27       propsMsg,
28       myInput
29     } = setupTest()
30     provide('provideData', 'provide data from setup')
31     return {
32       propsMsg,
33       myInput
34     }
35   }
36 }

四、router路由

  获取路由配置项:

  this.$router.options.routes

  当前路由组件名:

  this.$router.currentRoute.value.name

 1 <script>
 2 export default {
 3   name: 'ElementNav',
 4   data() {
 5     return {
 6       menuList: [],
 7       activeName: ''
 8     }
 9   },
10   created() {
11     this.$router.options.routes.forEach((item) => {
12       if (item.desc === 'element-plus') {
13         this.menuList = item.children
14       }
15     })
16     // console.log(this.menuList)
17     let currentRouteName = this.$router.currentRoute.value.name
18     // console.log(currentRouteName)
19     this.activeName = currentRouteName
20   },
21   mounted() {},
22   methods: {
23     menuClick(item) {
24       this.activeName = item.name
25     },
26     handleOpen(key) {
27       // console.log(key, keyPath)
28       if (key) {
29         this.$router.push({ name: key })
30       }
31     },
32     handleClose(key) {
33       if (key) {
34         this.$router.push({ name: key })
35       }
36     }
37   }
38 }
39 </script>

  项目配置页路由

  1 // eslint-disable-next-line
  2 import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
  3 import Home from '@/views/Home.vue'
  4 const Test = () => import('@/views/Test.vue')
  5 const Setup = () => import('@/views/Setup.vue')
  6 const ElementIndex = () => import('@/views/element/ElementIndex.vue')
  7 const ElementHome = () => import('@/views/element/ElementHome.vue')
  8 const ElementForm = () => import('@/views/element/ElementForm.vue')
  9 const ElementTree = () => import('@/views/element/ElementTree.vue')
 10 const ElementUpload = () => import('@/views/element/ElementUpload.vue')
 11 const ElementTable = () => import('@/views/element/ElementTable.vue')
 12 const ElementPages = () => import('@/views/element/ElementPages.vue')
 13 const ElementCarousel = () => import('@/views/element/ElementCarousel.vue')
 14 const ElementCalendar = () => import('@/views/element/ElementCalendar.vue')
 15 const ElementTransfer = () => import('@/views/element/ElementTransfer.vue')
 16 
 17 const routes = [
 18   {
 19     path: '/',
 20     name: 'Home',
 21     component: Home
 22   },
 23   {
 24     path: '/test',
 25     name: 'Test',
 26     // route level code-splitting
 27     // this generates a separate chunk (about.[hash].js) for this route
 28     // which is lazy-loaded when the route is visited.
 29     component: Test
 30   },
 31   {
 32     path: '/setup',
 33     name: 'Setup',
 34     component: Setup
 35   },
 36   {
 37     path: '/element',
 38     name: 'ElementIndex',
 39     component: ElementIndex,
 40     redirect: '/element/home',
 41     desc: 'element-plus',
 42     children: [
 43       {
 44         path: '/element/home',
 45         name: 'ElementHome',
 46         component: ElementHome,
 47         desc: '基础组件',
 48         icon: 'el-icon-office-building'
 49       },
 50       {
 51         path: '/element/form',
 52         name: 'ElementForm',
 53         component: ElementForm,
 54         desc: 'Form表单',
 55         icon: 'el-icon-message'
 56       },
 57       {
 58         path: '/element/tree',
 59         name: 'ElementTree',
 60         component: ElementTree,
 61         desc: '树形控件',
 62         icon: 'el-icon-grape'
 63       },
 64       {
 65         path: '/element/upload',
 66         name: 'ElementUpload',
 67         component: ElementUpload,
 68         desc: '上传组件',
 69         icon: 'el-icon-upload2'
 70       },
 71       {
 72         path: '/element/table',
 73         name: 'ElementTable',
 74         component: ElementTable,
 75         desc: 'Table表格',
 76         icon: 'el-icon-s-grid'
 77       },
 78       {
 79         path: '/element/pages',
 80         name: 'ElementPages',
 81         component: ElementPages,
 82         desc: 'pages分页',
 83         icon: 'el-icon-folder-opened'
 84       },
 85       {
 86         path: '/element/carousel',
 87         name: 'ElementCarousel',
 88         component: ElementCarousel,
 89         desc: '走马灯',
 90         icon: 'el-icon-picture'
 91       },
 92       {
 93         path: '/element/calendar',
 94         name: 'ElementCalendar',
 95         component: ElementCalendar,
 96         desc: '日历',
 97         icon: 'el-icon-date'
 98       },
 99       {
100         path: '/element/transfer',
101         name: 'ElementTransfer',
102         component: ElementTransfer,
103         desc: '穿梭框',
104         icon: 'el-icon-d-arrow-right'
105       }
106     ]
107   }
108 ]
109 
110 const router = createRouter({
111   // history: createWebHistory(process.env.BASE_URL), // HTML5模式路由
112   history: createWebHashHistory(process.env.BASE_URL), // 哈希路由
113   routes
114 })
115 
116 export default router

五、vuex状态管理

1. 提交

  import store from '@/store/index'
  watchEffect(() => {
    store.commit('setHomeInput', myInput.value)
  })
2. 获取
    const homeInput = computed(() => {
      return store.state.homeInput
    })
 1 import { createStore } from 'vuex'
 2 
 3 export default createStore({
 4   state: {
 5     homeInput: ''
 6   },
 7   mutations: {
 8     setHomeInput(state, data) {
 9       state.homeInput = data
10     }
11   },
12   actions: {},
13   modules: {}
14 })
原文地址:https://www.cnblogs.com/bushan/p/14598513.html