当前位置: 首页 > article >正文

unity lua属性绑定刷新

我们现在有一个 角色属性类叫heroModel,内容如下,当heroModel中的等级发生变化的时候,我们需要刷新界面显示等级信息,通常我们是在收到等级升级成功的协议的时候,发送一个事件,UI界面接受到这个事件的时候,刷新一下等级信息,如果不采用全局事件的方式,该怎么处理呢
我们能不能监听HeroModel的level这个属性,给这个属性绑定一个监听方法,当这个属性发生变化的时候,自动执行这个监听方法执行一些刷新操作。

local heroModel = {
        id = 1001,
        star = 1,
        level = 1, 
        life = 1000,
        atk = 100,
        def = 10,
    }
   

我们知道,lua有两个比较常见的原方法 __index 和 __newindex,__index是 元表提供的表对象内部数据获取元方法,__newindex是当对表中不存在的元素进行赋值时会被调用。当我们从heroModel中获取某一个属性值的时候,会先从heroModel中取值,如果heroModel中不存在该值,则会从原表中取值,同样当我们给heroModel赋值的时候,会先判断heroModel是否存在该属性,如果存在,直接赋值,不存在则从原方法 __newindex中进行赋值。加入heroModel中不存在level这个属性,那么我们给它赋值的时候,肯定会调用原方法__newindex ,这个时候我们就可以在这个原方法里面赋值的时候进行判断,属性level是否发生变化,如果发生了变化, 则执行一个回调方法

简单演示如下

local heroModel = {
         id = 1001, star = 1, level=1
     }

    ---创建原表
    local metaTable = {}
        metaTable.newInfo = {}  --保存新创建的属性值
        metaTable.bindDataList = {}  --存储回调方法
        metaTable.__index = function(t , k)
            printError("get " .. k)
            local res = metaTable.newInfo[k]
            return res
         end

        metaTable.__newindex = function(t, k, v)
            printError("set " .. k .. " = " .. tostring(v))
            if (not metaTable.newInfo[k] or metaTable.newInfo[k] ~= v) and metaTable.bindDataList[k] ~= nil then
                local callback = metaTable.bindDataList[k]
                callback()
            end
            metaTable.newInfo[k] = v
            return v
        end

    -- 将heroModel中的属性赋值到原表,并清空heroModel,这样操作之后,只要给heroModel进行赋值就会执行它的原方法 __newindex
     for k, v in pairs(heroModel) do
         metaTable.newInfo[k] = v
         heroModel[k] = nil
     end
    -- 设置元表
     setmetatable(heroModel, metaTable)

   -- 绑定回调方法
    metaTable.bindDataList["level"] = function()
        printError("level 值发生了变化")
    end

    --测试
    printError("----test---")
    printError("level 初始值 = "..tostring(heroModel.level)) --没有更新赋值时候进行调用
    heroModel.level = 10 --通过__newindex 刷新属性值,并执行回调
    heroModel.level = 11
    local b = heroModel.level --通关__index 获取新属性值
    printError("level新值 = " .. b)
    heroModel.kkk = 111 --通过__newindex 创建新属性值
    printError(heroModel.kkk) --通关__index 获取新属性值

输出结果

在这里插入图片描述

完整代码

DataBindModel = {}

---@class DataBindModel:nil
local DataBindModel = DataBindModel

---给实例添加绑定 内部方法 不要手动调用
---@param target dataBindInfo
function DataBindModel:__bindIns(target)
    if (target.dataBindvars) then
        return
    end
    local dataBindvars = {}
    local mateTable = getmetatable(target)
    setmetatable(dataBindvars, mateTable)

    for k, v in pairs(target) do
        dataBindvars[k] = v
        target[k] = nil
    end
    target.dataBindvars = dataBindvars
    target.bindInfo__ = {}
    target.isBind = false
    target.oldMateTable = mateTable
    local settable = { __index = function(t, key)
        return dataBindvars[key]
    end }
    settable.__newindex = DataBindModel.__newindex
    setmetatable(target, settable)
end

function DataBindModel:unBindIns(target)
    if (not target.dataBindvars) then
        return
    end
    local dataBindvars = target.dataBindvars
    local mateTable = target.oldMateTable
    target.oldMateTable = nil
    target.bindInfo__ = nil
    target.isBind = nil
    target.dataBindvars = nil
    setmetatable(target, mateTable)
    for k, v in pairs(dataBindvars) do
        target[k] = v
    end
end

function DataBindModel:newIndex(key)
    return self.dataBindvars[key]
end

