事情是这样的,我接到的需求是要做一个表单的动态效果,预期效果如图:
也就是更改了之后会把对应表单的标签变成红色,现在出现的问题是,当我操作其他数据的时候,即使我没有做更改他也会报错误高亮
这是全局指令的相关代码
export default {
bind(el, binding, vnode) {
resetInitialState(vnode); // 重置初始状态
},
inserted(el, binding, vnode) {
vnode.context.$nextTick(() => {
initializeState(el, binding, vnode);
});
},
update(el, binding, vnode, oldVnode) {
if (binding.value !== binding.oldValue) {
vnode.context.$nextTick(() => {
let id = vnode.context.form.id
let newVal = binding.value
let oldValue = binding.oldValue
let edited = false
if (id && newVal !== undefined && oldValue !== undefined) {
if (newVal !== oldValue) {
edited = true
}
}
updateLabelStyle(el, edited);
initializeState(el, binding, vnode);
});
}
},
unbind(el, vnode) {
resetInitialValues(vnode); // 重置初始值
if (el._observer) {
el._observer.disconnect();
}
},
};
function updateLabelStyle(el, edited) {
const labelElement = el.querySelector('label');
if (labelElement) {
edited ? labelElement.classList.add('edited-label') : labelElement.classList.remove('edited-label');
}
}
function resetInitialState(vnode) {
vnode.context.initialValues = {};
}
function resetInitialValues(vnode) {
const instanceUid = vnode.context._uid;
if (vnode.context.initialValues && vnode.context.initialValues[instanceUid]) {
delete vnode.context.initialValues[instanceUid];
}
}
function initializeState(el, binding, vnode) {
const propName = binding.expression;
const instanceUid = vnode.context._uid;
let initialValues = vnode.context.initialValues;
if (!initialValues) {
vnode.context.initialValues = initialValues = {};
}
if (!initialValues[instanceUid]) {
initialValues[instanceUid] = {};
}
const isNewForm = binding.modifiers.new;
if (isNewForm) {
initialValues[instanceUid][propName] = null;
} else if (initialValues[instanceUid][propName] === undefined) {
initialValues[instanceUid][propName] = JSON.stringify(binding.value);
}
const updateLabelStyle = (edited) => {
const labelElement = el.querySelector('label');
if (labelElement) {
edited ? labelElement.classList.add('edited-label') : labelElement.classList.remove('edited-label');
}
};
const updateLabelColor = (newVal) => {
let newValue = newVal === undefined || newVal === '' ? '' : JSON.stringify(newVal);
updateLabelStyle(newValue !== initialValues[instanceUid][propName]);
};
updateLabelColor(binding.value);
vnode.context.$watch(propName, (newVal) => {
vnode.context.$nextTick(() => {
updateLabelColor(newVal);
});
}, { deep: true });
const updateLabelCallback = () => updateLabelColor(vnode.context[propName]);
const classList = ['el-select', 'el-radio-group', 'el-input-number', 'el-checkbox-group', 'el-date-picker'];
for (const className of classList) {
if (el.classList.contains(className)) {
el._observer = observeElement(el.querySelector(`.${className.split('-').slice(-1)[0]}`), updateLabelCallback);
break;
}
}
}
function observeElement(element, callback) {
if (element) {
const observer = new MutationObserver(callback);
observer.observe(element, {
attributes: true,
childList: true,
subtree: true,
});
return observer;
}
}
最好是能远程帮看一下
先确认下问题,
也就是原本要求是:
A标签对应内容修改的话,那么A标签变红色
B/C/D其余标签没有内容修改那么不变化
现在的问题是:
A标签修改内容后,A标签变色
但是没有修改的B标签也变色了?
这个你想的复杂了 添加一个事件就解决了
initializeState这个函数换成下面代码试试
function (el, binding, vnode) {
const propName = binding.arg || "value";
const instanceUid = vnode.context.$options._uid;
let initialValues = vnode.context._initialValues;
if (!initialValues) {
vnode.context._initialValues = initialValues = {};
}
if (binding.modifiers.new) {
initialValues[propName] = null;
} else {
initialValues[propName] = JSON.stringify(binding.value);
}
function updateLabelStyle(edited) {
if (edited) {
el.classList.add("edited-label");
} else {
el.classList.remove("edited-label");
}
}
function updateLabelColor(newVal) {
const initialValue = initialValues[propName];
if (JSON.stringify(newVal) !== initialValue) {
updateLabelStyle(true);
} else {
updateLabelStyle(false);
}
}
updateLabelColor(binding.value);
vnode.context.$watch(
() => propName,
() => {
vnode.context.$nextTick(() => {
updateLabelColor(binding.value);
});
}
);
const classList = ["form-control", "custom-select", "checkbox", "radio"];
classList.forEach((className) => {
if (el.classList.contains(className)) {
const observer = observeElement(el, updateLabelColor);
}
});
}
function observeElement(element, callback) {
const observerConfig = { attributes: true, childList: true, subtree: true };
const observer = new MutationObserver(callback);
observer.observe(element, observerConfig);
return observer;
}
}
用vnode.context.$watch监听试一下呢
是不是null与空字符串的问题
【相关推荐】
加一个事件就行,
你的指令怎么使用的, 我看一看
刚才的完整代码
import { isEqual } from "lodash"
const isEmpty = val => {
return val === "" || val === undefined || val === null
}
const isChanged = (a, b) => {
if (isEmpty(a) && isEmpty(b)) {
return false
}
// 考虑输入框 数组变成 字符串
// 0 '0'
a = typeof a === "number" ? String(a) : a
b = typeof b === "number" ? String(b) : b
// TODO: 对象,select, checkbox 点击了之后之后数组顺序会变化,这里可能要考虑是否排序等
// ...
return !isEqual(a, b)
}
export default {
bind(el, binding, vnode) {
el.initialValue = binding.value
},
update(el, binding, vnode, oldVnode) {
const changed = isChanged(el.initialValue, binding.value)
const labelElement = el.querySelector("label")
// 添加一个状态,状态改变的时候再去设置
const statusChange = isChanged(el.changed, changed)
el.changed = changed
if (labelElement && statusChange) {
changed ? labelElement.classList.add("edited-label") : labelElement.classList.remove("edited-label")
}
}
}
你可以试着用v-model指令和watch属性来监听你表单值的变化,卡尼下能不能对应的更新样式。
如果以上回答对您有所帮助,点击一下采纳该答案~谢谢
引用Chatgpt回答
在Vue中,可以使用全局指令来改变表单样式。全局指令是可以在整个应用程序中重复使用的自定义指令。以下是一个示例,演示如何使用全局指令来改变表单样式:
form-style
:Vue.directive('form-style', {
bind: function (el, binding) {
// 在绑定元素时触发
el.style.border = '1px solid blue';
el.style.padding = '10px';
// 也可以根据传入的参数来动态改变样式
if (binding.value === 'red') {
el.style.border = '1px solid red';
el.style.padding = '5px';
}
}
});
<input v-form-style type="text" value="Sample Input">
这样,指令会自动应用到该输入框元素上,并改变其样式。
你也可以通过传递参数来动态改变样式。例如,以下代码将应用一个红色的边框和更小的内边距:
<input v-form-style="'red'" type="text" value="Sample Input">
请注意,该指令在所有使用v-form-style
的输入框上都会生效,因为它是一个全局指令。
这只是一个简单的示例,你可以根据自己的需求和具体的样式要求来自定义全局指令。希望这能帮到你!如果你有任何其他问题,请随时提问。