zoukankan      html  css  js  c++  java
  • 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 })
  • 相关阅读:
    使用Jmeter进行http接口测试
    Jmeter分布式压测
    Jmeter进阶技能-数据库信息,传递参数
    解决Mac OS X 升级10.10(Yosemite)后ADT(Eclipse)无法找到真机
    bug list
    【adb工具包】Android的工具包log日志抓取
    【AI模型测试】运行过程中出错和解决方案:ImportError: cannot import name '_validate_lengths'
    【AI模型测试】anaconda linux 常用命令、安装源、清理缓存(转)
    【AI模型测试】skimage库安装(转)
    【Python学习】pip 常用命令及控制台怎么查看python 及pip 和已安装包版本号(转)
  • 原文地址:https://www.cnblogs.com/bushan/p/14598513.html
Copyright © 2011-2022 走看看