Vuejs 2 impossible to interpolate attribute values

早过忘川 提交于 2019-12-14 00:13:37

问题


 <th :class="{'c-' + column, active: sortKey == column}"
      v-for="column in getColumns()" @click="sortBy(column)">
            {{ column }}
 </th>

I get invalid expression: Unexpected token + in

but the syntax is supposed to be correct.

I tried like 20 other ways and everyone fails

Even if I put only column in there i get [Object object] instead of the actual column name


so, this doesn't work at all inside es6 template syntax. It only works if I put the templates inside <script> tags in the index.html file

export default{

  template: `
    <div :class="[c-${column}]">
       ....
       <router-link :to="/list/${item.name}"> test </router-link>
       ....
    </div>
  `,

   created(){

   }

 }

I tried

${column}   - undefined variable
${$column}  - undefined variable
`${column}` - unexpected identifier
{{column}}  - invalid expression in vue

and other combinations and neither works inside the es6 template syntax.

so vuejs templates cannot be used with es6 modules and template syntax?


回答1:


For HTML class bindings there are two syntax you can use:

Object syntax

<div :class="{ selected: isSelected }"></div>

The presence of the class will be determined by the truthiness of the data property used. The class binding is expecting the following type: { [key: string]: boolean } or Record<string, boolean>.

When using a template string (backticks) as an object property name, you need to wrap it in square brackets.

ie:

<div :class="{ [`${dynamicClassName}`]: true }"></div>

Array syntax

There is also the array syntax, which allows us to bind a list of classes.

<div :class="['selected', 'some-other-class']"></div>

We can use the object syntax in the array syntax like so:

<div :class="['some-class', { selected: isSelected }]"></div>

Using template strings:

<div :class="[`${dynamicClassName}`, { [`${dynamicClassName2}`]: isSelected }]"></div>

Edit:

Try the following if you want to use a template literal:

template: `
    <div :class="'c-' + column">
       ....
       <router-link :to="'/list/' + item.name"> test </router-link>
       ....
    </div>
  `,



回答2:


When it accesses obj['c-' + column], it gets undefined - which is falsy. You want it to be truthy, so give it an object like { 'c-' + column: true, active: sortKey == column }

Leaving it falsy is just like having sortKey != column, which causes active to not appear in the classlist.




回答3:


I'm not sure exactly where the problem is because I can't see all of the code (Notably, the JS), but I'm just going to add a snippet that definitely works. The following code appears to do what you want (Or at least, what I think you want):

function getColumns() {
 return ["a", "b" ,"c"];
}

function sortBy(column) {
 console.log("Do sorting stuff with " + column);
 app.sortKey = column;
}

app = new Vue({
 el: '#app',
 data() {
  return {
   getColumns,
   sortBy,
   sortKey: "a",
  }
 },
}) 
.c-a {
  color: red;
}
.c-b {
  color: green;
}
.c-c {
  color: blue;
}
.active {
  border: 1px solid black;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
 <table>
  <tr>
   <th v-for="column in getColumns()"  :class="{['c-' + column]: true, active: sortKey == column}"
      @click="sortBy(column)">
            {{ column }}
   </th>
  </tr>
 </table>
</div>

Note that if you want Vue to be reactive with columns (I.e., sense when the columns change), then don't pass in getColumns. Just pass in the columns array itself. Then use app.columns = ["x", "y", "z"] to set a new array of columns, and Vue will sense this. That's the way it's meant to be used. You can force update if you know getColumns is going to return something new, but this isn't proper Vue usage.

Vue is a well-built framework, so don't think there's anything out there it simply can't do. As long as you update using app.something = newsomething, it'll rerender the DOM efficiently and give you that really nice syntax to do it with.

PS: You probably don't need that sortBy function (I'm assuming it just sorts the rows of the table). If your sortBy is used only for presentation logic, it's missing the point. All of the presentation logic can be entirely within the Vue. You can see this in action using computed and methods:

function getColumns() {
 return ["First", "Middle" ,"Last"];
}

data = [
 {
  "First": "Bernhard",
  "Middle": "G.F.",
  "Last": "Riemann",
 },
 {
  "First": "Leonhard",
  "Middle": "",
  "Last": "Euler",
 }, 
 {
  "First": "Karl",
  "Middle": "F.",
  "Last": "Gauss",
 },
];

app = new Vue({
 el: '#app',
 methods: {
  headerClass(column) {
    return {
      ['c-' + column.toLowerCase()]: true,
      active: this.sortKey == column
    };
   }
 },
 computed: {
  sortedData() {
   sortingBy = (x, y) => x[this.sortKey] > y[this.sortKey];
   return data.sort(sortingBy);
  },
 },
 data: {
  columns: getColumns(),
  sortKey: "First",
  data,
 },
})
.c-first {
  color: red;
}
.c-middle {
  color: green;
}
.c-last {
  color: blue;
}
.active {
  border: 1px solid black;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
 <table>
  <tr>
   <th v-for="column in columns" :class="headerClass(column)"
      @click="sortKey = column">
            {{ column }}
   </th>
  </tr>
  <tr v-for="row in sortedData">
   <td v-for="column in columns">
    {{ row[column] }}
   </td>
  </tr>
 </table>
</div>

Then, you can have all of the controller logic completely separated from presentation things like sorting the table. And, you don't have pollute any namespaces with sortBy (Using sortBy in the HTML means it has to be in the global namespace, which isn't going to work for a big project). I hope the above code shows how you can use VueJS to get full MVC separation.

As an added benefit, you don't have to presort the array using the default sortKey. As you've may have noticed, in my original code there is no initial "Do sorting stuff with a". The computed version handled the initial case automatically. Of course, this can just be done by calling sortBy("a") and probably pulling "a" into a defaultKey variable. The second option is still nicer.


This answer feels a lot more advertizy than I'd like, but "is vuejs just a waste of time?" is false in my opinion, and I thought it would be useful to explain why. That doesn't mean another frameworks like React isn't better, but VueJS is definitely a valid choice for presentation logic.




回答4:


Please use the template string in created method as shown below. It worked. I used some dummy values for demo.

export default {
  name: 'HelloWorld',
  data() {
    return {
      template: ``,
      column: "hare",
      item: {name: "krishna"},
      msg: 'Welcome to Your Vue.js App'
    }
  },
  created() {
    this.template = `
      <div :class="[c-${this.column}]">
        ....
        <router-link :to="/list/${this.item.name}"> test </router-link>
        ....
      </div>
    `;
  }
}



来源:https://stackoverflow.com/questions/52707851/vuejs-2-impossible-to-interpolate-attribute-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!