一、django模板变量和vue冲突解决 {{ }}

如果不可避免的在同一个页面里既有 django 渲染又有 vue 渲染的部分,可有 2 种方式解决

方法一:采用 vue 的 delimiters 分隔符。

new Vue({
  delimiters: ["{[", "]}"] // 可自定义符号
})

方法二:建议把 vue 的部分用 {% verbatim %} 包起来。我这里使用这种方法

见文档:https://docs.djangoproject.com/en/2.2/ref/templates/builtins/#verbatim

{% verbatim %}
        <div>{{ text }}</div>
{% endverbatim %}

二、示例

1、最简单的例子

一个 Vue 应用会将其挂载到一个 DOM 元素上 (对于这个例子是 #app) 然后对其进行完全控制。那个 HTML 是我们的入口,但其余都会发生在新创建的 Vue 实例内部。django部分不多描述了

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>
</head>


<body>

{% verbatim %}

<div id="app">
  {{ message }}
</div>

{% endverbatim %}

<script>

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})

</script>

</body>
</html>

访问页面
在这里插入图片描述
打开你的浏览器的 JavaScript 控制台 (就在这个页面打开),并修改 app.message 的值,你将看到上例相应地更新。

app.message="hello wangxiaoyu"

在这里插入图片描述
在这里插入图片描述

2、v-text 指令

用于渲染普通文本,无论何时,绑定的数据对象上 msg属性发生了改变,插值处的内容都会更新。v-text和{{}}表达式渲染数据,不解析标签。

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>
</head>
{% verbatim %}
<body>

<div id="app" v-text="message"></div>

<script>
    // 数据模板引擎
    // v-开头的指令是帮助我们渲染数据用的
    new Vue({
        el: "#app",
        data: {
            message: "Hello Vue Text",
        }
    })
</script>

</body>
{% endverbatim %}

</html>

访问页面
在这里插入图片描述

3、v-html 指令

如果你想输出真正的 HTML,你需要使用 v-html指令,v-text仅渲染标签,不能解析 HTML 代码。

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>
</head>
{% verbatim %}
<body>

<div id="app" v-html="message"></div>

<script>
    // 数据模板引擎
    // v-开头的指令是帮助我们渲染数据用的
    new Vue({
        el: "#app",
        data: {
            message: "<h1>Hello Vue</h1>",
        }
    })
</script>

</body>

{% endverbatim %}

</html>

访问页面
在这里插入图片描述

4、v-for 指令

可以绑定数组的数据来渲染一个项目列表

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>
</head>
{% verbatim %}
<body>

<div id="app">
  <ol>
    <li v-for="todo in todos">
      {{ todo.text }}
    </li>
  </ol>
</div>

<script>
var app = new Vue({
  el: '#app',
  data: {
    todos: [
      { text: '学习 JavaScript' },
      { text: '学习 Vue' },
      { text: '整个牛项目' }
    ]
  }
})
</script>

</body>

{% endverbatim %}

</html>

访问页面

在这里插入图片描述

在控制台里,输入 app.todos.push({ text: ‘新项目’ }),你会发现列表最后添加了一个新项目。
在这里插入图片描述
在这里插入图片描述

绑定字典,并且获取value、key和index值
在这里插入图片描述

5、v-if、v-else-if、v-else 条件判断
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>
</head>
{% verbatim %}
<body>


<div id="app">
    <div v-if="role == 'wangxiaoyu'">
        <h1>欢迎王小雨</h1>
    </div>
    <div v-else-if="role == 'wangdayu'">
        <h1>欢迎王大雨</h1>
    </div>
    <div v-else>
        <h1>欢迎 {{ role }}</h1>
    </div>
</div>

<script>
    // 数据模板引擎
    // v-开头的指令是帮助我们渲染数据用的
    var app = new Vue({
        el: "#app",
        data: {
            role: "wangxiaoyu"
        }
    })
</script>


</body>

