JavaWeb 学习笔记 9:Vue

JavaWeb 学习笔记 9:Vue

1.快速开始

Vue 是一个前端框架,可以作用于浏览器或者 Node.js,它的优点是可以实现视图(View)和数据模型(Model)的双向绑定。

Vue 的这种双向绑定类似于很多年前我用 C# 开发桌面应用的体验。

来看一个示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
    <input type="text" v-model="input">{{input}}
</div>
</body>
<script>
    const { createApp } = Vue
    createApp({
        data() {
            return {
                input: ""
            }
        }
    }).mount('#app')
</script>
</html>

这里使用一个 CDN 引入 vue 的 js 文件:

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

vue.global.js提供了一个全局的Vue对象,我们可以利用这个对象完成数据绑定:

const { createApp } = Vue

createApp需要传入一个 js 对象,这个对象的data属性接收一个方法,该方法返回的 js 对象的属性就是 Vue 的数据模型(Model):

createApp({
    data() {
        return {
            input: ""
        }
    }
}).mount('#app')

也就是说,这里创建的数据模型是input,初始值是空字符串。

data(){...}是一种匿名方法作为 js 对象属性的简写形式,和下面的方式是等价的:

createApp({
    data: function () {
        return {
            input: ""
        }
    }
}).mount('#app')

最后的.mount()方法会将创建好的 Vue 的数据模型绑定到指定的 Html DOM 节点上(在这个示例中是idappdiv),目标节点及其子节点都可以使用相应的数据模型。

要实现数据模型和具体 Html 视图标签的绑定,要定义一个v-model属性:

<input type="text" v-model="input">

实现绑定后,这个标签的值改变后数据模型就会改变,数据模型改变后标签的值也会改变,这就是双向绑定。

要在 Html 中直接(动态)显示数据模型的值,可以使用一个叫做”插值表达式“的东西:

{{input}}

页面被加载后,这个插值表达式会被 Vue 自动替换为数据模型的值,且数据模型的值改变后同样会更新。

最终的效果类似下面这样:

image-20230915154622811

输入框中输入任意值后,输入框后边的插值表达式的地方会随之改变。

2.常用指令

2.1.v-bind

前面已经介绍了使用v-model将数据模型绑定到标签的值,如果需要将数据模型绑定到标签的属性,就需要使用v-bind

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
    SearchEngine: {{se}}<br/>
    <select v-model="se">
        <option value="http://baidu.com">百度</option>
        <option value="https://cn.bing.com">Bing</option>
        <option value="http://google.com">Google</option>
    </select>
    <a v-bind:href="se" target="_blank">Go Search</a>
</div>
</body>
<script>
    const { createApp } = Vue
    createApp({
        data() {
            return {
                se: "http://google.com"
            }
        }
    }).mount('#app')
</script>
</html>

在上面这个示例中,用一个select标签选择不同的搜索引擎,并且这个标签和se模型绑定,还使用一个额外的链接(a标签)实现跳转到选择的搜索引擎(新标签页)。因为超链接需要根据我们选定的搜索引擎跳转到不同的地址,所以其href属性必须是动态的,传统方式可能需要一些 js 判断 select 标签的当前值并对超链接的 href 属性进行修改,但现在只需要用v-bindhref属性绑定到模型se上即可,因为模型se已经和select的值进行了绑定。

最终的效果就是选择不同的搜索引擎后点击 Go Search 即会跳转到相应的搜索引擎主页:

image-20230915160108233

此外,属性绑定还有一种简写方式:

<a :href="se" target="_blank">Go Search</a>

和下面的形式是等效的:

<a v-bind:href="se" target="_blank">Go Search</a>

2.2.v-on

除了可以绑定属性,还可以将 Vue 中定义的方法绑定到 DOM 事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
    <button v-on:click="clickHappen()">
        click
    </button>
</div>
</body>
<script>
    const {createApp} = Vue
    createApp({
        methods: {
            clickHappen: function () {
                console.log("click...")
            }
        }
    }).mount('#app')
</script>
</html>

需要注意的是,DOM 事件 并不等同于 Html 事件,比如 DOM 事件click对应 Html 事件onclick

createApp的初始化参数中,用methods属性定义 Vue 的自定义方法(事件处理器),因为可以是多个方法,所以methods的值是一个 js 对象,对象的属性名称是自定义方法名,值是匿名方法:

createApp({
    methods: {
        clickHappen: function () {
            console.log("click...")
        }
    }
}).mount('#app')

绑定事件很简单:

<button v-on:click="clickHappen()">

也可以使用一种简写方式:

<button @click="clickHappen()">

2.2.1.内联事件处理器

对于简单的内容,可以使用一种”内联事件处理器“的方式绑定事件,比如下面这个示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
    <button @click="countPlus">
        Count is: {{ count }}
    </button>
</div>
</body>
<script>
    const {createApp} = Vue
    createApp({
        data: function () {
            return {
                count: 0
            }
        },
        methods: {
            countPlus: function () {
                this.count++;
            }
        }
    }).mount('#app')
</script>
</html>

Vue 中定义的事件处理器countPlus的作用仅仅是让数据模型count自增,对于这种简单的事件处理,可以使用内联事件处理器的写法:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
    <button @click="count++">
        Count is: {{ count }}
    </button>
</div>
</body>
<script>
    const {createApp} = Vue
    createApp({
        data: function () {
            return {
                count: 0
            }
        }
    }).mount('#app')
