如何为v-for循环语句渲染内部进行动态切换渲染模板?

列车
  • 36

我想为v-for内的代码动态切换,由请求后端得到响应的传输v-for内部的代码,以下是我为此编写的代码,

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
  <ol>
      <template v-for="site in sites">
        <div v-html="message">
            
        </div>
      </template>
  </ol>
</div>

<script>
new Vue({
  el: '#app',
  data: {
      message:"<font color="red"><h1>{{ site.name }}</h2></font>",
    sites: [
      { name: 'Runoob' },
      { name: 'Google' },
      { name: 'Taobao' }
    ]
  },
    created(){
        
    }
    
})
</script>
</body>
</html>

message是我想用v-html指定的切换的渲染模板,message的内容假定是通过请求后端得到的。

运行后message的内容被渲染成html但,其中的{{site.name}}没有被渲染。以下为渲染效果图:

这个怎么解决么?

如果vue自己做不到的话,那只能用后端的模板引擎来搞定了。

回复
阅读 286
4 个回答

v-html是将message内容以html显示,并不能解析{{}}

如果想根据数据定义不同的模板,其实多写几个if else 完全是能满足要求的。

已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。
  • 可以绑定一个函数来实现
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>v-html</title>
</head>
<body>
  <div id="app">
    <div
      v-for="(item, index) of sites"
      :key="index"
    >
      <p v-html="handleMessage(item)"></p>
    </div>
  </div>
  <script src="https://unpkg.com/vue"></script>
  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        message: "<font color='red'><h1>{{ site.name }}</h2></font>",
        sites: [
          { name: 'Runoob' },
          { name: 'Google' },
          { name: 'Taobao' }
        ]
      },
      methods: {
        handleMessage (item) {
          const reg = /\{\{.+\}\}/g;
          return this.message.replace(reg, item.name);
        }
      }
    })
  </script>
</body>
</html>

示例的正则依据楼主的代码只作为参考,具体格式可以约定为更方便处理的格式

如果单纯的只是你问题描述中的那样,可以不用 v-html 来输出,直接在页面中和平时一样处理就好了。

<template>
  <div id="app">
    <ol>
        <template v-for="site in sites">
          <div>
            <font color="red"><h1>{{ site.name }}</h2></font>
          </div>
        </template>
    </ol>
  </div>
</template>
<script>
export default {
  data() {
    return {
      sites: [
        { name: 'Runoob' },
        { name: 'Google' },
        { name: 'Taobao' }
      ]
    };
  }
};
</script>

如果是你想定义多个不同的样式模板,建议你还是单独抽离成组件,然后引入使用,这样方便你编辑模板,业务组件也不会有很多模板代码,影响你阅读。

<!-- templateA.vue -->
<template>
  <li><font color="red"><h1>{{ data.name }}</h2></font></li>
</template>
<script>
export default {
  name:"templateA",
  props:{
    data:{
      type:Object,
      required:true
    }
  }
}
<!-- templateB.vue -->
<template>
  <li><font color="green"><h2>{{ data.name }}</h2></font></li>
</template>
<script>
export default {
  name:"templateB",
  props:{
    data:{
      type:Object,
      required:true
    }
  }
}
<template>
  <div id="app">
    <ol>
        <template v-for="site in sitesList">
          <component :is="item.component" :data="item" />
        </template>
    </ol>
  </div>
</template>
<script>
import { templateA } from './templateA.vue'
import { templateB} from './templateB.vue'
const siteTemplate = {
  A: templateA,
  B: templateB
}
export default {
  data() {
    return {
      sites: [
        { name: 'Runoob', type:"A" },
        { name: 'Google', type:"B" },
        { name: 'Taobao', type:"A" }
      ]
    };
  },
  computed:{
     sitesList(){
        return this.sites.map(item => Object.assign({}, item,{component: siteTemplate[item.type]})
     }
  }
};
</script>

已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。
你知道吗?

宣传栏