{% endverbatim %}


</html>

访问页面
在这里插入图片描述

在控制台输入app.role=“wangdayu” 修改数据
在这里插入图片描述
匹配到v-else-if="role == 'wangdayu',页面也跟着修改了
在这里插入图片描述

在控制台输入app.role=“elsetest” 修改数据,此时前面两个都没匹配到,则使用v-else的流程
在这里插入图片描述

6、v-show指令控制显示或隐藏
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>
</head>
{% verbatim %}
<body>

<div id="app">
    <div v-show="isShow">Hello Vue</div>
</div>

<script>
    let app = new Vue({
        el: "#app",
        data: {
            isShow: false,
        }
    })
</script>


</body>

{% endverbatim %}


</html>

上面设置默认不显示,在控制台输入app.isShow=true,然后可以看到有显示
在这里插入图片描述
在这里插入图片描述

7、v-bind

v-bind用于绑定数据和元素属性,比方你的class属性,style属性,value属性,href属性等等,只要是属性,就可以用v-bind指令进行绑定。
参考 https://www.cnblogs.com/liuchuanfeng/p/6742631.html

(1)、绑定绑定a标签的href属性

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>
</head>
{% verbatim %}
<body>

<div id="app">
    <a v-bind:href="jingdong">去京东</a>
</div>

<script>
    // 数据模板引擎
    // v-开头的指令是帮助我们渲染数据用的
    var app = new Vue({
        el: "#app",
        data: {
            jingdong: "https://www.jd.com",
        }
    })
</script>


</body>
{% endverbatim %}
</html>

访问页面

在这里插入图片描述

(2)使用v-bind:class="{ }绑定class属性,例如 v-bind:class="{ blockclass: isBlockclass,center: isCenter }",可以在对象中传多个属性,动态绑定多个class

v-bind:class指令可以与普通的class特性共存,由于使用频繁,通常将v-bind:属性名=" “的格式简写成:属性名=” "

先设置一个名称为blockclass的class样式,在div中使用v-bind:class="{ blockclass: isBlockclass }",里面的blockclass就是要绑定的class,isBlockclass的值决定了是否要绑定class,并且v-bind绑定的class也不会覆盖元素上已经存在的test类。

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>
        <style>
        .blockclass {
            width: 500px;
            height: 500px;
            background-color: lawngreen;
        }
    </style>

</head>
{% verbatim %}
<body>

<div id="app">
    <a v-bind:href="jingdong">去京东</a>
    <div class="test" v-bind:class="{ blockclass: isBlockclass,center:isCenter }"></div>

</div>

<script>

    var app = new Vue({
        el: "#app",
        data: {
            jingdong: "https://www.jd.com",
            isBlockclass:true,
            isCenter:true,
        }
    })
</script>


</body>

{% endverbatim %}


</html>

我们可以看到data里面的isActive设成了true,所以最后渲染出来会是这样:
在这里插入图片描述
在这里插入图片描述
(3)v-bind:class 直接绑定数据里的一个对象

因为v-bind指令的初衷就是为了动态的切换class,如果绑定的对象属性太多的话,就会影响代码的可阅读性了,因此我们很多时候会绑定一个定义在data上的对象,或者绑定一个返回对象的计算属性,可以通过对这个对象的修改来修改class。

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>
        <style>
        .blockclass {
            width: 500px;
            height: 500px;
            background-color: lawngreen;
        }
    </style>

</head>
{% verbatim %}
<body>

<div id="app">
    <a v-bind:href="jingdong">去京东</a>
    <div class="test" v-bind:class="classObject"></div>

</div>

<script>

    var app = new Vue({
        el: "#app",
        data: {
            jingdong: "https://www.jd.com",
            classObject:{ blockclass:true, center:true,}

        }
    })
</script>


</body>

{% endverbatim %}


</html>

