Использование this в шаблоне Vue внутри блока v-for для динамического извлечения данных на основе переменной цикла

Я пытаюсь использовать VueJS 2 для визуализации простого v-for, где я хотел бы, чтобы переменная цикла представляла свойство, к которому я хотел бы получить доступ. Это минимальный пример, показывающий, чего я хотел бы достичь:

var app = new Vue({
  el: '#app',
  data() {
    return {
      properties: ["a", "b", "c"],
      a: "Value Of A",
      b: "Value Of B",
      c: "Value Of C"
    };
  }
})
 
 <div id = "app">
    <div> this renders fine: a = {{ this['a'] }} </div>
    <div> 
      but this doesn't:
      <div v-for = "name in properties" :key = "name"> {{name}} = {{ this[name] }}</div>
    </div>
  </div>

<script src = "https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

По сути, я хотел бы отображать поля данных выборочно и в определенном порядке, определяемом полем свойств. Но пример ничего не может отобразить для {{ this[name] }}. На самом деле он даже не отображается, если я изменил его на {{ this['a'] }} для быстрого тестирования. {{ this['a'] }} если поместить за пределы блока v-for, он будет отображаться нормально.

В чем может быть проблема с блоком v-for?

jsfiddle.net/zg9fxap4
Mohsen 24.12.2020 12:13

да, вы можете обернуть a, b, c в другой объект, чтобы избежать использования «этого», но я не всегда контролирую модель. Было бы хорошо, если бы я мог назначить это переменной внутри моего шаблона.

Xinchao 24.12.2020 12:28

{{ $data[name] }} вместо {{ this[name] }}

Mohsen 24.12.2020 12:33

круто, а как насчет свойств и вычисляемых свойств?

Xinchao 24.12.2020 12:36

На самом деле вам не нужно будет вызывать this в скобках, {{ a }} выведет свойство a, либо вычисленные свойства

Mohsen 24.12.2020 12:41

правильно, но как насчет цикла v-for?

Xinchao 24.12.2020 12:47

На самом деле я не могу найти, почему this не будет работать в v-for, поэтому просто могу предложить вызвать метод и вернуть желаемый результат в этом случае.

Mohsen 24.12.2020 12:59

Я предполагаю, что более важный вопрос заключается в том, следует ли мне использовать «это» в шаблоне? Пробовал Vue3, и «это» отлично работает в цикле for.

Xinchao 24.12.2020 13:39

Для меня я использовал this в v-on, когда ключ объекта был динамической переменной в корне свойства данных компонента, однако вы можете предотвратить это, используя вычисляемое свойство или метод

Mohsen 24.12.2020 18:27

@Mohsen Мохсен, ты не против добавить свое решение $data в ответ?

Xinchao 25.12.2020 05:31
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
10
549
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

По соглашению все в шаблоне vue this автоматически. Фактически, вы не можете получить доступ ни к чему, кроме свойств, данных, методов, вычислений, фильтров и т. д., за пределами экземпляра компонента this в шаблоне.

Итак, this недоступен, потому что все, что вы заявляете в шаблоне, подразумевает его.

Насколько я понимаю, вы не можете заставить this исчезнуть в функции javascript, это только вопрос того, к чему он относится. Я знаю, что могу напрямую обращаться к полям this в шаблоне без явного указания this. Но мне нужно будет знать имя поля статически. Здесь я просто хочу использовать скобки.

Xinchao 26.12.2020 07:44

this подразумевается в шаблоне как экземпляр компонента. и все остальное, на что вы хотите сослаться, просто добавьте к данным или вычислите.

Steven Spungin 27.12.2020 07:01

для вашего примера создайте метод get(prop) и просто верните его, используя this в методе

Steven Spungin 27.12.2020 07:03
Ответ принят как подходящий

Покопавшись в скомпилированном шаблоне (через Vue Template Explorer), я понял, что этот (упрощенный, чтобы просто содержать проблемный v-for) шаблон:

<div id = "app">
  <div v-for = "name in properties" :key = "name"> {{name}} = {{ this[name] }}</div>
</div>

компилируется в:

function render() {
  with(this) {
    return _c('div', {
      attrs: {
        "id": "app"
      }
    }, _l((properties), function (name) {
      return _c('div', {
        key: name
      }, [_v(" " + _s(name) + " = " + _s(this[name]))])
    }), 0)
  }
}

где _c — это сокращение от createElement, _l — это сокращение от renderList, а _v — это сокращение от createTextVNode.

Теперь ясно, что причина, по которой я могу писать {{ a }}, не упоминая, где разрешать a, связана с выражением with(this), где this является прокси-объектом.

Однако проблема с v-for заключается в том, что фактический рендерер элемента передается как функция обратного вызова в _l:

function (name) {
  return _c('div', 
            {key: name}, 
            [_v(" " + _s(name) + " = " + _s(this[name]))])
}

Способ вызова обратного вызова, применяется правило привязки по умолчанию, а this привязан к глобальному объекту окна.

С VueJS 3 (обозреватель шаблонов) тот же шаблон компилируется немного по-другому:

import { renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock, toDisplayString as _toDisplayString, createVNode as _createVNode } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", { id: "app" }, [
    (_openBlock(true), _createBlock(_Fragment, null, _renderList(_ctx.properties, (name) => {
      return (_openBlock(), _createBlock("div", { key: name }, _toDisplayString(name) + " = " + _toDisplayString(this[name]), 1 /* TEXT */))
    }), 128 /* KEYED_FRAGMENT */))
  ]))
}

Обратите внимание, что функция рендеринга списка теперь определена как лямбда-выражение, поэтому this захвачено лексически.

Итак, чтобы заставить все это работать, я остановился на методе, предложенном другими в комментариях:

let app = new Vue({
  el: '#app',
  data() {
    return {
      properties: ["a", "b", "c", "d"],

      a: "Value Of A",
      b: "Value Of B",
      c: "Value Of C"

    };
  },
  
  computed: {
    d() {
     return "Value of D";
    }
  },
    
  methods: {
    get(prop) {
        return this[prop];
    }
  },
})
<script src = "https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id = "app">
   <div>
     from $data:
     <div v-for = "name in properties" :key = "name"> {{name}} = {{ $data[name] }}</div>
   </div>
   <div>
     from get:
     <div v-for = "name in properties" :key = "name"> {{name}} = {{ get(name) }}</div>
   </div>
 </div>

Другие вопросы по теме