一、计算属性
1、案例引入
实现如下效果 当姓和名变化时 全名跟着变化
2、使用插值语法实现和methods实现
<body>
<div id="root">
姓<input v-model="firstName" type="text">
名<input v-model="lastName" type="text">
<!--使用插值语法实现-->
全名<span>{{firstName}}{{lastName}}</span>
<!--使用methods实现 vue当数据发生变化 模板重新渲染加载 数据也会重新更新-->
全名<span>{{fullName()}}</span>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
firstName:"",
lastName:""
},
methods:{
fullName(){
return this.firstName+this.lastName
}
}
})
</script>
</body>
上面案例插入语法缺点
3、计算属性定义
要用的属性不存在 要通过已有属性计算得出
4、原理
5、优点
和methods对象实现相比 有缓存机制 效率更高 调试方便
备注:计算属性最终出现在vm上 直接读取即可
<body>
<div id="root">
姓<input v-model="firstName" type="text">
名<input v-model="lastName" type="text">
全名<span>{{fullName}}</span>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
firstName:"",
lastName:""
},
methods:{
},
/*1、fullName属性通过函数计算出的新属性 fullName也在vm对象上
* 2、功能:当有人读取fullName时 get且返回值作为fullName值
* 3、会做缓存处理,初次读取和所依赖的数据发生变化时get调用*/
computed:{
fullName:{
get(){
return this.firstName+this.lastName
},
/*当新属性被修改时候调用*/
set(){
}
}
}
})
</script>
</body>
6、计算属性简写方式
确定计算属性只读不写时候才能简写
<body>
<div id="root">
姓<input v-model="firstName" type="text">
名<input v-model="lastName" type="text">
全名<span>{{fullName}}</span>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
firstName:"",
lastName:""
},
methods:{
},
computed:{
//简写方式 看着是个函数 实际是个属性
fullName(){
return this.firstName+this.lastName;
}
}
})
</script>
</body>
二、监视属性
1、定义
监视某一个属性的变化,只有当监视的属性存在才能监视
2、两种写法
<body>
<div id="root">
<span>天气{{info}}</span>
<button @click="changeWeather">切换</button>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
isHot:true
},
methods:{
changeWeather(){
this.isHot = !this.isHot
}
},
computed:{
info(){
return this.isHot ? '炎热':'凉爽'
}
},
/*第一种写法:创建实列就已经知道要监视哪个属性就用这种方法*/
watch:{
//不仅可以监听data中属性 也可以监视计算属性info
isHot:{
immediate:true,//初始化就调用一下handler
//当ishot发生变化时调用handler
handler(newValue,oldValue){
console.log(newValue,oldValue);
}
}
},
});
/*第二种写法:当用户行为发生变化时候才监视用这种*/
vm.$watch('isHot',{
immediate:true,
handler(newValue,oldValue){
console.log(newValue,oldValue);
}
})
</script>
</body>
3、深度监视
vue中的watch默认不监测对象内部值得变化(一层)
配置deep:true可以监测对象内部值得变化(多层)
<body>
<div id="root">
<span>{{num.a}}</span>
<button @click="num.a++">切换</button>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
num:{
a:1,
b:2
}
},
methods:{
},
watch:{
/*监视多级结构中某个属性变化*/
'num.a':{
handler(newValue,oldValue){
console.log(newValue,oldValue);
}
},
/*监视多级中所有属性变化*/
num: {
deep:true,
handler(newValue,oldValue){
console.log(newValue,oldValue);
}
}
},
});
</script>
</body>
备注:
vue自身是可以监测对象内部值得改变 但vue提供得watch默认不可以
使用watch需要根据数据结构得变化决定是否采用监视
4、简写
<body>
<div id="root">
<span>{{num.a}}</span>
<button @click="num.a++">切换</button>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
isHot:true
},
methods:{
},
watch:{
/*当不用配置deep和immediate时监视可以简写如下*/
isHot(newValue,oldValue){
console.log(newValue,oldValue)
}
}
});
/*当不用配置deep和immediate时监视可以简写如下*/
vm.$watch('isHot',function (newValue,oldValue) {
console.log(newValue,oldValue)
})
</script>
</body>
5、计算属性和监视属性对比
1、computed能完成的功能 watch都可以完成
2、watch能完成的功能 computed不一定能完成 例如watch可以进行异步操作
3、所有被vue管理的函数最好写成普通函数,别用箭头函数,这样this的指向才是vm
4、所有不被vue管理的函数(定时器函数、ajax回调函数、promise回调函数)最好携程箭头函数 这样this指向才是vm或者组件实列对象
三、样式绑定
1、通过class绑定样式(三种方式)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
<style>
.basic{
width: 200px;
height: 200px;
}
.active1{
background-color: rosybrown;
}
.active2{
border-radius: 20px;
}
.active3{
border-color: green;
background-color: red;
}
</style>
</head>
<body>
<div id="root">
<!--字符串写法:适用于样式的类名不确定需要动态指定-->
<div class="basic" :class="one"></div>
<!--数组写法:适用于要绑定的样式个数不确定 名字也不确定-->
<div class="basic" :class="two"></div>
<!--对象写法:适用于要绑定的样式个数确定 名字也确定 但要动态决定用不用-->
<div class="basic" :class="three"></div>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
one:'active1',
two:['active1','active2'],
three:{
active2:true,
active3:true
}
},
});
</script>
</body>
</html>
2、通过style绑定样式(2种)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
<style>
.basic{
width: 200px;
height: 200px;
}
.active1{
background-color: rosybrown;
}
.active2{
border-radius: 20px;
}
.active3{
border-color: green;
background-color: red;
}
</style>
</head>
<body>
<div id="root">
<!--对象写法-->
<div class="basic" :style="styleObj">222</div>
<!--数组写法-->
<div class="basic" :style="styleArr">333</div>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
one:'active1',
two:['active1','active2'],
styleObj:{
borderRadius:"20px",
backgroundColor:"red"
},
styleArr:[
{
borderRadius:"20px",
backgroundColor:"red"
},
{
fontSize:"20px",
padding:"20px"
}
]
},
});
</script>
</body>
</html>
四、条件渲染和列表渲染
1、条件渲染
1.1、v-show语法
1、底层使用的是display实现,仅仅时样式的移除
<body>
<div id="root">
<!--直接写表达式-->
<div v-show="true">{{name}}</div>
<!--通过属性控制-->
<div v-show="flag">{{name}}</div>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
name:'hello',
flag:true
},
});
</script>
</body>
1.2、v-if语法
1、v-if条件渲染时不展示dom的元素直接移除,而不是使用display隐藏
2、v-if可以和v-else-if、v-else一起使用 但要求结构不能被打断
3、template只能配置v-if使用(使用template不会破坏原来的元素结构)
html结构直接删掉
<body>
<div id="root">
<!--直接写表达式-->
<div v-show="true">{{name}}</div>
<!--通过属性控制-->
<div v-show="flag">{{name}}</div>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
name:'hello',
flag:true
},
});
</script>
</body>
1.3、比较
1. 如果需要频繁切换 v-show 较好 因为节点在只是隐藏了
2. 当条件不成立时, v-if 的所有子节点不会解析
2、列表渲染
2.1、v-for
v-for指令用于展示列表数据,语法:v-for="(item,index) in xxx" :key="yyy"
可以遍历数组、对象、字符串、指定次数
<body>
<div id="root">
<div>
<!--遍历数组-->
<h2 v-for="(item,index) in arr">{{item}}--{{item.id}}--{{item.name}}--{{index}}</h2>
<!--遍历对象-->
<h2 v-for="(value,key) in obj" >{{key}}--{{value}}</h2>
<!--遍历字符串-->
<h2 v-for="(item,index) in str" >{{item}}--{{index}}</h2>
<!--遍历指定次数-->
<h2 v-for="(number,index) of 5" >{{number}}--{{index}}</h2>
</div>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
arr:[
{
id:1,
name:'一'
},
{
id:2,
name:'二'
},
{
id:3,
name:'三'
}
],
obj:{
id:1,
age:12,
name:'张三',
sex:'男'
},
str:'hello',
},
});
</script>
</body>
2.2、key的作用和原理
3、列表过滤
案例截图,输入关键字模糊展示
3.1、使用监视属性实现
<body>
<div id="root">
<input v-model="keyWord">
<ul>
<li v-for="(item,index) in filPersons" :key="item.id">{{item.id}}-年龄{{item.age}}-{{item.name}}</li>
</ul>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
keyWord:'',
persons:[
{id:1, name:'张三',age:10},
{id:2, name:'李四',age:20},
{id:3, name:'王五',age:30}
],
filPersons:[]
},
watch:{
keyWord:{
immediate:true,
handler(val){
this.filPersons = this.persons.filter((p)=>{
/*indexOf(str)没有找到返回-1 找到返回下表位置,如果var是''即空字符串,
则返回0即每个字符串都包含空字符串在开头*/
return p.name.indexOf(val)!== -1;
})
}
}
}
});
</script>
</body>
3.2、使用计算属性实现
<body>
<div id="root">
<input v-model="keyWord">
<ul>
<li v-for="(item,index) in filPersons" :key="item.id">{{item.id}}-年龄{{item.age}}-{{item.name}}</li>
</ul>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
keyWord:'',
persons:[
{id:1, name:'张三',age:10},
{id:2, name:'李四',age:20},
{id:3, name:'王五',age:30}
],
},
computed:{
filPersons(){
return this.persons.filter((p)=>{
return p.name.indexOf(this.keyWord) !== -1
})
}
}
});
</script>
</body>
当计算属性和监视都能实现的时候优先选择计算属性
4、列表排序
<body>
<div id="root">
<input v-model="keyWord" type="text" placeholder="输入关键字查询">
<button @click="sortType = 2">年龄升序</button>
<button @click="sortType = 1">年龄降序</button>
<button @click="sortType = 0">原顺序</button>
<ul>
<li v-for="(item,index) in filPersons" :key="item.id">{{item.id}}-年龄{{item.age}}-{{item.name}}</li>
</ul>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
keyWord:'',
sortType:0,
persons:[
{id:1, name:'张三',age:10},
{id:2, name:'李四',age:20},
{id:3, name:'张二三',age:90},
{id:4, name:'王五',age:30}
],
},
computed:{
filPersons(){
const arr = this.persons.filter((p)=>{
return p.name.indexOf(this.keyWord) !== -1
});
//只要sort不是0 都是true
if(this.sortType){
//sort会改变原数组 filter不会改变原数组
arr.sort((pre,next)=>{
//sort降序用后一个元素减去前一个元素即可 升序用前一个元素减去后一个元素
return this.sortType === 1 ? next.age-pre.age : pre.age-next.age
});
}
return arr;
}
}
});
</script>
</body>
五、内置指令
1、v-text
向其所在的节点中渲染文档内容;会替换掉其他节点中的内容,但是插值语法表达式不会
2、v-html
向指定节点渲染包含html结构的内容
v-html有安全问题容易导致xss攻击,一定要在可信的内容使用v-html 不要在用户提交的内容
3、v-if
如果为 true, 当前标签才会输出到页面
4、v-else
如果为 false, 当前标签才会输出到页面
5、v-show
通过控制 display 样式来控制显示/隐藏
6、v-for
遍历数组/对象
7、v-on
绑定事件监听, 一般简写为@
8、v-bind
绑定解析表达式, 可以省略 v-bind
9、v-model
双向数据绑定
10、v-cloak
配合css解决由于网速慢是在页面展示{{xx}}问题
正常的html+js+css页面如下 是从头往下渲染的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--如果加载这个资源花了5s(浏览器设置网速模拟)
那么前5s是空白界面 然后从上而下加载页面 这个称为页面的阻塞 -->
<script src="http://xxx/js/vue.js"></script>
</head>
<body>
<div id="root">
<span>你好</span>
</div>
<script>
const vm = new Vue({
el:"#root",
data:{
name:'<h3>你好</h3>'
},
});
</script>
</body>
</html>
上面也是可以正常运行的
但是js位置也可以放在body中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
/*设置有v-clock属性的元素样式 v-clock在vue接管元素后自动消失*/
[v-clock]{
display: none;
}
</style>
</head>
<body>
<div id="root">
<span v-clock>{{name}}</span>
</div>
<script src="http://xxx/js/vue.js"></script>
</body>
<script>
const vm = new Vue({
el:"#root",
data:{
name:'<h3>你好</h3>'
},
});
</script>
</html>
11、v-once
初次动态渲染后就视为静态内容,以后的数据改变不会引起v-once所在结构的更新可以用于优化性能
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="root">
<span v-once>初始值{{num}}</span>
<span>当前值{{num}}</span>
<button @click="num++">num+1</button>
</div>
<script src="js/vue.js"></script>
</body>
<script>
const vm = new Vue({
el:"#root",
data:{
num:1
},
});
</script>
</html>
12、v-pre
v-pre不会编译当前元素
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="root">
<span>固定的没有指令的可以加v-pre优化性能</span>
<span v-pre>{{num}}有指令的不能加v-pre</span>
</div>
<script src="js/vue.js"></script>
</body>
<script>
const vm = new Vue({
el:"#root",
data:{
num:1
},
});
</script>
</html>
六、vue生命周期
- 初始化显示
- beforeCreate()
- created()
- beforeMount()
- mounted()
- 更新状态: this.xxx = value
- beforeUpdate()
- updated()
- 销毁 vue 实例: vm.$destory()
- beforeDestory()
- destoryed()
七、插件
作用
对vue增加作用,本质是一个{}对象,但是要求这个对象必须包含install(安装)方法,所以可以自定义插件
定义
export default {
/*vue会自动调用 可以带参数 这个Vue参数就是vm的缔造者即vue构造函数*/
install(Vue,x,y,z){
console.log(x,y,z)
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
//定义全局指令
Vue.directive('fbind',{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
})
//定义混入
Vue.mixin({
data() {
return {
x:100,
y:200
}
},
})
//给Vue原型上添加一个方法(vm和vc就都能用了)
Vue.prototype.hello = ()=>{alert('你好啊')}
}
}
引入并使用
main.js中引入并使用
import MyPlugins from "./MyPlugins";
Vue.use(MyPlugins,1,2,3)