我将以代码配合理论讲解一下个人对数据驱动思想应用在项目实际中的效果。数据驱动视图的开发思想,数据驱动视图的原理,以代码的形式展现vue3数据驱动视图的业务实现!(案例就不单独写了,是从小demo里拆出来的代码,大家理解思路就行,不用太在乎代码。代码用的naiveui组件,不会这个组件的别看template,否则会看懵的

logo.PNG

MVVM模式(vue):

由VIewModel视图模型作为中间角色,连接View页面视图和Model数据的模式被成为MVVM模式。

MVVM模式的特点:

1、避免了XSS攻击风险

2、没有节点查找过程,性能强

3、视图模型拥有完全编程能力,可以随意控制页面节点

image.png

具体见:Vue的MVVM原理

演示代码:

案例:以下代码的作用是当点击tab切换时,用v-model双向绑定数据,绑定到handle,而handel是通过计算属性的set和get来控制,读取此值时,触发get函数,实现get函数里的路由判断并赋值的操作,可以用来动态改变标题。当点击另一个tabs时,会执行设置set操作,在此操作里,我们可以用路由进行跳转。那么便不再需要单独绑定点击事件的函数方法了

<script setup>
import { useRoute, useRouter } from 'vue-router'
import { computed } from 'vue'
const route = useRoute()
const router = useRouter()

const base = '/display/dynamic/' //此页面已知的路由
const handle = computed({  //计算属性,数据驱动视图的思想
    get: () => { //读取,不是分类管理就是列表管理
        return route.path === base + 'category' ? '分类管理' : '列表管理'
    },
    set: (val) => { //写入,如果值改变,则判断值是否是分类管理,从而三元判断路由,赋值路由切换页面
        const path = base + (val === '分类管理' ? 'category' : 'list')
        router.push(path) //切换页面
    }
})
</script>
<template>
    <n-card title="动态管理">
        <n-tabs type="line" animated v-model:value="handle"> //双向绑定,数据驱动视图
            <n-tab-pane name="分类管理" title="分类">
            </n-tab-pane>
            <n-tab-pane name="列表管理" title="列表">
            </n-tab-pane>
        </n-tabs><router-view />
    </n-card>
</template>


案例:

下方案例主要使用watch副作用函数(侦听器)。

deep设置为true可以深度监听,例如对象属性改变,例如数组的值改变

immediate挂载执行一次

监听分页数据:当页面挂载后立即执行一次发送请求获取到table列表数据并渲染到页面上。开启了深度监听此对象,当次对象的数据一改变,例如页码、条数一改变则立刻会被深度监听到,监听到则执行回调函数,执行回调时,会自动发送请求,重新数据table数据并渲染。而再也不需要写点击事件去主动修改数据并发送请求。只需要使用侦听器监听数据的改变,数据一改变立刻发送请求。


<script setup>
import request from '@/utils/request'
import { NButton } from 'naive-ui'
import { ref, computed, watch } from 'vue'
import { Add, Remove } from '@vicons/ionicons5'
const schools = ref([])
// 先获取校区数据
request.get('/schools').then(res => {
    schools.value = res
})
// 选项
const schoolOptions = computed(() => schools.value.map(item => ({
    label: item.name,
    value: item.id
})))
const params = ref({
    schoolId: 1,
    page: 1,
    pageSize: 10
})

const result = ref({
    total: 0,
    data: []
})
// 什么时候发查询请求?
// 查询涉及的条件,变化的时候,发请求
// 数据驱动的思想:数据变化,页面自动更新
// Vue 是一个数据驱动的,MVVM 框架,watch/computed
watch(params, (val) => {
    // order asc 正序  desc 倒叙
    request.get('/dynamicCategories', { params: { _page: val.page, _limit: val.pageSize, schoolId: val.schoolId, _sort: 'id', _order: 'desc' } }).then(res => {
        result.value = res
    })
    // immediate: true 组件初始化立即执行一次
}, { immediate: true, deep: true })


// 是否展示弹框
const showEdit = ref(false)
// 选中的分类
const selected = ref(null)
// 编辑分类名称
const name = ref('')
const columns = [{ type: "selection" }, {
    title: "分类名称",
    key: "name"
}, {
    title: "动态数",
    key: "num"
}, {
    title: "创建时间",
    key: "created"
}, {
    title: "操作",
    render(item) {
        return <NButton type="primary" size='small' onClick={ () => {
            showEdit.value = true
            selected.value = item
            name.value = item.name
        } }>编辑</NButton>
    }
}]

const confirmChangeCategory = () => {
    if (!name.value) {
        $message.warning('请输入分类名称')
        return
    }
    if (selected.value) {
        request.patch('/dynamicCategories/' + selected.value.id, { name: name.value }).then(() => {
            $message.success('修改成功')
            showEdit.value = false
            params.value = { ...params.value }
            selected.value = null
        })
    } else {
        request.post('/dynamicCategories', { name: name.value, schoolId: params.value.schoolId, created: new Date().toLocaleDateString().replaceAll('/', '-'), num: 0 }).then(() => {
            $message.success('添加成功')
            showEdit.value = false
            params.value = { ...params.value }
        })
    }
}
// 选择的删除项
const deletes = ref([])
const onDelete = () => {
    $dialog.warning({
        title: "批量删除",
        content: "确定要删除所选项么?",
        positiveText: "确认删除",
        onPositiveClick: () => {
            const getDelete = (id) => request.delete('/dynamicCategories/' + id)
            // Promise.allSettled
            // all 所有请求都返回  allSettled  所有请求都结束

            Promise.allSettled(deletes.value.map(getDelete)).then(() => {
                $message.success('删除成功')
                params.value = { ...params.value, page: 1 }
                deletes.value = []
            })
        }
    })
}
</script>
<template>
    <div>
        <div>
            <n-form inline>
                <n-form-item label="校区">
                    <n-select v-model:value="params.schoolId" :options="schoolOptions" style="width: 200px"></n-select>
                </n-form-item>
            </n-form>
            <n-space style="display:flex;flex-flow:row nowrap">
                <n-button type="primary" @click="showEdit = true">
                    <n-icon>
                        <add />
                    </n-icon>
                    添加</n-button>
                <n-button type="error" @click="onDelete">
                    <n-icon>
                        <remove />
                    </n-icon>
                    删除</n-button>
            </n-space>
        </div>
        <n-data-table :row-key="row => row.id" :columns="columns" :data="result.data" :pagination="false" :bordered="false"
            v-model:checked-row-keys="deletes" />
        <n-pagination v-model:page-size="params.pageSize" v-model:page="params.page" :item-count="result.total"
            show-quick-jumper style="margin-top: 1em;" show-size-picker :page-sizes="[10, 20, 50]">
            <template #goto>
                跳转至
            </template>
        </n-pagination>
        <n-modal v-model:show="showEdit">
            <n-card style="width:400px" :title="(selected ? '编辑' : '添加') + '分类'">
                <n-input placeholder="分类名称" v-model:value="name"></n-input>
                <template #footer>
                    <n-button type="primary" style="float:right" @click="confirmChangeCategory">确定</n-button>
                </template>
            </n-card>
        </n-modal>
    </div>
</template>

<style scoped>
.container {
    .header {
        display: flex;
        flex-flow: row nowrap;
        justify-content: space-between;
        align-items: end;
        margin-bottom: 20px;
    }
}
</style>

关于数据驱动思想总结:

由于今晚时间关系暂不整理这篇文章,以后整理了重新补发。

现在总结一下vue3数据驱动视图的开发思想:

1、通过computed计算属性去做一些数据的计算,当数据的依赖发生改变时,即可自动做一些逻辑处理(例如发送请求)

2、通过computed计算属性的set和get,当此属性被读取或者修改时,自动做一些逻辑处理

3、通过watch监听,监听某个变量,可以预先处理一次,可以深度监听。当数据改变时,自动做一些逻辑请求

我们只需要关注数据的变化,由数据变化自动做一些逻辑处理,而不需要过于关注页面事件,逻辑处理等



(以下是个人所理解的vue3数据驱动视图的实际应用,仅供参考哦)