(4)v-bind:class 数组语法、我们可以把一个数组传给v-bind:class,以应用一个class列表,数组里面的变量名表示类名,在vue对象中设置。

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>
        <style>
        .blockclass {
            width: 500px;
            height: 500px;
            background-color: lawngreen;
        }
    </style>

</head>
{% verbatim %}
<body>

<div id="app">
    <a v-bind:href="jingdong">去京东</a>

     <div class="test" v-bind:class="[classA,classB]"></div>

</div>

<script>

    var app = new Vue({
        el: "#app",
        data: {
            jingdong: "https://www.jd.com",
            classA:"blockclass",
            classB:"center",

        }
    })
</script>


</body>

{% endverbatim %}


</html>
8、v-on 用于绑定事件

作用:绑定事件监听器
缩写:@ v-on:click可以缩写为@cli

  • List item

ck
预期:Function | Inline Statement | Object
参数:event

如下使用v-on:click="reverseMessage"绑定click事件执行reverseMessage()这个方法,在vue对象中的methods:{}字段中新建方法

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>

</head>
{% verbatim %}
<body>

<div id="app">

    <p>{{ message }}</p>
    <button v-on:click="reverseMessage">反转消息</button>

</div>

<script>

    var app = new Vue({
        el: "#app",
        data: {
            message: 'Hello Vue!'
        },
        methods: {
            reverseMessage: function () {
            this.message = this.message.split('').reverse().join('')
            }
        }
    })
</script>


</body>

{% endverbatim %}


</html>

访问页面
在这里插入图片描述

如果方法不需要额外参数,那么方法后的()可以不添加。
如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去
如果需要同时传入某个参数,同时需要event时,可以通过$event传入事件。下面方法中使用es6的写法省略了function
在这里插入图片描述
在这里插入图片描述

v-on修饰符
Vue提供了修饰符来帮助我们方便的处理一些事件:
.stop - 调用 event.stopPropagation()。
.prevent - 调用 event.preventDefault()。
.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
.native - 监听组件根元素的原生事件。
.once - 只触发一次回调。
在这里插入图片描述

9、v-model 指令实现表单输入和应用状态之间的双向绑定

v-model 指令用来在 input、select、textarea、checkbox、radio 等表单控件元素上创建双向数据绑定,根据表单上的值,自动更新绑定的元素的值。
参考:https://www.cnblogs.com/mark5/p/11603428.html

v-model其实是一个语法糖,它的背后本质上是包含两个操作:

  • v-bind绑定一个value属性
  • v-on指令给当前元素绑定input事件
<input type="text" v-model="message">
等同于
<input type="text" v-bind:value="message" v-on:input="message = $event.target.value">

(1)、v-model 绑定input输入框

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>
</head>
{% verbatim %}
<body>

<div id="app">

    <p>{{ message }}</p>
    <input v-model="message">

</div>

<script>

    var app = new Vue({
        el: "#app",
        data: {
            message: 'Hello Vue!',
        },
    })
</script>


</body>

{% endverbatim %}


</html>

查看页面
在这里插入图片描述
message变量和input输入框和

标签绑定,如果修改输入框的值,则message值有变化,上面的

标签也会跟着修改
在这里插入图片描述

(2)、v-model 绑定select单选框

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>
    
</head>
{% verbatim %}
<body>

<div id="app">
    
    <select v-model="selected">
        <option value="A被选">A</option>
        <option value="B被选">B</option>
        <option value="C被选">C</option>
    </select>

    <p>{{ selected }}</p>

</div>

<script>

    var app = new Vue({
        el: "#app",
        data: {
            selected: "",
        },
    })
</script>


</body>

{% endverbatim %}


</html>

这里selected变量与单选框和

标签进行绑定,可以看到选择后

标签内容也会跟着变化,通过selected也可以设置value默认值,达到默认选择的效果,这里这是的是空字符串,比如要默认选择B,可以设为B的value=“B被选”

在这里插入图片描述

(3)、v-model 绑定checkbox复选框

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>

