Bootstrap

【Vue】Pinia 和 ElementPlus组件库

目录

Pinia

Pinia的概念

是什么

使用目的

Pinia中存什么

Pinia的使用

下载pinia包

创建pinia实例并注册 

定义仓库

使用示例

ElementPlus组件库

ElementPlus组件库是什么

ElementPlus组件库的安装

安装

引入

测试

常用组件

Form表单组件

多选框分组

单选框分组

单个表单项校验

表单组件整体校验

form表单组件关于验证的函数

组件库提供的图标

Table表格组件

​编辑 对表格的列进行自定义

Tree树形组件

自定义节点内容

Dialog对话框组件

el-menu标签属性

菜单嵌套

添加图标

菜单分组


Pinia

Pinia的概念

是什么

Pinia是一个状态管理工具,vue的专属状态管理库,它可以让我们实现跨组件(多个组件)或页面共享状态。

使用目的

  1. 多个组件数据保持同步。
  2. 数据的变化是可追踪的。

Pinia中存什么

多个组件共享的数据,才存储在pinia中,某个组件的私有数据,依旧存储在组件自身内部。

比如:登录的用户名,在各个页面中都需要使用,则用户名存储在pinia中。


Pinia的使用

下载pinia包

npm install pinia

yarn add pinia

创建pinia实例并注册 

//main.js
//导入
import { createPinia } from 'pinia'


//创建pinia实例
const pinia = createPinia()


//注册pinia实例
app.use(pinia)

定义仓库

在/src/store/xxx.js文件下,定义仓库。

        store是用defineStore()定义的,它的第一个参数要求是独一无二的名字,这个名字也被用作id,是必须传入的,pinia将用它来连接store和devtools,我们将返回的函数命名为use..Store,这样符合组合式函数风格的约定。

        当组件需要获取这个共享仓库时,导入我们通过defineStore()定义的仓库,使用方法通过如下示例会更好理解。

使用示例

stock.js  (组合式定义store

//导入定义仓库函数
import { defineStore } from 'pinia'
import { ref } from 'vue'
//定义仓库
//defineStore(仓库id,函数或对象)

//函数传参
export const useStockStore=defineStore('stock',()=>{
    //提供共享数据
    const stock=ref(20)

    //提供修改数据的方法

    //增加stock数据
    function addStock(){
        stock.value++
    }

    //减少stock数据
    function subStock(){
        stock.value--
    }

    //返回数据和方法
    return{
        stock,
        addStock,
        subStock
    }

})

或者 stock.js(选项式定义store)

export const useStockStore=defineStore('stock',{
    //state:存放共享数据,类似于 setup传参时的ref或reactive,这里的数据是响应式的
    state:()=>({
        stock:0
    }),
    //getters:存放计算属性
    getters:{
        double:(state)=> state.stock*2
    },
    //actions:存放修改数据的函数
    actions:{
        addStock(){
            //this指向当前state对象
            this.stock++
        },
        subStock(){
            this.stock--
        }
    }
})

Add.vue 获取共享数据

<template>
<div class="add">
    <h3>Add组件</h3>
    <p>已知库存数:{{ stockStore.stock }}</p>
    <button @click="stockStore.addStock()">库存+1</button>
</div>
</template>

<script setup>
    //导入useStockStore函数
    import { useStockStore } from '@/store/stock.js'
    //调用函数,获取pinia仓库
    const stockStore = useStockStore()


</script>

<style scoped>

</style>

Sub.vue

<template>
<div class="sub">
    <h3>Sub组件</h3>
    <p>已知库存数:{{stockStore.stock}}</p>
    <button @click="stockStore.subStock()">库存-1</button>
</div>
</template>

<script setup>
    //导入useStockStore函数
    import { useStockStore } from '@/store/stock.js'
    //调用函数,获取pinia仓库
    const stockStore = useStockStore()

</script>

<style scoped>

</style>

App.vue 

<template>
  <h2>根组件</h2>
  库存总数:<input type="number" v-model.number="stockStore.stock" />
  <hr />
  <Add />
  <hr />
  <Sub />
</template>

<script setup>
import Add from './components/Add.vue'
import Sub from './components/Sub.vue'
import { useStockStore } from './store/stock'

const stockStore = useStockStore()
</script>

<style>
  #app{
    width: 350px;
    margin: 100px auto;
    padding: 5px 10px;
    border: 1px solid #ccc;
  }
</style>

ElementPlus组件库

以下是通过ElementPlus官方文档的学习笔记,官方文档链接如下:

