添加实例属性
基本示例
您可能希望在许多组件中使用一些数据/实用程序,但您不希望污染全局范围。 在这些情况下,您可以通过在原型上定义它们,使它们对每个 Vue 实例可用
|
现在 $appName
在所有 Vue 实例上都可用,甚至在创建之前。 如果我们运行
|
那么 "My App"
将被记录到控制台!
实例属性作用域的重要性
您可能想知道
“为什么
appName
以$
开头? 这很重要吗? 它做了什么?
这里没有魔法。 $
是 Vue 用于所有实例可用的属性的约定。 这避免了与任何定义的数据、计算属性或方法发生冲突。
“冲突? 你是什么意思?”
另一个好问题! 如果您设置
|
那么您期望下面记录什么?
|
它将是 "My App"
,然后是 "The name of some other app"
,因为 this.appName
被 data
覆盖(有点像)当实例被创建时。 我们使用 $
对实例属性进行作用域以避免这种情况。 如果您愿意,您甚至可以使用自己的约定,例如 $_appName
或 ΩappName
,以防止与插件或未来功能发生冲突。
现实世界示例:用 Axios 替换 Vue 资源
假设您正在替换现在已退役的 Vue 资源。 您非常喜欢通过 this.$http
访问请求方法,并且您希望用 Axios 代替它。
您所要做的就是将 axios 包含在您的项目中
|
将 axios
别名为 Vue.prototype.$http
|
然后您将能够在任何 Vue 实例中使用诸如 this.$http.get
之类的方法
|
原型方法的上下文
如果您不知道,添加到 JavaScript 原型中的方法将获得实例的上下文。 这意味着它们可以使用 this
访问实例上定义的数据、计算属性、方法或任何其他内容。
让我们在 $reverseText
方法中利用这一点
|
请注意,如果您使用 ES6/2015 箭头函数,上下文绑定将不会起作用,因为它们隐式绑定到其父作用域。 这意味着箭头函数版本
|
将抛出错误
|
何时避免这种模式
只要您在对原型属性进行作用域方面保持警惕,使用这种模式是相当安全的 - 也就是说,不太可能产生错误。
但是,它有时会导致与其他开发人员的混淆。 例如,他们可能会看到 this.$http
,然后想,“哦,我不知道 Vue 有这个功能!” 然后他们转到另一个项目,当 this.$http
未定义时感到困惑。 或者,也许他们想谷歌如何做某事,但找不到结果,因为他们没有意识到他们实际上是在使用 Axios 的别名。
便利性是以明确性为代价的。 当查看组件时,无法判断 $http
来自哪里。 Vue 本身? 插件? 同事?
那么有哪些替代方案呢?
替代模式
不使用模块系统时
在没有模块系统(例如通过 Webpack 或 Browserify)的应用程序中,有一个模式经常与任何 JavaScript 增强的前端一起使用:全局 App
对象。
如果您要添加的内容与 Vue 本身无关,这可能是一个不错的选择。 以下是一个示例
|
如果您对 Object.freeze
皱眉,它的作用是防止将来更改该对象。 这实质上使它的所有属性都成为常量,保护您免受未来的状态错误。
现在这些共享属性的来源更加明显:应用程序中某个地方定义了一个 App
对象。 要找到它,开发人员可以执行项目范围的搜索。
另一个优点是 App
现在可以在您的代码中的任何地方使用,无论它是否与 Vue 相关。 这包括将值直接附加到实例选项,而不是必须进入函数以访问 this
上的属性
|
使用模块系统时
当您可以使用模块系统时,您可以轻松地将共享代码组织成模块,然后在需要的地方 require
/import
这些模块。 这是明确性的典范,因为在每个文件中,您都会获得一个依赖项列表。 您确切地知道每个依赖项来自哪里。
虽然肯定更冗长,但这种方法绝对是最易于维护的,尤其是在与其他开发人员合作或构建大型应用程序时。