【问题标题】:vue.js DOM Template Parsing Caveatsvue.js DOM 模板解析注意事项
【发布时间】:2018-12-27 01:19:09
【问题描述】:

Vue 文档DOM Template Parsing Caveats 说:

应该注意,如果您使用来自以下来源之一的字符串模板,此限制适用:

  • 字符串模板(例如template: '...'

v-for with a Component

注意is="todo-item" 属性。这在 DOM 模板中是必需的 […]

但这不是“字符串模板”吗?

Vue.component('todo-item', {
  template: '\
    <li>\
      {{ title }}\
      <button v-on:click="$emit(\'remove\')">Remove</button>\
    </li>\
  ',
  props: ['title']
})

【问题讨论】:

    标签: html vue.js


    【解决方案1】:

    您可能会对字符串模板的“范围”感到困惑,因为它可以让您摆脱上述限制。

    如果限制子元素类型的 HTML 父元素(在本例中为 &lt;ul&gt;)位于字符串模板中,那么您就可以了。

    但如果它在真实的 DOM 中,那么浏览器将开始检查限制并取出它不期望的子元素。

    Vue 文档中的确切示例可能不再非常相关,因为浏览器现在似乎接受自定义元素作为 &lt;ul&gt; 的子元素(至少在 Chrome 和 Firefox 中):

    Vue.component('todo-item', {
      template: '\
        <li>\
          {{ title }}\
          <button v-on:click="$emit(\'remove\')">Remove</button>\
        </li>\
      ',
      props: ['title']
    })
    
    new Vue({
      el: '#todo-list-example',
      data: {
        newTodoText: '',
        todos: [{
            id: 1,
            title: 'Do the dishes',
          },
          {
            id: 2,
            title: 'Take out the trash',
          },
          {
            id: 3,
            title: 'Mow the lawn'
          }
        ],
        nextTodoId: 4
      },
      methods: {
        addNewTodo: function() {
          this.todos.push({
            id: this.nextTodoId++,
            title: this.newTodoText
          })
          this.newTodoText = ''
        }
      }
    })
    li {
      /* Items will be RED if hoisted out of the UL */
      background-color: red;
    }
    
    ul li {
      /* Items will be GREEN if kept inside the UL */
      background-color: green;
    }
    <script src="https://unpkg.com/vue@2"></script>
    
    <div id="todo-list-example">
      <form v-on:submit.prevent="addNewTodo">
        <label for="new-todo">Add a todo</label>
        <input v-model="newTodoText" id="new-todo" placeholder="E.g. Feed the cat">
        <button>Add</button>
      </form>
      <ul>
        <!-- Using directly the Component in DOM -->
        <todo-item
          v-for="(todo, index) in todos"
          v-bind:key="todo.id"
          v-bind:title="todo.title"
          v-on:remove="todos.splice(index, 1)"
        ></todo-item>
      </ul>
    </div>

    但是考虑一下我们将&lt;ul&gt; 替换为&lt;table&gt;&lt;li&gt; 由表行&lt;tr&gt;&lt;td&gt; 替换的情况:

    Vue.component('todo-item', {
      template: '\
        <tr><td>\
          {{ title }}\
          <button v-on:click="$emit(\'remove\')">Remove</button>\
        </td></tr>\
      ',
      props: ['title']
    })
    
    new Vue({
      el: '#todo-list-example',
      data: {
        newTodoText: '',
        todos: [{
            id: 1,
            title: 'Do the dishes',
          },
          {
            id: 2,
            title: 'Take out the trash',
          },
          {
            id: 3,
            title: 'Mow the lawn'
          }
        ],
        nextTodoId: 4
      },
      methods: {
        addNewTodo: function() {
          this.todos.push({
            id: this.nextTodoId++,
            title: this.newTodoText
          })
          this.newTodoText = ''
        }
      }
    })
    tr,
    td {
      /* Cells will be RED if hoisted out of the table */
      background-color: red;
    }
    
    table tr,
    table td {
      /* Cells will be GREEN if kept inside the table */
      background-color: green;
    }
    <script src="https://unpkg.com/vue@2"></script>
    
    <div id="todo-list-example">
      <form v-on:submit.prevent="addNewTodo">
        <label for="new-todo">Add a todo</label>
        <input v-model="newTodoText" id="new-todo" placeholder="E.g. Feed the cat">
        <button>Add</button>
      </form>
      <table>
        <!-- Using directly the Component in real DOM -->
        <todo-item
          v-for="(todo, index) in todos"
          v-bind:key="todo.id"
          v-bind:title="todo.title"
          v-on:remove="todos.splice(index, 1)"
        ></todo-item>
      </table>
    </div>

    现在,如果应用模板不再留在真实的 DOM 中,而是指定为模板字符串:

    Vue.component('todo-item', {
      template: '\
        <tr><td>\
          {{ title }}\
          <button v-on:click="$emit(\'remove\')">Remove</button>\
        </td></tr>\
      ',
      props: ['title']
    })
    
    new Vue({
      el: '#todo-list-example',
      template: `
      <div>
        <form v-on:submit.prevent="addNewTodo">
          <label for="new-todo">Add a todo</label>
          <input v-model="newTodoText" id="new-todo" placeholder="E.g. Feed the cat">
          <button>Add</button>
        </form>
        <table>
          <!-- Using directly the Component in template string -->
          <todo-item
            v-for="(todo, index) in todos"
            v-bind:key="todo.id"
            v-bind:title="todo.title"
            v-on:remove="todos.splice(index, 1)"
          ></todo-item>
        </table>
      </div>
      `,
      data: {
        newTodoText: '',
        todos: [{
            id: 1,
            title: 'Do the dishes',
          },
          {
            id: 2,
            title: 'Take out the trash',
          },
          {
            id: 3,
            title: 'Mow the lawn'
          }
        ],
        nextTodoId: 4
      },
      methods: {
        addNewTodo: function() {
          this.todos.push({
            id: this.nextTodoId++,
            title: this.newTodoText
          })
          this.newTodoText = ''
        }
      }
    })
    tr,
    td {
      /* Cells will be RED if hoisted out of the table */
      background-color: red;
    }
    
    table tr,
    table td {
      /* Cells will be GREEN if kept inside the table */
      background-color: green;
    }
    <script src="https://unpkg.com/vue@2"></script>
    
    <div id="todo-list-example">
    </div>

    为了完整起见,如果我们将应用模板保留在真实 DOM 中,但正确使用 is 特殊属性来引用我们的组件,如 Vue 文档示例中所做的那样:

    Vue.component('todo-item', {
      template: '\
        <tr><td>\
          {{ title }}\
          <button v-on:click="$emit(\'remove\')">Remove</button>\
        </td></tr>\
      ',
      props: ['title']
    })
    
    new Vue({
      el: '#todo-list-example',
      data: {
        newTodoText: '',
        todos: [{
            id: 1,
            title: 'Do the dishes',
          },
          {
            id: 2,
            title: 'Take out the trash',
          },
          {
            id: 3,
            title: 'Mow the lawn'
          }
        ],
        nextTodoId: 4
      },
      methods: {
        addNewTodo: function() {
          this.todos.push({
            id: this.nextTodoId++,
            title: this.newTodoText
          })
          this.newTodoText = ''
        }
      }
    })
    tr,
    td {
      /* Cells will be RED if hoisted out of the table */
      background-color: red;
    }
    
    table tr,
    table td {
      /* Cells will be GREEN if kept inside the table */
      background-color: green;
    }
    <script src="https://unpkg.com/vue@2"></script>
    
    <div id="todo-list-example">
      <form v-on:submit.prevent="addNewTodo">
        <label for="new-todo">Add a todo</label>
        <input v-model="newTodoText" id="new-todo" placeholder="E.g. Feed the cat">
        <button>Add</button>
      </form>
      <table>
        <!-- Using a TR with "is" in real DOM -->
        <tr
          is="todo-item"
          v-for="(todo, index) in todos"
          v-bind:key="todo.id"
          v-bind:title="todo.title"
          v-on:remove="todos.splice(index, 1)"
        ></tr>
      </table>
    </div>

    【讨论】:

    【解决方案2】:

    否!警告适用于浏览器加载的模板它们被 Vue 处理之前。如果您执行类似...

    vm = new Vue({el : '#vueRoot'})
    // the template under vueRoot is in a real .html page and must be processed by Vue after loading by the browser.
    

    如果您使用&lt;template&gt; 元素,则同样适用。浏览器正在将它认为是 HTML 的内容加载到 DOM 中,但实际上是一个原始的 Vue 模板。

    在您的示例 todo-item 中,重要的不是您包含的组件模板代码,而是调用它的地方。您可以在 javascript 中使用 &lt;todo-item&gt;,但在上述情况下您必须(或应该)使用 &lt;li is="todo-item"&gt;,在这种情况下,此自定义元素将在 Vue 再次取出之前加载到 DOM 中。

    【讨论】:

      猜你喜欢
      • 2016-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 2011-06-06
      相关资源
      最近更新 更多