</head>
{% verbatim %}
<body>

<div id="app">

    <input type="checkbox" id="one" value="value_one" v-model="checkedNames">
    <label for="one">选项一</label>
    <input type="checkbox" id="two" value="value_two" v-model="checkedNames">
    <label for="two">选项二</label>
    <input type="checkbox" id="three" value="value_three" v-model="checkedNames">
    <label for="three">选项三</label>

    <p>{{ checkedNames }}</p>

</div>

<script>

    var app = new Vue({
        el: "#app",
        data: {
            checkedNames: [],
        },
    })
</script>


</body>

{% endverbatim %}


</html>

因为是多选,这里的data中的变量用数组[ ]来表示默认值,选择后同样会进行改变
在这里插入图片描述

10、vue指令计算属性

计算属性在vue对象的computed:{}字段里定义并设置返回值,例如在这里定义了sumScore这个变量,返回值为其他input标签绑定的v-model.number.lazy值相加。

  • 使用v-model.numbe指令来绑定input标签,因为input默认都是字符串类型的,如果需要数字类型的则需要加上number。
  • 使用v-model.lazy,改变input框中的内容并不会使得span中的内容发生变化,此时当输入框失去焦点后触发change事件.控制台中输出相应内容,如果不添加的话,在input中修改是便会每次都触发computed的计算函数,这样有一定的损耗,加上lazy属性后,当输入框数去焦点后才进行计算
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>

</head>
{% verbatim %}
<body>

<div id="app">

<table border="1">
            <thead>
                <tr>
                    <th>学科</th>
                    <th>成绩</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Python</td>
                    <td><input type="text" v-model.number.lazy="python"/></td>
                </tr>
                <tr>
                    <td>Vue</td>
                    <td><input type="text" v-model.number.lazy="vue"/></td>
                </tr>
                <tr>
                    <td>Go</td>
                    <td><input type="text" v-model.number.lazy="go"/></td>
                </tr>
                <tr>
                    <td>总成绩</td>
                    <td>{{ sumScore }}</td>
                </tr>
            </tbody>
        </table>
</div>

<script>
     let vm = new Vue({
            el: "#app",
            data: {
                python: 88,
                vue: 100,
                go: 65
            },
            computed: {
                sumScore: function () {
                    return this.python + this.vue + this.go;
                },
            },
        })

</script>


</body>

{% endverbatim %}


</html>

访问页面
在这里插入图片描述
如果进行修改input的值,那么sumScore也会改变,从而显示的值也改变
在这里插入图片描述

每个计算属性都包含一个getter和一个setter,在上面的例子中,我们只是使用getter来读取。在某些情况下,你也可以提供一个setter方法(不常用)。
在需要写setter的时候,代码如下
在这里插入图片描述
计算属性会进行缓存,如果多次使用时,计算属性只会调用一次
在这里插入图片描述
在这里插入图片描述

11、vue 监听属性

