.
Vue与原生js对比
案例:将文本框输入的内容显示到页面中
原生js
vue
对比
最明显的区别:vue 中不用操作 dom 元素
这可以让开发者将经历集中到数据处理及业务逻辑开发中
vue
Vue特点
1.国人开发的一个轻量级框架。
2.双向数据绑定,在数据操作方面更为简单。
3.视图,数据,结构分离,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作。
4.组件化,方便封装和复用
5.虚拟DOM: dom操作是非常耗费性能的,不再使用原 生的dom操作节点,极大解放dom操作
vue框架
通过 new Vue 创建 vue 实例
el 属性指定当前 vue 实例的挂载点
data 中是模型数据,这些数据依赖于当前的vue实例,
可以在控制台中通过app.msg访问data中数据
数据绑定
所谓属于绑定,就是将 vue 实例中的 data 属性中的变量显示到挂载点(dom结构)中
内容绑定
将 data 中的数据显示成内容(开始标签与结束标签之间)
使用 {{}}
<div id="app">
<p>{{title}}</p>
</div>
上面只能显示纯文本,如果要显示 html 内容,需要使用 v-html 指令
<p v-html="content"></p>
属性绑定
将data中的数据作为某个元素的属性的值
使用 v-bind:属性名称 指令,属性可以是内置,也可以是自定义的
<p v-bind:id="id">{{title}}</p>
v-bind: 可以缩写为 :
<p :id="id" :class="title_class">{{title}}</p>
双向数据绑定
什么是数据双向绑定?
vue是一个mvvm框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是vue的精髓之处了。值得注意的是, 我们所说的数据双向绑定,一定是对于UI控件来说的,非UI控件不会涉及到数据双向绑定。 单向数据绑定是使用状态管理工具(如redux)的前提。如果我们使用vuex,那么数据流也是单项的,这时就会和双向数据绑定有冲突解决方法
为什么要实现数据的双向绑定?
在vue中,如果使用vuex,实际上数据还是单向的,之所以说是数据双向绑定,这是用的UI控件来说,对于我们处理表单,vue的双向数据绑定用起来就特别舒服了。
<body>
<div id="app">
<!-- <span>{{msg}}</span> -->
<input type="text" v-model="msg" />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
msg: 'hello',
},
})
</script>
</body>
复选框的数据绑定
复选框,v-model 绑定的是 checked 属性
vue绑定
vue绑定class
<body>
<div id="app">
<p v-bind:class="pClass"></p>
<!-- 对象表示法 -->
<!-- <p v-bind:class="{active:isActive}">对象表示法</p> -->
<!-- 多个属性共存 -->
<!-- 将 class 属性称作静态 class,将 v-bind:class 称作动态class -->
<p class="base" v-bind:class="{active:isActive,color:isColor}">对象表示法</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
id: 11,
pClass: 'c2',
isActive: true,
isColor: true
},
})
</script>
</body>
vue绑定style
<body>
<div id="app">
<p :style="{width:w,height:h,backgroundColor:a}"></p>
<p :style="obj"></p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
w: '300px',
h: "200px",
a: 'lightblue',
obj: {
width: '400px',
height: '100px',
backgroundColor: 'blue'
}
},
})
</script>
</body>
表单控件的值
可以用 v-model 指令在表单 、 及 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。
v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
text 和 textarea 元素使用 value property 和 input 事件;
checkbox 和 radio 使用 checked property 和 change 事件;
select 字段将 value 作为 prop 并将 change 作为事件。
单选框
<body>
<div id="app">
<label for="man">男</label>
<input type="radio" id="man" value="man" v-model="gender" />
<label for="women">女</label>
<input type="radio" id="women" value="women" v-model="gender" />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
gender: '',
},
})
</script>
</body>
设置多个单选框的 v-model 为同样的值,就可以省略 name 属性
选择某个单选框后,此单选框的 vlue 属性值会赋值给 gender 属性
设置 gender 属性的值为某个单选框的 value 值,此单选框就会默认选中
下拉菜单
<body>
<div id="app">
<select v-model="city">
<option disabled value="">请选择</option>
<option value="bj">北京</option>
<option value="sh">上海</option>
</select>
<p>{{city}}</p>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
city: '',
},
})
</script>
</body>
模板使用js表达
<body>
<div id="app">
<p>{{age + 1}}</p>
<p>{{message.split('').reverse().join('')}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
age: 10,
message: '12345',
},
})
</script>
</body>
列表渲染
我们可以用 v-for 指令基于一个数组来渲染一个列表。
<body>
<div id="app">
<ul>
<li v-for="blog in blogs">{{blog}}</li>
</ul>
<ul>
<li v-for="item in books">{{item.title}}--- {{item.author}}</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
blogs: ['今天的天气不是很好', '不知道明天怎样', '现在6度', '外面好冷啊'],
books: [
{ id: 1, title: '庆余年', author: '忘了' },
{ id: 2, title: '在劫难逃', author: '五百' },
{ id: 3, title: '盗墓笔记', author: '南派三叔' },
],
},
})
</script>
</body>
模板渲染
<body>
<div id="app">
<ul>
<li v-for="item in books">{{item.title}}</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
books: [],
},
created: function () {
fetch('data.json')
.then((res) => {
return res.json()
})
.then((res) => {
this.books = res
})
},
})
</script>
</body>
created 函数会再 vue 实例实例化时执行
//data.json
[
{ "id": 1, "title": "庆余年", "author": "忘了" },
{ "id": 2, "title": "鬼吹灯", "author": "忘了" },
{ "id": 3, "title": "盗墓笔记", "author": "忘了" }
]
条件渲染
可以单独使用 v-if,或者 v-if 和 v-else,或者 v-if 和 v-else-if 搭配使用。
v-if在单独使用的时候,与 v-show 的作用是一样的,都是根据变量的值决定是显示还是隐藏当前元素。
<body>
<div id="app">
<h1 v-if="isMary">已婚</h1>
<h1 v-else>未婚</h1>
<div v-if="type">v-if</div>
<div v-show="type">v-show</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
isMary: false,
type: true
},
})
</script>
</body>
v-if 和 v-show 的区别
共同点:都能控制元素的显示和隐藏。
不同点:实现本质方法不同。
v-show本质就是通过控制css中的display设置为none,控制隐藏,只会编译一次; v-if是动态的向DOM树内添加
或者删除DOM元素,若初始值为false,就不会编译了。而且v-if不停的销毁和创建比较消耗性能。
总结:如果要频繁切换某节点,使用v-show(切换开销比较小,初始开销较大)。如果不需要频繁切换某节点使用v-if (初始渲染开销较小,切换开销比较大)
事件处理
js 中可以通过 addEventListener 的方式为元素注册各种事件类型
vue 中通过 v-on 指令为元素注册事件监听,在 methods 对象中定义方法
<body>
<div id="app">
<button v-on:click="greet">按钮</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
name: 'onlifes'
},
methods: {
greet: function () {
// 事件当中, this 指向的是当前 vue 实例
console.log(this.name);
this.name = 'yhb'
}
}
})
</script>
</body>
切换元素背景
<title>Document</title>
<style>
.base {
width: 200px;
height: 200px;
border: 1px solid black;
}
.active {
background-color: blue;
}
</style>
</head>
<body>
<div id="app">
<div v-on:click="changeBg" class="base" :class={active:isActive}></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
isActive: false
},
methods: {
changeBg: function () {
this.isActive = !this.isActive
}
}
})
</script>
</body>
切换壁纸
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body,
#app {
height: 100%;
}
nav {
height: 150px;
background-color: rgba(0, 0, 0, .2);
text-align: center;
}
img {
height: 120px;
margin: 15px 20px;
}
</style>
</head>
<body>
<div id="app" :style="{backgroundImage:bgImg}">
<nav>
<img src="./images/1.jpg" v-on:click="changeBg('./images/1.jpg')" alt="">
<img src="./images/2.jpg" v-on:click="changeBg('./images/2.jpg')" alt="">
<img src="./images/3.jpg" v-on:click="changeBg('./images/3.jpg')" alt="">
</nav>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
bgImg: 'url(./images/1.jpg)'
},
methods: {
changeBg: function (url) {
console.log(url);
// 切换 bgImg 的值为当前点击的图片的路径
this.bgImg = `url(${url})`
}
}
})
</script>
</body>
计算属性
对于任何复杂逻辑,你都应当使用计算属性。
<body>
<div id="app">
<!-- {{numbers.split('').reverse().join('')}} -->
<p>{{reversednumbers}}</p>
<table>
<thead>
<tr>
<th>编号</th>
<th>标题</th>
<th>发表时间</th>
</tr>
</thead>
<tbody>
<tr v-for="item in blogListFormat">
<td>{{item.id}}</td>
<td>{{item.title}}</td>
<td>{{item.create_time}}</td>
</tr>
</tbody>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
numbers: '12345',
blogList: [
{ id: 1, title: '今天真的好冷', create_time: 1614665768000 },
{ id: 2, title: '明天气温就回升了', create_time: 1614579284000 },
{ id: 3, title: '春暖花开', create_time: 1583043284000 }
]
},
// 用户自定义的方法
methods: {
// formatTime: function (a) {
// return a
// }
},
// 计算属性
computed: {
reversednumbers: function () {
// 计算属性内部一定要使用 return 返回一个值
return this.numbers.split('').reverse().join('')
},
blogListFormat: function () {
this.blogList.forEach(item => {
item.create_time = moment((item.create_time)).format('YYYY-MM-DD HH:mm:ss')
})
return this.blogList
}
}
})
</script>
</body>
data 中和 compoted 中都叫做属性,
也就是说 numbers 和 reversednumbers 都叫做属性
1、data 中的属性的值是一个数字、字符串、对象、数组等静态值
2、compited 中的属性叫做计算属性,其值是一个匿名函数
3、匿名函数一定要返回一个值,作为这个属性的值
控制台中修改 create_time 的值测试计算属性,注意不能加上引号
使用方法格式化日期
<body>
<div id="app">
<table>
<thead>
<tr>
<th>编号</th>
<th>标题</th>
<th>发表时间</th>
</tr>
</thead>
<tbody>
<tr v-for="item in blogList">
<td>{{item.id}}</td>
<td>{{item.title}}</td>
<td>{{formatTime(item.create_time)}}</td>
</tr>
</tbody>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
blogList: [
{ id: 1, title: '今天真的好冷', create_time: 1614665768000 },
{ id: 2, title: '明天气温就回升了', create_time: 1614579284000 },
{ id: 3, title: '春暖花开', create_time: 1583043284000 }
]
},
// 用户自定义的方法
methods: {
formatTime: function (a) {
return moment(a).format('YYYY-MM-DD HH:mm:ss')
}
},
})
</script>
</body>
侦听器
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
vue 中的计算属性是不支持异步操作的,只能计算一些同步的值,但是可以使用 vue-async-computed 插件实现这一点
案例
<body>
<div id="app">
<input type="text" v-model="age">
<br>
<span>{{message}}</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
/*
用户在文本框中输入年龄
1、如果年龄>=12,span中就显示“12虽已经到了入刑年龄”
2、如果年龄<12岁,span中就显示“还不到入刑年龄”
*/
let app = new Vue({
el: '#app',
data: {
age: 20,
message: ''
},
methods: {},
computed: {},
watch: {
age: function (newValue, oldValue) {
// 当 age 属性发生变化时,就会执行这个函数
if (newValue >= 12) {
this.message = '12虽已经到了入刑年龄'
} else {
this.message = '还不到入刑年龄'
}
}
}
})
</script>
</body>
用计算属性实现侦听器
<body>
<div id="app">
<input type="text" v-model="age">
<br>
<span>{{ageInfo}}</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
age: 20
},
computed: {
ageInfo: function () {
if (this.age >= 12) {
return '12岁已经到了入刑年龄'
} else {
return '还不到入刑年龄'
}
}
}
})
</script>
</body>
问答案例
<body>
<div id="app">
<label for="question">请输入你的问题</label>
<input type="text" v-model="question">
<ul>
<li v-for="item in answer">
{{item}}
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
question: '',
answer: []
},
//
methods: {
getAnswer: function () {
let that = this
axios.get('http://localhost:3000/answer.php?q=' + this.question)
.then(function (response) {
// console.log(response.data);
that.answer = response.data
})
}
},
watch: {
question: function (newValue) {
this.getAnswer()
}
}
})
</script>
</body>