vue是一个前端框架,开发者只需要关注视图层(HTML+CSS+JS),其他的框架都已经封装好了。
网络通信:axios
页面跳转:vue-router
状态管理:vuex
VUE-UI: element-ui等等
学习vue之前,一定要有HTML、CSS、JavaScript的基础。
原生js开发,就是让我们按照【ECMAScript】标准的开发方式,简称ES,特点是:所有浏览器都支持。ES也有很多版本。开发时,大多是按照ES6的版本开发。但是大多数浏览器现在基本支持到ES5,所有我们需要使用 Webpack进行打包。
本质上,webpack是一个现代JavaScript应用程序的静态模块打包器
,项目下需要有 package.json文件
。webpack是一款模块加载兼打包工具,能把各种资源(js,ES6)图片等作为模块来处理和使用。
ViewModel能够监听数据的变化,并且对视图进行更新。而且还能监听到视图的变化,通知数据进行改变。
命令 | 说明 | 实例 |
---|---|---|
v-bind | 绑定属性 | v-bind:title=“message” 或者 :title=“message” |
v-on | 绑定事件 | v-on:click=“方法” 或者 @click=“方法” |
v-if | 是否显示(删除DOM元素方式) | 0”>我是h2 |
v-show | 是否显示(改属性方式) | 0”>我是h2 |
v-for | 遍历 | |
v-model | 数据视图双向绑定 | |
v-once | 在标签元素上使用后,元素中vue变量的值不会再改变 | {{ message }} |
v-pre | 不解析{{}},插值表达式,原封不动 | |
v-cloak | 解决插值表达式闪烁 |
为某个元素绑定事件,实现一个事件监听功能。
语法:v-on
或者使用v-on的语法糖 @
当函数中没有需要参数时,vue指令中调用函数时,可以不加(),但是插值表达式必须加
<div id="app">
<h2>{{counter}}h2>
<button @click="increment">+button>
<button @click="decrement">-button>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
const app = new Vue({
el:"#app",
data:{
counter:0
},
methods:{
increment(){
this.counter++;
},
decrement(){
this.counter--;
}
}
})
script>
当方法中定义了参数,但是使用的时候没有传过来,那么Vue会将浏览器生成的event对象给调用的方法中第一个参数传过去。
<div id="app">
<button @click="add">+button>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
const app = new Vue({
el:"#app",
methods:{
add(abc){ // 这里会获取到event对象
console.log(abc)
}
}
})
script>
当方法中,需要一般参数和事件参数时,特殊情况
<div id="app">
<button @click="add">+button>
<button @click="add(11, event)">+button>
<button @click="add(11,$event)">+button>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
const app = new Vue({
el:"#app",
methods:{
add(abc,event){
console.log(abc, event)
}
}
})
script>
.stop : 调用event.stopPropagation(),阻止冒泡
使用后,当子元素和父元素都设置了点击事件时,点击子元素,只执行子元素的点击事件
<div id="app" @click="divClick">
aaaaaa
<button @click.stop="btnClick">按钮button>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
const app = new Vue({
el:"#app",
methods:{
btnClick(){
console.log('btnClick')
},
divClick(){
console.log('divClick')
}
}
})
script>
.prevent : 调用event.preventDefault(),阻止默认事件,比如表单提交,我点提交按钮,只想执行我自己定义的事件进行提交
<div id="app" @click="divClick">
<form action="aaa">
<input type="submit" value="提交" @click.prevent="formSubmit">
form>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
const app = new Vue({
el:"#app",
methods:{
formSubmit(){
console.log('formSubmit')
}
}
})
script>
.keyCode: 监听键盘点击
@keyup.enter: 回车
<div id="app">
<input type="text" @keyup.enter="add" value="">
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
const app = new Vue({
el:"#app",
methods:{
add(){
alert("回车了")
}
}
})
script>
.native : 监听组件的根元素的原生事件
.once : 只触发一次,回调只执行一次
从开始创建 -> 初始化数据 -> 编译模板 -> 挂载DOM -> 渲染->卸载等
开发中,经常会需要在某一个时刻把数据加载到页面元素中,那么在vue生命周期中,就存在一些钩子函数(事件),我们可以在某一刻的钩子函数中加载数据。
beforeCreate:创建vue实例之前执行的钩子函数
created: 创建vue实例完成后,执行的钩子函数
beforeMount: 将编译完成的HTML挂载到对应虚拟DOM时触发的钩子(此时页面是没有内容的)
mouted: 编译好的HTML挂载到页面完后执行的钩子(可在此做数据的初始化),注意:mounted在整个实例中只会执行一次
。。。
var app = new Vue({
el:"#app",
data:{
items:["java","Linux"]
},
mounted(){
console.log("初始化数据了")
}
})
组件就是可以复用的Vue实例,说白了,就是一组可以重复使用的模板
<div id="app">
<vue v-for="item in items" :wlh="item">vue>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
// 定义组件
Vue.component("vue",{
props:['wlh'], // 定义这个组件接收的参数
template: '{{ wlh }} ' // 定义展示的模板
})
var app = new Vue({
el:"#app",
data:{
items:["java","Linux"]
}
})
script>
后面开发中,我们一个vue文件就是一个组件,可在view(html)中引用。
需要注意的是:vue组件中不能定义data属性,只能定义一个data的函数
计算属性:计算出来的结果保存在属性中,内存中运行:虚拟DOM。计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,节约系统开销。
理解为:将计算结果存入缓存
需要注意的是:计算属性是一个属性,不是一个函数,调用时不要加小括号 '()'
<div id="app">
<p>currentTime1 : {{ currentTime1() }}p>
<p>currentTime2 : {{ currentTime2 }}p>
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>
var app = new Vue({
el:"#app",
data:{
message:"hello vue"
},
methods:{
currentTime1:function(){
return Date.now(); // 返回一个时间戳
}
},
// 计算属性 不要和 methods属性中的方法重复,否则只会调用 methods中的方法
computed:{
currentTime2:function(){
this.message; // 当发现 message属性变化时,会重新返回一个 时间戳,否则就不会变
return Date.now(); // 返回一个时间戳
}
}
})
script>
以上代码中实现,当 vue对象的message属性变化时(由于currentTime2函数中用到了 message),currentTime2会再次执行一次,并且将结果返回给 {{currentTime2}}
计算属性的实现,实际上就是属性的get方法
new Vue({
el: '#app',
data:{
firstName:"w",
lastName:"lh"
},
computed:{
fullName:function(){ // fullName和fullName2达到同样的效果
return this.firstName + " " + this.lastName;
},
fullName2:{
set:function(){ // 计算属性中,set方法一般不用实现,这里只是为了说明
},
get:function(){ // 通过get方法,获取值
return this.firstName + " " + this.lastName;
}
}
}
})
问题一:
网页元素被正式渲染到浏览器上面之前,会先去虚拟DOM中做一次预处理。假如有上次遗留的可复用的一些网页元素,那么Vue就会去直接去使用这些用过的DOM元素(导致某些数据没有被清空),把某些属性给替换掉。
问题二:
假如一个数组已经渲染到了浏览器上,然后我要动态给数组中插入一个元素,那么默认的做法就是:找到要替换的位置,然后把值直接赋给这个位置上,然后后面依次去修改元素的值。导致效率低下。
解决方案:
给标签元素加key,给标签做一个标识,假如两个标签元素的key是相同的,那么vue才会去复用标签元素
;当我们插入元素时,需要使用key给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。
key要选择具有唯一值的
<li :key="xxx.id">li>
let支持块级作用域。var是不支持块级作用域的,也就是var定义的变量全局
可用。
ES5及之前因为if和for
都没有块级作用域的概念,所以很多时候都要借助于function的作用域(注意function是有作用域的)来解决使用外面变量的问题。
在ES6中,加入了let
,let是有if和for块级作用域。
实例讲解:
var
if(true){
var name = "zs" // 在if代码块中定义了一个 name属性
}
alert(name)// 因为name是没有块级作用域的(name变成了全局变量),if代码块外部同样可以调用。。。
let
if(true){
let name = "zs" // 在if代码块中定义了一个 name属性
}
alert(name)// 因为name是有块级作用域的(name变成了局部变量),if代码块外部不能调用
将标识符修改为常量。在ES6开发中,优先使用const,只有需要改变某一个标识符的时候才去使用let。
定义const时,必须要赋值进行初始化。
需要注意的是:常量的含义是,指向的对象不能修改,但是可以改变对象内部的属性。
const obj = {
name:"zs",
age:21
}
obj.name = "ls" // 可以修改
const name ="zs"
const age = 21
function hello(){
alert("你好")
}
const obj = {
name, // 可直接省略value值,会自动找上面的name
age,
hello // 这里会直接找同名的 对象赋给 hello属性
}
console.log(obj)
const obj = {
run(){
},
eat(){
}
}
<div id="app">
<ul>
<li v-for="item in letters" :key="item">{{item}}li>
ul>
<button @click="clickBtn">点击button>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
const app = new Vue({
el: "#app",
data: {
letters: ["a", "b", "f","c", "d"]
},
methods: {
clickBtn() {
// 1.push()方法 是响应式
this.letters.push('aa','bb');
// 2.直接修改数组中的值 注意:不是响应式,修改后,页面上不会发生任何改变
this.letters[0] = 'bbbbb';
// 3.pop() (删除尾部的一个元素)响应式
this.letters.pop();
// 4.shift() (删除头部的一个元素) 响应式
this.letters.shift()
// 5.unshift() 在头部插入元素 响应式
this.letters.unshift("aaaa","bc");
// 6.splice() (插入元素) param1:开始位置 param2:数量 params3:元素或者数组 响应式
this.letters.splice(1,1,"j","k","l") // 把下标是 1 的元素替换成了 j、k、l
// 7.sort() 排序 响应式
this.letters.sort()
//8.reverse() 反转 响应式
this.letters.reverse()
}
}
})
script>
<td>¥{{item.price | getFinalPrice}}td>
<script>
const app = new Vue({
el: "#app",
filters:{
getFinalPrice(price){
return price.toFixed(2); // 保留两位小数
}
}
})
script>
原理:当vue对象解析 {{message}}之前,div标签会存在一个 v-cloak
的属性,在vue解析完{{message}}之后,将div标签的v-cloak
属性删除掉。
<style>
[v-cloak]{
display: none;
}
style>
<body>
<div id="app" v-cloak>
{{message}}
div>
body>
实现:当选中一个选项时,把当前选项的value值,及时更新到变量中
<div id="app">
<select v-model="selected">
<option value="" disabled>--请选择--option>
<option value="A">Aoption>
<option value="B">Boption>
<option value="C">Coption>
select>
<h2>{{ selected }}h2>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
var app = new Vue({
el:"#app",
data:{
selected:''
}
})
script>
<h2 class="title" :class="[active, line]">h2>
<h2 class="title" :class="['active', 'line']">h2>
第一个h2标签的 active和line是使用的vue中的变量
第二个h2标签是定义class的值为: active和line
class和:class最后都会被合并到一起。
<h2 :style="{font-size: '20px'}">h2> // 使用值
<h2 :style="{font-size: vueFontSize+'px'}">h2> // 使用vue变量
<div id="app">
<h2 v-if="books.length==0">购物车为空h2>
<table border="1px">
<tr v-if="books.length!=0">
<td>序号td>
<td>书名td>
<td>出版日期td>
<td>价格td>
<td>购买数量td>
<td>操作td>
tr>
<tr v-for="(item,index) in books" :key="item.id">
<td>{{index+1}}td>
<td>{{item.name}}td>
<td>{{item.date}}td>
<td>¥{{item.price | getFinalPrice}}td>
<td>
<button @click="decrement(index)" :disabled="item.count===1">-button>
{{item.count}}
<button @click="increment(index)">+button>
td>
<td>
<button @click="remove(index)">移除button>
td>
tr>
table>
总价:{{totalPrice | getFinalPrice}}
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
const app = new Vue({
el: "#app",
data: {
books:[
{
id:1,
name:"《算法导论》",
date:"2006-9",
price:85.12,
count:1
},
{
id:2,
name:"《UNIX编程艺术》",
date:"2006-2",
price:59.28,
count:1
},
{
id:3,
name:"《编程珠玑》",
date:"2008-10",
price:39.2,
count:1
},
{
id:4,
name:"《代码大全》",
date:"2006-3",
price:128.00,
count:1
}
]
},
methods:{
remove(index){
this.books.splice(index, 1);
},
increment(index){
this.books[index].count++;
},
decrement(index){
this.books[index].count--;
}
},
computed:{
totalPrice:function(){
console.log("totalPrice")
return this.books.reduce((a, b) => a+b.count*b.price, 0);
}
},
filters:{
getFinalPrice(price){
return price.toFixed(2);
}
}
})
script>