下面示例创建了两个输入框,data 属性中, kilometers 和 meters 初始值都为 0。watch 对象创建了两个方法 kilometers 和 meters。当我们再输入框输入数据时,watch 会实时监听数据变化并改变自身的值。

  • 可以在vue对象的 watch: {}字段中进行设置,例如watch: {kilometers: function (val) {}},监听kilometers属性的变化,function定义的方法中接收变化后的值参数。
  • 也可以在vue对象外部,调用vue对象的属性进行设置,例如app.$watch('kilometers', function (newValue, oldValue) {},监听app这个vue对象中kilometers属性的变化,function定义的方法中接收旧的和新的两个值参数。
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src={% static "vue.js" %}></script>

</head>
{% verbatim %}
<body>

<div id="app">
    千米 : <input type="text" v-model="kilometers">
    米 : <input type="text" v-model="meters">
</div>
<p id="info"></p>
</div>

<script>
    var app = new Vue({
        el: '#app',
        data: {
            kilometers: 0,
            meters: 0
        },
        methods: {},
        computed: {},
        watch: {
            kilometers: function (val) {
                this.kilometers = val;
                this.meters = this.kilometers * 1000
            },
            meters: function (val) {
                this.kilometers = val / 1000;
                this.meters = val;
            }
        }
    });
    // $watch 是一个实例方法
    app.$watch('kilometers', function (newValue, oldValue) {
        // 这个回调将在 vm.kilometers 改变后调用
        document.getElementById("info").innerHTML = "修改前值为: " + oldValue + ",修改后值为: " + newValue;
    })

</script>


</body>

{% endverbatim %}


</html>

访问页面,然后修改input框的值,可以看到有相互转换
在这里插入图片描述

三、综合实例 购物车

参考 vue 简单实现购物车案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<script src="../static/vue.js"></script>
<body>
 <style>
    thead {
      background-color: rgb(243, 243, 243);
    }

    td,
    th {
      border: solid 1px rgb(226, 226, 226);
    }

    table {
      border-collapse: collapse;
    }

    .end {
      color: black;
      font-size: 30px;
    }
  </style>

<div id="app">
    <table>
      <thead>
        <tr>
          <th></th>
          <th>书籍名称</th>
          <th>出版日期</th>
          <th>价格</th>
          <th>购买数量</th>
          <th>操作</th>
        </tr>
      </thead>
        <tbody>
        <tr v-for="(item,key) in books">
          <td>{{ key+1 }}</td>
          <td>{{item.name}}</td>
          <td>{{item.publish}}</td>
          <td>{{item.price | singlePrice}}</td>
          <td>
              <!-- 减少数量的按钮,click事件绑定decrement方法 当数量为 1 时不能再减少按钮变为不可用-->
            <button @click="decrement(key)" :disabled="item.count===1">-</button>
            <button>{{item.count}}</button>
              <!-- 增加数量的按钮,click事件绑定increment方法-->
            <button @click="increment(key)">+</button>
          </td>

            <!--移除商品的按钮,click时间绑定remove方法,传入key将当前数组中当前key的商品删除-->   <!---->
          <td><button @click="remove(key)">移除</button></td>
        </tr>
        </tbody>

    </table>

    <!-- 当books数组的长度不为0,显示总价格,如果长度为0则表示商品都被移除了,显示购物车为空 -->
     <div class="end">
      <div v-if="books.length!==0">
        总价格{{totalPrice}}
      </div>
      <div v-else> 购物车为空 </div>
    </div>

</div>

 <script>
    const app = new Vue({
      el: '#app',
      data: {
        books: [{
            name: '《算法导论》',
            publish: '2006-9',
            price: 85,
            count: 1
          },
          {
            name: '《UNIX编程艺术》',
            publish: '2006-2',
            price: 59,
            count: 1
          },
          {
            name: '《编程珠玑》',
            publish: '2008-10',
            price: 39,
            count: 1
          },
          {
            name: '《代码大全》',
            publish: '2006-3',
            price: 128,
            count: 1
          }
        ]
      },
      methods: {
        increment(key) {
          this.books[key].count++;
        },
        decrement(key) {
          this.books[key].count--;
        },
        remove(key) {
          this.books.splice(key, 1);
        }
      },
      computed: {
          //计算属性,表示总价格,当监听相关数据有变化时会跟着改变
        totalPrice() {
          //for in 遍历写法
           let sum = 0;
           for (let i in this.books) {
             sum += this.books[i].price * this.books[i].count;
           }

          //高阶函数reduce写法
          //let sum = this.books.reduce((prev, item) => prev + item.price, 0);

          return '¥' + sum.toFixed(2);

        }
      },
      filters: {
          //过滤器,将价格进行格式化
        singlePrice(value) {
          return '¥' + value.toFixed(2);
        }
      }
    })
  </script>

</body>
</html>

在这里插入图片描述

Logo

前往低代码交流专区

更多推荐