Просмотр исходного кода

polish: warn when an existing property starting with $ is not pro… (#8214)

Eduardo San Martin Morote 7 лет назад
Родитель
Сommit
952ae33290
2 измененных файлов с 60 добавлено и 3 удалено
  1. 16 3
      src/core/instance/proxy.js
  2. 44 0
      test/unit/features/instance/render-proxy.spec.js

+ 16 - 3
src/core/instance/proxy.js

@@ -24,6 +24,16 @@ if (process.env.NODE_ENV !== 'production') {
     )
   }
 
+  const warnReservedPrefix = (target, key) => {
+    warn(
+      `Property "${key}" must be accessed with "$data.${key}" because ` +
+      'properties starting with "$" or "_" are not proxied in the Vue instance to ' +
+      'prevent conflicts with Vue internals' +
+      'See: https://vuejs.org/v2/api/#data',
+      target
+    )
+  }
+
   const hasProxy =
     typeof Proxy !== 'undefined' && isNative(Proxy)
 
@@ -45,9 +55,11 @@ if (process.env.NODE_ENV !== 'production') {
   const hasHandler = {
     has (target, key) {
       const has = key in target
-      const isAllowed = allowedGlobals(key) || (typeof key === 'string' && key.charAt(0) === '_')
+      const isAllowed = allowedGlobals(key) ||
+        (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data))
       if (!has && !isAllowed) {
-        warnNonPresent(target, key)
+        if (key in target.$data) warnReservedPrefix(target, key)
+        else warnNonPresent(target, key)
       }
       return has || !isAllowed
     }
@@ -56,7 +68,8 @@ if (process.env.NODE_ENV !== 'production') {
   const getHandler = {
     get (target, key) {
       if (typeof key === 'string' && !(key in target)) {
-        warnNonPresent(target, key)
+        if (key in target.$data) warnReservedPrefix(target, key)
+        else warnNonPresent(target, key)
       }
       return target[key]
     }

+ 44 - 0
test/unit/features/instance/render-proxy.spec.js

@@ -45,5 +45,49 @@ if (typeof Proxy !== 'undefined') {
 
       expect(vm.$el.textContent).toBe('foo')
     })
+
+    it('should warn properties starting with $ when found', () => {
+      new Vue({
+        data: { $a: 'foo' },
+        template: `<div>{{ $a }}</div>`
+      }).$mount()
+      expect(`Property "$a" must be accessed with "$data.$a"`).toHaveBeenWarned()
+    })
+
+    it('should warn properties starting with _ when found', () => {
+      new Vue({
+        data: { _foo: 'foo' },
+        template: `<div>{{ _foo }}</div>`
+      }).$mount()
+      expect(`Property "_foo" must be accessed with "$data._foo"`).toHaveBeenWarned()
+    })
+
+    it('should warn properties starting with $ when not found', () => {
+      new Vue({
+        template: `<div>{{ $a }}</div>`
+      }).$mount()
+      expect(`Property or method "$a" is not defined`).toHaveBeenWarned()
+      expect(`Property "$a" must be accessed with "$data.$a"`).not.toHaveBeenWarned()
+    })
+
+    it('should warn properties starting with $ when not found (with stripped)', () => {
+      const render = function (h) {
+        return h('p', this.$a)
+      }
+      render._withStripped = true
+      new Vue({
+        data: { $a: 'foo' },
+        render
+      }).$mount()
+      expect(`Property "$a" must be accessed with "$data.$a"`).toHaveBeenWarned()
+    })
+
+    it('should not warn properties starting with $ when using $data to access', () => {
+      new Vue({
+        data: { $a: 'foo' },
+        template: `<div>{{ $data.$a }}</div>`
+      }).$mount()
+      expect(`Property or method "$a" is not defined`).not.toHaveBeenWarned()
+    })
   })
 }