添加实例属性
这样 就在所有的 Vue 实例中可用了,甚至在实例被创建之前就可以。如果我们运行:
new Vue({
beforeCreate: function () {
console.log(this.$appName)
}
})
则控制台会打印出 My App
。就这么简单!
为实例属性设置作用域的重要性
你可能会好奇:
这里没有什么魔法。$
是在 Vue 所有实例中都可用的属性的一个简单约定。这样做会避免和已被定义的数据、方法、计算属性产生冲突。
“你指的冲突是什么意思?”
另一个好问题!如果你写成:
Vue.prototype.appName = 'My App'
那么你希望下面的代码输出什么呢?
new Vue({
data: {
// 啊哦,`appName` *也*是一个我们定义的实例属性名!😯
appName: 'The name of some other app'
},
beforeCreate: function () {
console.log(this.appName)
},
created: function () {
console.log(this.appName)
}
})
比如你打算替换已经废弃的 库。你实在是很喜欢通过 this.$http
来访问请求方法,希望换成 axios 以后还能继续这样用。
你需要做的事情是把 axios 引入你的项目:
设置 Vue.prototype.$http
为 axios
的别名:
然后你就可以在任何 Vue 实例中使用类似 this.$http.get
的方法:
new Vue({
el: '#app',
data: {
users: []
},
created () {
var vm = this
this.$http
.get('https://jsonplaceholder.typicode.com/users')
.then(function (response) {
vm.users = response.data
})
}
})
原型方法的上下文
你可能没有意识到,在 JavaScript 中一个原型的方法会获得该实例的上下文。也就是说它们可以使用 this
访问数据、计算属性、方法或其它任何定义在实例上的东西。
让我们将其用在一个名为 $reverseText
的方法上:
Vue.prototype.$reverseText = function (propertyName) {
this[propertyName] = this[propertyName]
.split('')
.reverse()
.join('')
}
new Vue({
data: {
message: 'Hello'
},
created: function () {
this.$reverseText('message')
console.log(this.message) // => "olleH"
})
注意如果你使用了 ES6/2015 的箭头函数,则其绑定的上下文不会正常工作,因为它们会隐式地绑定其父级作用域。也就是说使用箭头函数的版本:
会抛出一个错误:
Uncaught TypeError: Cannot read property 'split' of undefined
然而,有的时候它会让其他开发者感到混乱。例如他们可能看到了 this.$http
,然后会想“哦,我从来没见过这个 Vue 的功能”,然后他们来到另外一个项目又发现 this.$http
是未被定义的。或者你打算去搜索如何使用它,但是搜不到结果,因为他们并没有发现这是一个 axios 的别名。
这种便利是以显性表达为代价的。当我们查阅一个组件的时候,要注意交代清楚 $http
是从哪来的:Vue 自身、一个插件、还是一个辅助库?
那么有别的替代方案吗?
替代方案
在没有模块系统 (比如 webpack 或 Browserify) 的应用中,存在一种任何重 JS 前端应用都常用的模式:一个全局的 App
对象。
如果你想要添加的东西跟 Vue 本身没有太多关系,那么这是一个不错的替代方案。举个例子:
var App = Object.freeze({
name: 'My App',
version: '2.1.4',
helpers: {
// 这是我们之前见到过的 `$reverseText` 方法
// 的一个纯函数版本
reverseText: function (text) {
return text
.split('')
.reverse()
.join('')
}
}
})
如果你在好奇 Object.freeze
,它做的事情是阻止这个对象在未来被修改。这实质上是将它的属性都设为了常量,避免在未来出现状态的 bug。
现在这些被共享的属性的来源就更加明显了:在应用中的某个地方有一个被定义好的 App
对象。你只需在项目中搜索就可以找到它。
这样做的另一个好处是 App
可以在你代码的任何地方使用,不管它是否是 Vue 相关的。包括向实例选项直接附加一些值而不必进入一个函数去访问 this
上的属性来得到这些值:
new Vue({
data: {
appVersion: App.version
},
methods: {
reverseText: App.helpers.reverseText
}
当使用模块系统时
虽然毫无疑问它更啰嗦,但是这种方法确实是最可维护的,尤其是当和多人一起协作一个大型应用的时候。