1:vue的安装
使用一个框架,我们第一步要做什么呢?安装下载它
安装Vue的方式有很多:
方式一:直接CDN引入
你可以选择引入开发环境版本还是生产环境版本
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
方式二:下载和引入
开发环境 https://vuejs.org/js/vue.js
生产环境 https://vuejs.org/js/vue.min.js
方式三:NPM安装
通过webpack和CLI的安装使用
我的公司开发时使用webpack安装了vue即方式三
注:本文是本人vue学习笔记,本文多数内容属于Vue2.6之前的内容,只有较为重要的地方才会补充2.6版本之后的内容,望周知。
2:Vue中的MVVM
个人理解:
v-view就是页面
m-model就是数据
vm-viewModel是Vue
DOM Listeners就像计数那个例子一样,事件发生了他会监听到反应到页面上
Data Bindings 数据绑定,就是data里的数据,不用像js一样一大堆代码反应到页面上
视频中的讲解
View层:
视图层
在我们前端开发中,通常就是DOM层。
主要的作用是给用户展示各种信息。
Model层:
数据层
数据可能是我们固定的死数据,更多的是来自我们服务器,从网络上请求下来的数据。
在我们计数器的案例中,就是后面抽取出来的obj,当然,里面的数据可能没有这么简单。
VueModel层:
视图模型层
视图模型层是View和Model沟通的桥梁。
一方面它实现了Data Binding,也就是数据绑定,将Model的改变实时的反应到View中
另一方面它实现了DOM Listener,也就是DOM监听,当DOM发生一些事件(点击、滚动、touch等)时,可以监听到,并在需要的情况下改变对应的Data。
3:Vue的生命周期
根据生命周期实际中用到的应该是那些方法吧
上图方法
created()创建时执行(比如组件创建出来)
mounted() template挂载到dom上时执行
updated()发生刷新时执行
4:基础语法(插值语法)
mustache语法(双括号语法)
<h2>{{first + last}}</h2>
<h2>{{first + '' + last}}</h2>
<h2>{{first}} {{last}}</h2>和上面的结果一样的
<h2>{{count * 2}}</h2>
v-once指令
在我们不希望一个元素随界面随意的改变而改变时可以使用这个
该指令后面不需要跟任何表达式(比如之前的v-for后面是由跟表达式的)
该指令表示元素和组件(组件后面才会学习)只渲染一次,不会随着数据的改变而改变。
<h2 v-once>{{message}}</h2>
不会变,只会保持最开始的值
v-html指令
某些情况下,我们从服务器请求到的数据本身就是一个HTML代码
如果我们直接通过{{}}来输出,会将HTML代码也一起输出。
但是我们可能希望的是按照HTML格式进行解析,并且显示对应的内容。
如果我们希望解析出HTML展示,可以使用v-html指令,该指令后面往往会跟上一个string类型,会将string的html解析出来并且进行渲染
<h2 v-html="url"></h2>
后端传过来的是一个<a href/>的html语言字符串url,可以让vue自动解析
v-text指令
<h2 v-text="message"></h2>与<h2>{{message}}</h2>相同
但它不够灵活。建议使用mastache语法
v-pre指令
<h2 v-pre>{{message}}</h2>显示出来的就是{{message}}
v-cloak指令
<div id="app" v-cloak>{{message}}</div>
当vue还没初始化完成时先显示v-cloak的样式,初始化好vue自己就删了这个
属性,防止网络卡时没加载完vue显示{{message}}
v-bind指令
可以动态绑定a元素的href属性
可以动态绑定img元素的src属性
<img v-bind:src="imgUrl">
后端传回来的图片地址放在imgUrl中通过v-bind反应到页面上
语法糖写法:<img :src="imgUrl">
v-bind绑定class
<!--如果嫌太长可以把这个写到下面的方法里-->true还是false保留不保留class
<!--<h2 :class="{active: isActive, line: isLine}">{{message}}</h2>-->
<h2 :class="getClass()">{{message}}</h2>
:class="{isActive: index === currentIndex}
v-bind绑定style(对象语法)<h2 :style="{key(属性) :value(属性值)}"></h2>//value要加单引号,防止被vue解析成变量
<h2 :style="{fontSize :'50px'}">{{message}}</h2>支持驼峰也支持原来的
用法一:直接通过{}绑定一个类
<h2 :class="{'active': isActive}">Hello World</h2>
用法二:也可以通过判断,传入多个值
<h2 :class="{'active': isActive, 'line': isLine}">Hello World</h2>
用法三:和普通的类同时存在,并不冲突
注:如果isActive和isLine都为true,那么会有title/active/line三个类
<h2 class="title" :class="{'active': isActive, 'line': isLine}">Hello World</h2>
用法四:如果过于复杂,可以放在一个methods或者computed中
注:classes是一个计算属性
<h2 class="title" :class="classes">Hello World</h2>
v-bind绑定style(数组语法)
<h2 :style="[baseStyle,baseStyle1]">{{message}}</h2>
baseStyle: {background : "blue"},这个在data里
baseStyle1: {fontsize : "30px"}
用法一:直接通过{}绑定一个类
<h2 :class="['active']">Hello World</h2>
用法二:也可以传入多个值
<h2 :class=“[‘active’, 'line']">Hello World</h2>
用法三:和普通的类同时存在,并不冲突
注:会有title/active/line三个类
<h2 class="title" :class=“[‘active’, 'line']">Hello World</h2>
用法四:如果过于复杂,可以放在一个methods或者computed中
注:classes是一个计算属性
<h2 class="title" :class="classes">Hello World</h2>
案例:vue v-for出来的列表,点击当前,当前被点击的字体变颜色
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.active {
color: red;
}
</style>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="(m,item) in movies">
<a @click="btnClick(item)" :key="item" :class="{active:i===item}">{{item}}--{{m}}</a></li>
</ul>
</div>
<script>
//创建Vue实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
movies: ['海王', '星际穿越', '大话西游', '少年派', '盗梦空间'],
i: 0,
},
methods: {
btnClick: function (index) {
this.i = index;
},
}
});
</script>
</body>
</html>
v-bind也用于向另一个组件传递props值
v-for指令
v-for遍历数组中的对象属性
<tr v-for="(item, index) in books">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.date}}</td>
<td>{{item.price | showPrice}}</td>
<td>
<button @click="add(index)">+</button>
{{item.count}}
<button @click="sub(index)" :disabled="item.count <= 1">-</button>
</td>
<td>
<button @click="removeBook(index)">移除</button>
</td>
</tr>
v-for遍历数组
<ul>
<li v-for="(item ,index) in people" @click="change(index)" :class="{isActive: index === currentIndex}">{{index}}-{{item}}</li>
</ul>
</div>
<script>
const app = new Vue({
el : '#app',
data : {
message : "hello",
people: ["爷爷","奶奶","爸爸"],
currentIndex: 0
},
methods : {
change : function (index) {
this.currentIndex = index
},
}
})
v-for遍历对象
如果遍历的people是对象则显示的是value
<li v-for="(key, value) in people">{{key}}.{{value}}</li>对象key value都要可以这样
<li v-for="(key, value, index) in people">{{key}}.{{value}}-{{index}}</li>加上索引值(对象值)
<li v-for="item in people" :key="item">{{item}}</li>
最好绑定一个key,插入数据更有效率,key要唯一不变,所以不能用index
官方推荐我们在使用v-for时,给对应的元素或组件添加上一个:key属性。
为什么需要这个key属性呢(了解)?
是为了高效的更新虚拟DOM(设计到Vue的虚拟DOM的Diff算法)
条件判断 v-if、v-else-if、v-else、及条件渲染 v-show指令
<h2 v-if="score>90">优秀</h2>这些写太长,实际可以弄个函数再直接用那个语法
<h2 v-else-if="score>80">良好</h2>
<h2 v-else-if="score>60">及格</h2>
<h2 v-else>不及格</h2>根据条件满足显示那个
<h2 v-show="score>90">优秀</h2>
v-if条件为false时是整个元素都没有,不在dom中,
而v-show条件为false时,是因为有个行内样式display: none
导致不显示的当显示与隐藏切换频繁时用v-show,效率高,
只有不频繁时用v-if
事件监听 v-on指令
<button v-on:click="change">按钮</button>
语法糖写法:<button @click="change">click</button>
<button @click="btnClick">click</button>
当btnClick方法要传参数却这样写时,会自动将游览器产生的event事件对象
当做参数传过去
<button @click="btnClick(3,$event)">click</button>
如果传入多个参数时也要获得游览器产生的event事件对象可以用$event传
在某些情况下,我们拿到event的目的可能是进行一些事件处理。
Vue提供了修饰符来帮助我们方便的处理一些事件:
.stop - 调用 event.stopPropagation()。
.prevent - 调用 event.preventDefault()。
.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
.native - 监听组件根元素的原生事件。
.once - 只触发一次回调。
<div @click="dClick">
<button @click.stop="bClick">按钮</button>
</div>加上.stop防止也执行div上的事件(前端将这种称为冒泡)
<input type="submit" value="提交" @click.prevent="sClick">
加上.prevent防止默认的事件执行
<input type="text" @keyup.enter="keyup">
当敲回车键才会执行这个方法
.once这个事件只会执行一次
v-model指令
v-model表单元素和数据的双向绑定
v-model原理
v-model其实是一个语法糖,它的背后本质上是包含两个操作:
1.v-bind绑定一个value属性
2.v-on指令给当前元素绑定input事件
也就是说下面的代码:等同于下面的代码:
<input type="text" v-model="message">
等同于
<input type="text" v-bind:value="message"
v-on:input="message = $event.target.value">
v-model 单选框 复选框结合使用
v-model:radio
v-model:checkbox
复选框分为两种情况:单个勾选框和多个勾选框
单个勾选框:
v-model即为布尔值。
此时input的value并不影响v-model的值。
多个复选框:
当是多个复选框时,因为可以选中多个,所以对应的data中属性是一个数组。
当选中某一个时,就会将input的value添加到数组中。lable好处就是用户可以点击文字也会选中,一般一个label绑定一个input
v-model:select
单选:只能选中一个值。
v-model绑定的是一个值。
当我们选中option中的一个时,会将它对应的value赋值到mySelect中
多选:可以选中多个值。
v-model绑定的是一个数组。
当选中多个值时,就会将选中的option对应的value添加到数组mySelects中,加入数组好返回给服务器
修饰符
lazy修饰符:
默认情况下,v-model默认是在input事件中同步输入框的数据的。
也就是说,一旦有数据发生改变对应的data中的数据就会自动发生改变。
lazy修饰符可以让数据在失去焦点或者回车时才会更新:
number修饰符:
默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理。
但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理。
number修饰符可以让在输入框中输入的内容自动转成数字类型:
trim修饰符:
如果输入的内容首尾有很多空格,通常我们希望将其去除
trim修饰符可以过滤内容左右两边的空格
5:创建vue实例中传入的options对象中的选项
computed:
computed: {//计算属性,里面写的是方法,但方法名多起属性名,前面不加get
fullname : function () {
return this.message+','+this.name
}
<h2>{{fullname}}</h2>
computed只会调用一次保存缓存,methods调用几次执行几次没有缓存
本质是get方法,没有set方法,但也可以加进去set方法
computed定义的方法我们是以属性访问的形式调用的,{{computedTest}}
但是methods定义的方法,我们必须要加上()来调用,如{{methodTest()}
对于任何复杂逻辑,你都应当使用计算属性
computed依赖于data中的数据,只有在它的相关依赖数据发生改变时才会重新求值
6:组件化
组件的使用分成三个步骤:
创建组件构造器
注册组件
使用组件。
但感觉我的公司实际开发中要么已经直接生成好了,要么写不到这些
这里的步骤都代表什么含义呢?
1.Vue.extend():
调用Vue.extend()创建的是一个组件构造器。
通常在创建组件构造器时,传入template代表我们自定义组件的模板。
该模板就是在使用到组件的地方,要显示的HTML代码。
事实上,这种写法在Vue2.x的文档中几乎已经看不到了,它会直接使用下面我们会讲到的语法糖,但是在很多资料还是会提到这种方式,而且这种方式是学习后面方式的基础。
2.Vue.component():
调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称。
所以需要传递两个参数:1、注册组件的标签名 2、组件构造器
3.组件必须挂载在某个Vue实例下,否则它不会生效
注册组件语法糖组件自己的数据存放在组件对象的data属性中,这个data属性必须是一个函数,而且这个函数返回一个对象,对象内部保存着数据
为什么data在组件中必须是一个函数呢?
首先,如果不是一个函数,Vue直接就会报错。
其次,原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
全局组件和局部组件
当我们通过调用Vue.component()注册组件时,组件的注册是全局的
这意味着该组件可以在任意Vue示例下使用。
如果我们注册的组件是挂载在某个实例中, 那么就是一个局部组件
父组件和子组件
父子互相调用方法或者属性
父调用子(父函数中)
<cpn ref="aaa"></cpn>
this.$children[0].showMessage()所有子
this.$refs.aaa.showMessage()能找到ref=aaa的子,用的多
子访问父(开发基本用不到)$parent(耦合度太高)$root(根目录一般不放东西)
$children的缺陷:
通过$children访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值。
但是当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化。
有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用$refs
$refs的使用:
$refs和ref指令通常是一起使用的。
首先,我们通过ref给某一个子组件绑定一个特定的ID。
其次,通过this.$refs.ID就可以访问到该组件了。
父子组件之间通信
父传子通过props属性以及绑定
子传父以子通过$emit方法发送数据
父传子
<div id="app">//这边不支持驼峰,用了驼峰要用c-message="message"
<cpn :cmessage="message" :cpeople="people" :cpokemon="pokemon"></cpn>
</div>
<template id="cpnt">
<div>//这边可以驼峰
<h2>{{count}}</h2>
<h2>{{cmessage}}</h2>
<h2>{{cpokemon.moves}}</h2>
<ul>
<li v-for="item in cpeople">{{item}}</li>
</ul>
</template>
<script>
const cpn= Vue.component('cpn', {
template: '#cpnt',
data() {//数据是方法不能属性防止组件复用时属性交叉更改
return {
count: 0
}
},
//props: ['cmessage','cpeople']
props: {
cmessage: {
type: String,
required: true,
default: 'sdsdsd'
},
cpeople: {
type: Array,
required: true,
default: []
},
cpokemon: {
type: Object,
default: function () {
return {message: 'error'}
}
}
}
})
const app = new Vue({
el: '#app',
data: {
message: 'hello',
people: [123,321,12345],
pokemon: {
id: 1,
name: 'pikaque',
moves: 'quik stast'
}
},
components: {
cpn
}
})
子传父
<cpn @item-click="cpnClick"></cpn>
</div>
<template id="cpnt">
<div>
<button v-for="item in cata" @click="btnClick(item)">{{item.name}}</button>
</div>
</template>
const cpn= Vue.component('cpn', {
template: '#cpnt',
data() {
return {
cata: [
{id:1,name:"qwqwqwqw"},
{id:2,name:"asasasas"},
{id:3,name:"zxzxzxzx"},
{id:4,name:"cvcvcvcv"}
]
}
},
methods: {
btnClick(item) {
this.$emit('item-click',item)
}
}
const app = new Vue({
el: '#app',
data: {
message: 'hello'
},
components: {
cpn
},
methods: {
cpnClick(item){
console.log('cpnClick',item)
}
}
})
7:插槽slot
编译作用域
<div id="app">
<cpn ref="aaa" v-show="isshow"></cpn>
</div> isshow看vue实例的属性
<template id="cpnt">
<div>
<h2 v-show="isShow">weq</h2>
</div>
</template>看组件里的isShow
父组件模板的所有东西都会在父级作用域内编译;
子组件模板的所有东西都会在子级作用域内编译
即父组件的属性由父组件中的变量决定,子由子决定
作用域插槽:使用
在父组件使用我们的子组件时,从子组件中拿到数据:
我们通过获取到slotProps属性
在通过slotProps.data就可以获取到刚才我们传入的data了
<cpn>
<div slot-scope="slot">
<span>{{slot.data.join(' * ')}}</span>
</div>
</cpn>
</div>
<template id="cpnt">
<slot :data="people">
<ul>
<li v-for="item in people">{{item}}</li>
</ul>
</slot>
</template>
slot基本使用
cpn >
<h2 slot="center">dsfsfdsfds</h2>指定替代那个slot
</cpn>
<slot name="center"><span>222</span></slot>
<div v-if="!isActive"><slot name="item-icon"></slot></div>
<div v-else><slot name="item-icon-active"></slot></div>
<div :class="{active: isActive}"><slot name="item-text"></slot></div>
插槽最好外面都包装个div,防止直接替换的时候将指令也替换了,比如这里的:class="{active: isActive}直接写在slot中就会被替换
slot有三种类型
默认插槽 default
具名插槽 name
作用域插槽 v-slot
在子组件中:
插槽用标签来确定渲染的位置,里面放如果父组件没传内容时的后备内容。一个不带 name的 出口会带有隐含的名字“default”。
具名插槽用name属性来表示插槽的名字
作用域插槽在作用域上绑定属性来将子组件的信息传给父组件使用
8:其他
一:过滤器
<td>{{item.price | showPrice}}</td>
filters: {
showPrice(price){
return '$' + price.toFixed(2)
}
}
二:编译作用域
例子
来源:CSDN
作者:道格艾葛
链接:https://blog.csdn.net/qq_44904944/article/details/104052806