Looping a block of code in IE 11

2019-02-25 09:09发布

For a project, I need to loop through a list of objects given in javascript, and display them horizontally in a html table. Example here: https://jsfiddle.net/50wL7mdz/83227/

html:

<div id="app">
  <table>
  <thead><tr><td colspan='5'>{{body.title}}</td></tr></thead>
  <tbody>
    <tr>
      <template v-for='car in body.cars'>
        <td>{{car.make}}</td>
        <td>{{car.model}}</td>
        <td>{{car.year}}</td>
      </template>
    </tr>
  </tbody>
  </table>
</div>

javascript:

 new Vue({
  el: '#app',
  data: {
    body: {title : 'test title',
    cars: [{make: 'Honda', model: 'Civic', year: 2010},
    {make: 'Toyota', model: 'Camry', year: 2012},
    {make: 'Nissan', model: 'Versa', year: 2014}]}
  }
})

In the actual project, the length of "cars" in unknown so looping is unavoidable. You can see the example works fine in Chrome and Firefox, but not working in IE.

After contacting Vue dev team, they informed me that template tag simply isn't accepted in "tr" of IE, and I need to use string based templates instead. However after experimenting with Vue components, turns out Vue also doesn't allow multiple root elements in a template. Link to Vue ticket here (closed): https://github.com/vuejs/vue/issues/7243

What would be a good way to do this and make it work on IE as well?

3条回答
你好瞎i
2楼-- · 2019-02-25 09:49

Evan gives the answer in the issue. Use a string template.

new Vue({
  el: '#app',
  template: "\
  <table>\
  <thead><tr><td colspan='5'>{{body.title}}</td></tr></thead>\
  <tbody>\
    <tr>\
      <template v-for='car in body.cars'>\
        <td>{{car.make}}</td>\
        <td>{{car.model}}</td>\
        <td>{{car.year}}</td>\
      </template>\
    </tr>\
  </tbody>\
  </table>",
  data: {
    body: {title : 'test title',
    cars: [{make: 'Honda', model: 'Civic', year: 2010},
    {make: 'Toyota', model: 'Camry', year: 2012},
    {make: 'Nissan', model: 'Versa', year: 2014}]}
  }
})

Ugly as that looks it does work in IE. You could also write a render function.

render: function(h){
  let cells = []
  for (var i=0; i < this.body.cars.length; i++){
    cells.push(h("td", this.body.cars[i].make))
    cells.push(h("td", this.body.cars[i].model))
    cells.push(h("td", this.body.cars[i].year)) 
  }

  let header = h("thead", [h("tr", [h("td", {attrs: {colspan: 5}}, [this.body.title])])])
  let body = h("tbody", [h("tr", cells)])

  return h("table", [header, body])
}
查看更多
ゆ 、 Hurt°
3楼-- · 2019-02-25 09:54

Evan picked up that you were declaring the component as html and then mounting Vue to it. That is the problem with IE11: the browser first processes the html before knowing anything about Vue and reaches a critical error when it reaches the template tag, before going on to process the js. In order to make IE process the template tag you have to give it to the browser from Vue, so Vue can do the interpreting. This is why a string-based template is recommended: Vue takes the template as a string and then gives the browser HTML to display.

Then as you've picked up, Vue can only have one root element for a template. The solution is to keep backing out of the DOM tree until you have one root element. In this case I propose just making the entire table the template. Then you would have:

javascript:

Vue.component('car-table', {
  data: function () {
      return {
        title: 'test title',
        cars: [{
          make: 'Honda',
          model: 'Civic',
          year: 2010
        }, {
          make: 'Toyota',
          model: 'Camry',
          year: 2012
        }, {
          make: 'Nissan',
          model: 'Versa',
          year: 2014
        }]
      };
    },
    template: '\
    <table>\
        <thead>\
        <tr>\
            <td colspan="5">{{title}}</td>\
        </tr>\
      </thead>\
      <tbody>\
        <tr>\
          <template v-for="car in cars">\
          <td>{{car.make}}</td><td>{{car.model}}</td><td>{{car.year}}</td>\
          </template>\
        </tr>\
      </tbody>\
    </table>',
});

new Vue({
  el: '#app',
});

and html:

<div id="app">
  <car-table></car-table>
</div>

I've updated the jsfiddle to reflect this.

查看更多
神经病院院长
4楼-- · 2019-02-25 10:02

EDIT: don't read this one, it is only accurate for Vue 1!

I don't think you're going to be able to do this currently. IE simply does not allow template tags, so the only way to do this is using <tr is="component-name"> and have a separate component (with a single root element) which can be applied to the tr or td. Looping through each element and adding 3 tds per cannot be done.

Again, using the is attribute on a tr or td is the current solution, but that does not allow for multi-root components as you have requested. Perhaps you can create a component for each car and do <td is="car-component"> and then style the TD to look like 3 columns.

查看更多
登录 后发表回答