一个 Vue 3 UI 框架 | Element Plus

ElementPlus组件库是什么

由饿了吗团队开发的,是一个基于vue3的PC端免费的组件库,目的就是为开发者提供一套灵活而优雅的组件,里面包含很多常见组件:比如按钮、表单、表格、字体图标等,还有一些高级组件,比如日期选择器、对话框。

ElementPlus组件库的安装

安装

第一种方法

npm install element-plus

第二种方法 

yarn add element-plus

第三种方法 

pnpm install element-plus

这三种按照个人喜好选择一种即可。 

引入

如果对打包后的文件大小不是很在乎,可以使用完整引入,一般而言PC端不太在意这个,所以这里我们使用完整引入。

在main.js中导入并注册

// main.js
import { createApp } from 'vue'

//导入ElementPlus组件库
import ElementPlus from 'element-plus'

//导入样式
import 'element-plus/dist/index.css'
import App from './App.vue'

const app = createApp(App)

//注册,这里是全局注册,一旦注册了,可以在任意vue文件中使用ElementPlus提供的组件

app.use(ElementPlus)
app.mount('#app')

测试

我们进入官方文档

一个 Vue 3 UI 框架 | Element Plusicon-default.png?t=O83Ahttps://element-plus.org/zh-CN/选择组件

查看组件库中提供的组件源代码,将其拷贝到我们的vue文件中,如果能正常显示,就代表安装成功了

如下:

常用组件

Form表单组件

多选框分组
const form = reactive({
    name: '',
    region: '',
    date1: '',
    date2: '',
    delivery: false,
    type: [],
    resource: '',
    desc: '',
})

这里 el-checkbox-group v-model="form.type",form.type如上所示是一个数组,这里多个选项我们需要定义一个数组来接收。

el-checkbox value="Online activities";这里的value属性是给type属性收集勾选选项的值使用的

<el-checkbox-group v-model="form.type">
     <el-checkbox value="Online activities" name="type">
            Online activities
     </el-checkbox>
     <el-checkbox value="Promotion activities" name="type">
            Promotion activities
     </el-checkbox>
     <el-checkbox value="Offline activities" name="type">
            Offline activities
     </el-checkbox>
     <el-checkbox value="Simple brand exposure" name="type">
            Simple brand exposure
     </el-checkbox>
</el-checkbox-group>
单选框分组

这里的resource由上面form对象的定义可以看出,他不是一个数组,因此只能那个接收一个。

<el-radio-group v-model="form.resource">
     <el-radio value="Sponsor">Sponsor</el-radio>
     <el-radio value="Venue">Venue</el-radio>
</el-radio-group>
单个表单项校验

单个表单项的校验,需要做3处绑定

1、el-form

        :model="表单对象"

        :rules="校验规则对象"

2、el-form-item:

        prop="要校验的字段名称"

3、表单控件:

        v-model="数据"

如下:

<el-form :model="form" :rules="rules" label-width="auto" style="max-width: 600px">

        <el-form-item label="Activity name" prop="name">

        <el-input v-model="form.name" />

</el-form-item>

这里的form就是我们创建好的,用来接收表单数据的对象

const form = reactive({
    name: '',
    region: '',
    date1: '',
    date2: '',
    delivery: false,
    type: [],
    resource: '',
    desc: '',
})

rules是我们定义好的表单规则,要校验的属性名:[{},{}],一个属性可以绑定多个校验规则

const rules = {
    name:[
        {
            //必填项
            required: true, 
            //不满足条件的错误提示信息
            message: 'Please input activity name', 
            //检验的触发时机:blur是在失去焦点的时候
            trigger: 'blur'
        },
        {
            //type:'date'  'array' 限制输入的类型
            //长度限制
            min: 3, 
            max: 50, 
            message: 'Length should be 3 to 50', 
            trigger: 'blur'
            
        }
    ]
}

这里prop的值是我们要校验的属性名,与form对象中定义的名字要保持一致。

表单组件整体校验

进行整体校验前,应要先给每个表单项绑定检验方法,也就是表单项校验方法

整体校验步骤如下:

  1. 通过ref属性,获取form表单组件实例
  2. 在form表单组件绑定ref属性,在js中通过对应的ref属性.value获取表单组件实例,在调用form提供的validate函数进行校验。
<template>
    <el-form ref="formRef" :model="form" :rules="rules" label-width="auto" style="max-width: 600px" >
    //……