</script>
</html>

2.3.v-if

可以用v-if控制标签是否显示:

<div id="app">
    <div v-if="count < 5">小于5</div>
    <div v-else-if="count == 5">等于5</div>
    <div v-else>大于5</div>
    <button @click="count++">
        Count is: {{ count }}
    </button>
</div>

这个示例是在之前示例基础上,添加3个div标签,用来显示当前数据模型count的值是否大于5,这里使用v-ifv-else-ifv-else属性控制所在标签在什么条件下才显示。

2.3.1.v-show

除了v-if外,还有一个v-show标签,有类似的效果:

<div id="app">
    <div v-show="count < 5">小于5</div>
    <div v-show="count == 5">等于5</div>
    <div v-show="count > 5">大于5</div>
    <button @click="count++">
        Count is: {{ count }}
    </button>
</div>

这两个示例在页面显示上效果完全相同,但它们的实现细节有所不同。

对于 v-show,它是控制是否显示的 css 样式来显示或隐藏标签实现的:

image-20230915164657882

对于 v-if,它是直接添加或删除 DOM 节点的方式来实现的:

image-20230915164815542

2.4.v-for

之前展示过一个搜索引擎筛选的示例,是用硬编码的方式实现的select标签的option标签,现在可以用v-for循环遍历数据模型来生成 option 标签:

<body>
<div id="app">
    SearchEngine: {{se}}<br/>
    <select v-model="se">
        <option v-for="engine in engines" :value="engine.url">{{engine.name}}</option>
    </select>
    <a :href="se" target="_blank">Go Search</a>
</div>
</body>
<script>
    const { createApp } = Vue
    createApp({
        data() {
            return {
                se: "http://google.com",
                engines: [
                    {name: "百度", url: "http://baidu.com"},
                    {name: "Bing", url: "https://cn.bing.com"},
                    {name: "Google", url: "http://google.com"}
                ]
            }
        }
    }).mount('#app')
</script>

就像时候后端的语言一样,有时候在循环遍历的时候我们希望获取当前的数组元素下标,在使用 Vue 的v-for时可以这样:

<option v-for="(engine,i) in engines" :value="engine.url">{{i}}-{{engine.name}}</option>

效果:

image-20230915170523469

这种写法和 Python 的风格类似。

3.生命周期

Vue 有以下生命周期阶段:

image-20210831160239294

Vue 官方的生命周期图示:

组件生命周期图示

一般我们只需要定义和使用 mounted 回调方法即可:

<script>
    const {createApp} = Vue
    createApp({
        data: function () {
            return {
                count: 0
            }
        },
        mounted: function (){
            console.log("Vue is ready...")
        }
    }).mount('#app')
</script>

mounted回调被执行时意味着 Vue 已经加载完毕。

4.案例:商品列表

用 Vue 可以简化页面数据的填充工作,这里以之前使用的示例项目login-demo为例进行说明。

之前是使用 Axios 获取数据后,用 JQuery 操作 DOM 对象,进行遍历填充。虽然 JQuery 简化了一部分操作,但操作 DOM 对象依然是一个繁琐的工作。

使用 Vue,我们只需要将需要填充的数据定义成数据模型:

createApp({
    data() {
        return {
            brands: [],
            username: ""
        };
    },
    // ...
})
// ...

然后使用这个数据模型绑定标签:

<table id="brandsTable" border="1" cellspacing="0" width="800">
    <tr>
        <th>序号</th>
        <th>品牌名称</th>
        <th>企业名称</th>
        <th>排序</th>
        <th>品牌介绍</th>
        <th>状态</th>
        <th>操作</th>
    </tr>
    <tr align="center" v-for="(brand,index) in brands">
        <td>{{index+1}}</td>
        <td>{{brand.brandName}}</td>
        <td>{{brand.companyName}}</td>
        <td>{{brand.ordered}}</td>
        <td>{{brand.description}}</td>
        <td v-if="brand.status==0">启用</td>
        <td v-else>禁用</td>
        <td><a :href="brand.editUrl">修改</a>
            <a :href="brand.deleteUrl">删除</a></td>
    </tr>
</table>

现在 Vue 的数据模型和标签已经绑定好了,只要数据模型中有内容,表格就会自动填充。

所以剩下的工作就是在 mounted 回调中异步加载数据:

mounted() {
    let _vue = this;
    axios({
        method: "POST",
        url: "/login-demo/brand/list",
        data: {}
    })
        .then((resp) => {
        _vue.brands = resp.data;
        _vue.brands.forEach((brand) => {
            brand.editUrl = "/login-demo/brand/edit?id=" + brand.id;
            brand.deleteUrl = "/login-demo/brand/delete?id=" + brand.id;
        });
    });
    axios({
        method: "GET",
        url: "/login-demo/user/info",
        data: {}
    }).then((resp)=>{
        _vue.username = resp.data.username;
    });
}

这里有一个小技巧,在createApp的事件处理器(自定义方法)或者生命周期回调中,可以使用this.attrName获取 Vue 的数据模型,但是如果嵌套了对象,比如上边的axios(),在axios的方法(这里是then)中,this显然指向的是axios对象本身,如果想要获取外部的句柄,就需要在外部定义一个局部变量,这里用_vue表示。

可以用类似的方式简化其它页面,比如品牌添加页。这里不再赘述,感兴趣的可以查看完整示例。

The End,谢谢阅读。

本文的完整示例代码可以从这里获取。

5.参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值