function DataBindModel:__newindex(key, var)
    local vars = self.dataBindvars
    local oldValue = vars[key]
    vars[key] = var

    if (self.isBind) then

        if (oldValue ~= var) then
            local bindInfo__ = self.bindInfo__
            local bindData = bindInfo__[key]
            if (bindData) then
                local tempBindData = {}
                for i, bdata in ipairs(bindData) do
                    table.insert(tempBindData, bdata)
                end
                for i, bdata in ipairs(tempBindData) do
                    bdata.callBack(var, bdata, self)
                end
                tempBindData = nil
            end
        end
    end

end

---@param target any @model
---@param bindInfo dataBindInfo
function DataBindModel:bindKey(target, bindInfo)
    if not target then
        printWarningColor("FFB500FF", "dataModel is nil")
        return
    end

    if (not target.dataBindvars) then
        self:__bindIns(target)
    end
    local bindInfo__ = target.bindInfo__
    local bindData = bindInfo__[bindInfo.key]
    if (not bindData) then
        bindData = {}
        bindInfo__[bindInfo.key] = bindData
    end
    target.isBind = true
    local uiNode = bindInfo.uiNode
    if (uiNode and not tolua.isnull(uiNode)) then
        ---@type CS.NodeEventListener
        local nodeEventListener = uiNode:GetComponent(typeof(CS.NodeEventListener))
        if not nodeEventListener then
            nodeEventListener = uiNode.gameObject:AddComponent(typeof(CS.NodeEventListener))
            bindInfo.nodeEventHandle = function()
                self:unBindKey(target, bindInfo)
            end
            if nodeEventListener.destroyCallback then
                nodeEventListener.destroyCallback = nodeEventListener.destroyCallback + bindInfo.nodeEventHandle
            else
                nodeEventListener.destroyCallback = bindInfo.nodeEventHandle
            end
        end
    end
    table.insert(bindData, bindInfo)
end

---@param target any
---@param bindInfo dataBindInfo
function DataBindModel:unBindKey(target, bindInfo)
    if (not target.dataBindvars) then
        return
    end
    local bindInfo__ = target.bindInfo__
    local bindData = bindInfo__[bindInfo.key]
    if (bindData) then
        local index = table.indexof(bindData, bindInfo)
        if (index) then

            table.remove(bindData, index)
            local uiNode = bindInfo.uiNode
            if (uiNode and not tolua.isnull(uiNode)) then
                local nodeEventHandle = uiNode:GetComponent(typeof(CS.NodeEventListener))
                if nodeEventHandle then
                    nodeEventHandle.destroyCallback = nodeEventHandle.destroyCallback - bindInfo.nodeEventHandle
                end
            end
        end
        if (#bindData == 0) then
            bindInfo__[bindInfo.key] = nil
        end
    end
    local count = 0;
    for k, v in pairs(bindInfo__) do
        count = count + 1;
        break ;
    end
    if (count <= 0) then
        self:unBindIns(target)
    end
end

---@param bindDataInfos dataBindInfo
function DataBindModel:bindKeys(target, bindDataInfos)
    for i, data in ipairs(bindDataInfos) do
        self:bindKey(target, data)
    end
end

---@param bindDataInfos dataBindInfo
function DataBindModel:unBindKeys(target, bindDataInfos)
    for i, data in ipairs(bindDataInfos) do
        self:unBindKey(target, data)
    end
end

return DataBindModel

调用

注:DataBindModel 是一个全局table

local heroModel = {
         id = 1001, star = 1, level=1
     }
local bindDatas = {
	key = "level", 
	callBack = function(value, bindInfo, model)
		-- 执行刷新逻辑
		self:checkRed()
	end
}
DataBindModel:bindKeys(heroModel, bindDatas)

http://www.kler.cn/a/566706.html

相关文章:

  • C++ 设计模式 十一:代理模式 (读书 现代c++设计模式)
  • MySQL 和 Elasticsearch 之间的数据同步
  • docker里面pgadmin4自动备份pg数据库操作
  • NIM平台开发基于提示工程的大语言模型(LLM)应用
  • 笔记20250225
  • IP-----双重发布
  • 使用PDFMiner.six解析PDF数据
  • 【Rust中级教程】题外话:Rust + Python联合编程(基于Maturin)
  • 城电科技|会追日的智能花,光伏太阳花开启绿色能源新篇章
  • 一个便捷的web截图库~
  • 回溯算法(C/C++)
  • mysql中事务的基本概念
  • 开源PDF解析工具olmOCR
  • next.js-学习3
  • USRP4120-通用软件无线电平台
  • C语言一维数组的全面解析
  • CAN总线通信协议学习1——物理层
  • HarmonyOS 5.0应用开发——多线程Worker和@Sendable的使用方法
  • 版图自动化连接算法开发 00004 ------ 给定一个点,添加一个中间点实现 Manhattan 方式连接两个给定的坐标点
  • I2S音频开发(使用USB音频进行验证)