</template>
import { ref } from 'vue'
const formRef = ref(null)
const onSubmit=()=>{
    formRef.value.validate((valid) => {
        if (valid) {
            console.log('验证通过')
        } else {
            console.log('验证失败')

        }
    })
}

 重置表单组件内容

const onCancel = () => {
    formRef.value.resetFields()
}
form表单组件关于验证的函数
名称

说明

validate((valid)=>{ })表单整体校验,全部通过valid为true,否则为false
resetFields()重置表单(把表单的值恢复成默认值,另一个会移除红色的错误校验结果)

组件库提供的图标

使用组件库提供的图标,我们先下载对应的包

npm install @element-plus/icons-vue

组件库提供类似于下面这种的图标

在main.js中导入我们需要使用的图标,如下导入User和Lock

//main.js
import {User,Lock} from '@element-plus/icons-vue'
app.component(User.name,User)
app.component(Lock.name,Lock)

 导入后,我们这里通过输入框的prefix-icon和suffix-icon属性来添加图标

<el-input v-model="username" placeholder="请输入用户名" prefix-icon="User"></el-input>

效果如下 

Table表格组件

el-table:表格组件

        data:数据源,也就是我们创建的数据数组名

        border:添加列之间的线

        stripe:设置表格斑马纹样式

        style:行内样式

el-table-colum:表示一列

        label:类名

        prop:要填充的数据属性名称,与数据源数组里的数据对象名保持一致

 对表格的列进行自定义

通过对表格的列进行自定义,我们可以添加样式

要对列进行自定义,el-table-colum中就不传prop属性,我们通过作用域插槽定义我们想要的结构。

        <el-table-column label="Date" width="180">
            <template #default="obj">
                <el-icon :size="14">
                    <Timer />
                </el-icon>
                <span>{{ obj.row.date }}</span>
            </template>
        </el-table-column>

通过slot可以获取到row、column、$index和store,我们将这些属性传递给obj(只是一个变量名字)对象,在通过这个对象访问这些属性,也可以直接对要获取的属性进行解构。

通过el-icon标签设置图标的大小。

效果如下:

Tree树形组件

示例效果如下:

如下代码: 

<template>
    <el-tree 
        style="max-width: 600px" 
        :data="data" 
        :props="defaultProps" 
        @node-click="handleNodeClick" />
</template>

<script lang="ts" setup>
interface Tree {
    label: string
    children?: Tree[]
}

const handleNodeClick = (data: Tree) => {
    console.log(data)
}

const data: Tree[] = [
    {
        label: 'Level one 1',
        children: [
            {
                label: 'Level two 1-1',
                children: [
                    {
                        label: 'Level three 1-1-1',
                    },
                ],
            },
        ],
    },
    {
        label: 'Level one 2',
        children: [
            {
                label: 'Level two 2-1',
                children: [
                    {
                        label: 'Level three 2-1-1',
                    },
                ],
            },
            {
                label: 'Level two 2-2',
                children: [
                    {
                        label: 'Level three 2-2-1',
                    },
                ],
            },
        ],
    },
    {
        label: 'Level one 3',
        children: [
            {
                label: 'Level two 3-1',
                children: [
                    {
                        label: 'Level three 3-1-1',
                    },
                ],
            },
            {
                label: 'Level two 3-2',
                children: [
                    {
                        label: 'Level three 3-2-1',
                    },
                ],
            },
        ],
    },
]

const defaultProps = {
    children: 'children',
    label: 'label',
}
</script>

1、el-tree标签的data属性绑定数据源数组,这个数组通过children来体现层级结构,可以不断嵌套,l数组内label标签树形为展示内容。

2、el-tree标签的props属性,指明渲染的属性名,默认渲染的是children和label,如果后台返回树形数据源里不叫label和children,那么可以通过props进行配置,指明children和label在数据源数组中对应属性名。

 3、@node-click="handleNodeClick"节点点击事件,这里data是当前节点对象

const handleNodeClick = (data: Tree) => {
    console.log(data)
}

4、给树形组件添加选择框,给el-tree标签添加 show-checkbox 属性

5、设置每次只有一个节点可以展开,给el-tree标签添加 accordion 属性

6、设置默认所有节点都展开,给el-tree标签添加 default-expand-all 属性

自定义节点内容

节点的内容支持自定义,我们可以在节点区添加按钮或者图标等,对树节点内容进行自定义有两种方法:render-content 和 scoped slot,这里使用 scoped slot,scoped slot会传入两个参数node和data,分别表示当前节点的Node对象和当前节点的数据,本质还是使用作用域插槽的方式。

