在有 Vue Router 的项目中如何在 Object 原型上增加方法

在Vue Router项目中,为Object.prototype添加自定义方法可能导致方法体内容被拼接到url参数里。原因是Vue Router的query.js中的resolveQuery函数在处理时,通过for-in遍历到了这个可枚举的log方法。解决方案是利用Object.defineProperty将方法设为不可枚举,以防止在for-in循环中被处理。建议避免直接修改内置对象的prototype,而是采用外置公共方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现象

在有 Vue Router 的项目开发过程中,在 Object.prototype 上挂自定义方法,会发现它的函数体内容会被拼接到 url 参数里。(下面以 Object.prototype.log 为例)

import Vue from 'vue'
import App from './App'
import router from './router'
// 在 Object.prototype 上挂了一个方法
Object.prototype.log = function() {
   
   
  console.log(this)
}
new Vue({
   
   
  el: '#app',
  router,
  components: {
   
    App },
  template: '<App/>'
}
<think>我们之前讨论的是一个处理SVG字符串的方法,现在用户希望在Vue2框架中重写这个方法。考虑到Vue2的特点,我们可能需要将这个功能封装成一个Vue的全局方法、实例方法、过滤器或者一个工具函数。这里我建议将其封装为一个工具函数,因为它是纯字符串处理,不涉及Vue的响应式系统。 但是,如果用户希望在Vue组件中方便地使用,我们可以将其挂载到Vue原型上,这样在组件中可以通过`this.$processSvg`来调用。 另外,由于SVG处理是纯字符串操作,我们也可以考虑将其写成一个独立的模块,然后在需要的地方导入。 根据用户提供的引用,Vue2中重写方法通常是通过修改原型来实现的(如引用[1]中重写VueRouter的push和replace方法)。因此,我们可以模仿这种方式,在Vue原型上添加我们的方法。 步骤: 1. 编写处理SVG字符串的函数,功能与之前相同。 2.Vue项目的入口文件(如main.js)中,将这个函数挂载到Vue原型上。 注意:由于处理SVG字符串不涉及Vue的响应式,所以不需要像数组方法重写那样(引用[2]和[4])考虑响应式更新。我们只需要一个纯函数。 实现: 在main.js中: ```javascript import Vue from 'vue' // 定义处理SVG的函数 function processSvg(svgStr) { // 这里实现之前讨论的SVG处理逻辑 // 包括提取样式和替换class='cls-2'为内联样式 // 返回修改后的SVG字符串和提取的样式规则 // 使用正则表达式提取样式 const extractedStyles = [] const stylePattern = /\.cls-2\s*{[^}]*}/g const styles = svgStr.match(stylePattern) if (styles) { extractedStyles.push(...styles) } // 替换class='cls-2'为内联样式fill:#7d928d // 注意:可能class属性值包含多个类,我们只替换掉cls-2,并保留其他类 // 使用正则表达式替换 // 思路:先解析XML,如果解析失败则用正则,但正则可能不够健壮,所以我们优先使用DOM解析,但考虑到在浏览器环境中我们可以使用DOMParser // 在浏览器环境中,我们可以使用DOMParser来解析和操作SVG const parser = new DOMParser() const doc = parser.parseFromString(svgStr, 'image/svg+xml') if (doc.documentElement.nodeName === 'parsererror') { // 解析错误,使用正则作为备选 const regex = /class\s*=\s*['"]\s*([^'"]*\bcls-2\b[^'"]*)['"]/g const modifiedSvg = svgStr.replace(regex, (match, classAttr) => { // 从class属性中移除cls-2 const newClass = classAttr.replace(/\bcls-2\b/g, '').trim() if (newClass) { return `class="${newClass}" style="fill:#7d928d"` } else { return 'style="fill:#7d928d"' } }) return { modifiedSvg, extractedStyles } } // 遍历所有元素 const elementsWithCls2 = doc.querySelectorAll('[class*="cls-2"]') elementsWithCls2.forEach(el => { const classes = el.getAttribute('class').split(/\s+/) const newClasses = classes.filter(cls => cls !== 'cls-2') if (newClasses.length) { el.setAttribute('class', newClasses.join(' ')) } else { el.removeAttribute('class') } // 设置内联样式 const currentStyle = el.getAttribute('style') || '' // 移除原有的fill属性(如果有) const styleObj = {} if (currentStyle) { currentStyle.split(';').forEach(decl => { if (decl.trim()) { const [prop, value] = decl.split(':').map(s => s.trim()) if (prop && value) { styleObj[prop] = value } } }) } // 设置fill styleObj['fill'] = '#7d928d' // 重新序列化style const newStyle = Object.entries(styleObj).map(([prop, value]) => `${prop}:${value}`).join(';') el.setAttribute('style', newStyle) }) // 将doc转回字符串 const serializer = new XMLSerializer() const modifiedSvg = serializer.serializeToString(doc) return { modifiedSvg, extractedStyles } } // 挂载到Vue原型 Vue.prototype.$processSvg = processSvg // 然后正常创建Vue实例 new Vue({ // ... options }) ``` 在组件中使用: ```javascript export default { methods: { someMethod() { const svgString = `...` // 你的SVG字符串 const { modifiedSvg, extractedStyles } = this.$processSvg(svgString) // 使用modifiedSvg } } } ``` 注意: 1. 由于使用了DOMParser和XMLSerializer,这个函数只能在浏览器环境中运行。 2. 如果需要在Node.js环境中运行,可以使用类似jsdom的库,但通常Vue项目运行在浏览器中,所以这里我们假设环境是浏览器。 另外,如果用户不希望修改原型,也可以将其导出为一个单独的模块,然后在需要的地方引入。 例如,创建一个文件`svgUtils.js`: ```javascript export function processSvg(svgStr) { // 同上 } ``` 然后在组件中引入: ```javascript import { processSvg } from '@/utils/svgUtils' export default { methods: { someMethod() { const result = processSvg(svgString) // ... } } } ``` 这样更符合模块化的思想,也便于测试。 根据用户的需求,他们要求重写之前的方法,并且参考了Vue2中重写方法的方式(修改原型)。因此,两种方式都可以,但修改原型的方式可以全局访问,而模块化的方式更灵活。 最后,考虑到用户可能需要在多个地方使用,我建议同时提供两种方式,但以修改原型的方式为主,因为用户要求“重写”,而引用中也是修改原型。 注意:在Vue3中,我们通常不会修改原型,而是使用插件或组合式API。但这里是Vue2。 相关问题: 1.何在Vue2中创建全局工具函数? 2. 如何处理SVG字符串以保留命名空间? 3.Vue2中重写方法时如何避免污染全局原型? 4. 如何为Vue2编写一个处理SVG的插件? 5. 在Node.js环境下如何实现相同的SVG处理功能?</think>在 Vue2 框架中重写 SVG 处理方法,可以通过原型扩展或全局混入实现。以下是完整的实现方案: ### 方法一:通过 Vue 原型扩展 (推荐) 在项目入口文件 `main.js` 中添加: ```javascript import Vue from 'vue' // 保存原始 SVG 处理方法 const originProcessSvg = Vue.prototype.$processSvg // 重写 SVG 处理方法 Vue.prototype.$processSvg = function(svgStr) { try { // 使用 DOMParser 解析 SVG const parser = new DOMParser() const doc = parser.parseFromString(svgStr, 'image/svg+xml') // 提取样式规则 const extractedStyles = [] const styleElements = doc.querySelectorAll('style') styleElements.forEach(style => { const matches = style.textContent.match(/\.cls-2\s*{[^}]*}/g) if (matches) extractedStyles.push(...matches) }) // 处理所有含 cls-2 的元素 const elements = doc.querySelectorAll('.cls-2') elements.forEach(el => { // 添加内联样式 const currentStyle = el.getAttribute('style') || '' const newStyle = currentStyle.replace(/fill:[^;]+;?/, '') + 'fill:#7d928d;' el.setAttribute('style', newStyle.trim()) // 更新 class 属性 const classes = el.className.baseVal ? el.className.baseVal.split(/\s+/) : el.getAttribute('class').split(/\s+/) const newClasses = classes.filter(cls => cls !== 'cls-2') if (newClasses.length > 0) { el.className.baseVal ? el.className.baseVal = newClasses.join(' ') : el.setAttribute('class', newClasses.join(' ')) } else { el.removeAttribute('class') } }) // 生成修改后的 SVG const serializer = new XMLSerializer() const modifiedSvg = serializer.serializeToString(doc) return { modifiedSvg, extractedStyles } } catch (error) { // 降级处理:使用正则表达式 console.error('XML 解析失败,使用正则降级处理', error) // 提取样式 const styleRegex = /\.cls-2\s*{[^}]*}/g const extractedStyles = (svgStr.match(styleRegex) || []) // 替换 class 属性 const modifiedSvg = svgStr.replace( /class\s*=\s*['"]([^'"]*\bcls-2\b[^'"]*)['"]/g, (match, classAttr) => { const newClasses = classAttr.replace(/\bcls-2\b/g, '').trim() return newClasses ? `class="${newClasses}" style="fill:#7d928d"` : 'style="fill:#7d928d"' } ) return { modifiedSvg, extractedStyles } } } // 可选:保留原始方法引用 Vue.prototype.$originProcessSvg = originProcessSvg ``` ### 方法二:通过全局混入 在 `main.js` 中添加: ```javascript import Vue from 'vue' Vue.mixin({ methods: { $processSvg(svgStr) { // 实现代码同上 } } }) ``` ### 在组件中使用 ```vue <template> <div> <div v-html="processedSvg"></div> </div> </template> <script> export default { data() { return { svgContent: `<?xml version="1.0" encoding="utf-8"?> <svg>...你的 SVG 内容...</svg>`, processedSvg: '' } }, mounted() { this.processSvg() }, methods: { processSvg() { const { modifiedSvg } = this.$processSvg(this.svgContent) this.processedSvg = modifiedSvg } } } </script> ``` ### 关键实现说明 1. **DOM 解析优先**: - 使用 `DOMParser` 解析 SVG,比正则更可靠[^1] - 正确处理 SVG 命名空间和复杂结构 - 通过 `XMLSerializer` 序列化回字符串 2. **多类名处理**: ```javascript // 处理 class="cls-1 cls-2" 情况 const classes = el.className.baseVal ? el.className.baseVal.split(/\s+/) : el.getAttribute('class').split(/\s+/) const newClasses = classes.filter(cls => cls !== 'cls-2') ``` 3. **样式合并**: ```javascript // 保留现有样式,只替换 fill const currentStyle = el.getAttribute('style') || '' const newStyle = currentStyle.replace(/fill:[^;]+;?/, '') + 'fill:#7d928d;' ``` 4. **降级处理**: - 当 XML 解析失败时自动使用正则表达式 - 处理 `class="cls-2"` 和 `class='cls-2'` 等多种格式 ### 注意事项 1. **浏览器兼容性**: - `DOMParser` 和 `XMLSerializer` 在现代浏览器中完全支持 - 如需支持 IE11,需添加 polyfill: ```bash npm install @polyfill.io/browser ``` 2. **性能优化**: - 对于大型 SVG,使用 `doc.querySelectorAll` 比递归遍历更高效 - 使用 `requestAnimationFrame` 处理超长 SVG 3. **安全考虑**: - 通过 `v-html` 渲染 SVG 时确保内容可信 - 使用 `DOMPurify` 清理不受信任的 SVG 内容 ```bash npm install dompurify ``` ```javascript import DOMPurify from 'dompurify' // 在返回前清理 const cleanSvg = DOMPurify.sanitize(modifiedSvg) return { modifiedSvg: cleanSvg, extractedStyles } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值