<el-tree>

        <template #default="{node,data}">

                //自定义结构

         </template>

</el-tree>

Dialog对话框组件

1、这里el-dialog使用v-model绑定一个属性值,为true则对话框显示,false不显示,默认为false,当点击按钮时,属性值变为true。

<template>
  <el-button plain @click="dialogVisible = true">
    Click to open the Dialog
  </el-button>

  <el-dialog
    v-model="dialogVisible"
    title="Tips"
    width="500"
    :before-close="handleClose"
  >
    <span>This is a message</span>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="dialogVisible = false">Cancel</el-button>
        <el-button type="primary" @click="dialogVisible = false">
          Confirm
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessageBox } from 'element-plus'

const dialogVisible = ref(false)

const handleClose = (done: () => void) => {
  ElMessageBox.confirm('Are you sure to close this dialog?')
    .then(() => {
      done()
    })
    .catch(() => {
      // catch error
    })
}
</script>

2、el-dialog的title属性表示对话框标题显示的内容

3、:before-close="handleClose"表示对话框关闭前的回调函数 ,每次点击❌图标,或取消的时候,会触发绑定的回调函数

4、自定义对话框内容,使用默认插槽

<template #default>
     <el-form>
         <el-form-item label="账号">
            <el-input></el-input>
         </el-form-item>
         <el-form-item label="密码">
             <el-input></el-input>
         </el-form-item>
      </el-form>
</template>

5、具名插槽footer,自定义底部操作内容,具名插槽header自定义头部内容。

    <template #footer>
      <div class="dialog-footer">
        <el-button @click="dialogVisible = false">Cancel</el-button>
        <el-button type="primary" @click="dialogVisible = false">
          Confirm
        </el-button>
      </div>
    </template>

为网站提供导航功能的菜单

完整代码如下:

<template>

  <el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo" default-active="2"
    text-color="#fff" @open="handleOpen" @close="handleClose">
    <el-sub-menu index="1">
      <template #title>
        <el-icon>
          <location />
        </el-icon>
        <span>Navigator One</span>
      </template>
      <el-menu-item-group title="Group One">
        <el-menu-item index="1-1">item one</el-menu-item>
        <el-menu-item index="1-2">item two</el-menu-item>
      </el-menu-item-group>
      <el-menu-item-group title="Group Two">
        <el-menu-item index="1-3">item three</el-menu-item>
      </el-menu-item-group>
      <el-sub-menu index="1-4">
        <template #title>item four</template>
        <el-menu-item index="1-4-1">item one</el-menu-item>
      </el-sub-menu>
    </el-sub-menu>
    <el-menu-item index="2">
      <el-icon><icon-menu /></el-icon>
      <span>Navigator Two</span>
    </el-menu-item>
    <el-menu-item index="3" disabled>
      <el-icon>
        <document />
      </el-icon>
      <span>Navigator Three</span>
    </el-menu-item>
    <el-menu-item index="4">
      <el-icon>
        <setting />
      </el-icon>
      <span>Navigator Four</span>
    </el-menu-item>
  </el-menu>
</template>

<script lang="ts" setup>
import {
  Document,
  Menu as IconMenu,
  Location,
  Setting,
} from '@element-plus/icons-vue'
const handleOpen = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
</script>
<style>
  .el-menu{
    width: 350px;
  }
</style>
el-menu标签属性
  • active-text-color:选中文本颜色
  •  background-color:菜单背景颜色
  • default-active:默认选中的菜单,根据el-sub-menu的index属性
  • text-color:文字的默认颜色
  • @open:sub-menu菜单展开触发的事件
  • @close:sub-menu菜单关闭触发的事件
菜单嵌套

如果菜单项需要包含子菜单使用 el-sub-menu内包含子菜单,不需要则直接使用el-menu-item标签,通过插槽设置菜单内容

<el-sub-menu index="1-4">
    //当前菜单项显示的内容
    <template #title>item four</template>
    //这里可以继续嵌套el-sub-menu
    <el-menu-item index="1-4-1">item one</el-menu-item>
</el-sub-menu>
添加图标

菜单项添加图标可以使用如下格式:

<el-menu-item index="2">
    <el-icon><icon-menu /></el-icon>
    <span>Navigator Two</span>
</el-menu-item>
菜单分组

若需要将子菜单进行分组,可以通过el-menu-item-group标签来实现

<el-menu-item-group title="Group One">
     <el-menu-item index="1-1">item one</el-menu-item>
     <el-menu-item index="1-2">item two</el-menu-item>
</el-menu-item-group>

;