vue 第一天
vue 属于 mvvm ,是mvc的一种变体,M是moudle 数据层,V是视图层,VM就是把 M和 V建立起来通讯。
vue的理解,就是用new出来的 实例 vue来控制一块html 的渲染。
vue的使用,引入vue.js 再在script里实例化vue 就是new出来 如下:
//引入 vue.js
let vm = new Vue({
el:'xx'//这个xx表示你想要控制渲染的这块区域
data:{ //data 里面用来定义数据,并且是具有响应式的
a:123,
....
}
})
data里定义的数据使用方法:
1.maustache 语法,声明式渲染使用数据
{{变量名}}
data选项所接受的数据类型:
可以接受:String number arr obj bl undefind null 空字符 0
其中:undefined null 空 都在页面上渲染不出来
数据绑定:
v-text=‘变量名’ 可以渲染出变量里的值 以字符串的形式 等同于 {{变量名}},不识别html标签
v-html =‘变量名’ 非转义输出 会将html标签识别 并渲染到页面
v-bind:属性名=‘变量名’ 表示绑定上这个属性 这个属性就能使用data 的变量
简写为 :属性=‘变量名’
还有一种写法 把属性也当作data的数据变量 可以这么写, :[变量名]=‘变量名’
列表渲染:
v-for="(item,index) of arr" 可以循环渲染指定的次数
v-for="(val,key) of obj" 循环的是一个对象,那么 val 表示值,key 表示键,同样对象有几个成员就渲染几次
条件渲染:v-if =“条件” 满足条件才会显示
v-show =‘条件’ 满足条件才会显示
区别:if 是移除dom元素, show 是控制css样式 display
事件:
绑定事件写法: v-on:事件类型=‘函数名’
简写:@事件类型=“函数名”
函数书写位置:
实例出的vue里,添加options成员 methods 在这个成员里写方法
<button @click='show'></button>
let vm = new Vue({
methods:{
show(){
执行代码
}
}
})
双向绑定:
两种方式:v-model = ‘变量名’ vue里自带的系统指令,可以双向绑定上生产数据
:value = ‘变量名’ 这种就需要配合 事件来完成 例如如下
:value = data @input=checkIptvalue
let vm = new Vue({
methods:{
checkIptvalue(e){
return this.data = e.target.value
}
}
})
不响应式状况
1.例如 给对象添加了不存在的属性
2.修改了数组的长度
3.修改数组索引上的值
key的使用
一个良好的编程习惯在使用 v-for之后 给每一个标签加一个key
使用方法: :key=“item.id”
day2
模板表达式:可以在{{ }} 插值表达式里写一些语法 例如 if for 数组方法 字符串方法 但是不推荐
可以把这些写在,methods 这个成员里面
计算属性
data和computed 都是响应式的,
使用方法: 在vue里添加新的options 叫做 computed 在它里面可以对应的数据操作方法,计算数据然后才渲染,不过依赖data数据。
注意:跟函数的区别,函数每次都会调用,但是计算属性,会根据如果每次都会缓存,如果是同样的结果就直接拿出来使用,优化性能
不能直接改变计算属性的值,直接修改报错,要通过它内部带的get 和 set 方法
练习 小案例 增删改查
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
<body>
//这是我要控制渲染的这一块html
<div id="app">
<h2>增删改查</h2>
昵称<br>
//绑定上v-model
<input v-model="name" type="text"/>
<br>
内容<br>
<input v-model="content" type="text"/><br>
//提交的时候触发添加功能
<button @click="add" type="button">提交</button>
<div >
//绑定查询功能 search'计算属性
<input v-model="search" type="text"/><br>
<table >
<thead>
<tr>
<th>id</th>
<th>昵称</th>
<th>留言</th>
<th>操作</th>
</tr>
</thead>
<tbody>
//v-if 判断是否有内容渲染,如果没有 就出现这个暂无数据的提示
<tr v-if="list.length===0">
<td colspan="4">暂无数据</td>
</tr>
//这里根据数组里的内容来渲染
<tr v-for="(item,index) of cptList" :key="item.id">
<th>{{item.id}}</th>
<td>{{item.name}}</td>
<td>{{item.content}}</td>
<td>
//点击删除 触发删除功能 并且传入item的id 和下标
<button @click="del(item.id,index)" type="button">删除</button>
//点击更改,触发更改功能,并传入两个参数,item的id和下标
<button @click="check(item.id,index)" type="button">更改</button>
</td>
</tr>
</tbody>
//清空按钮是只有数组不为空的时候才出现
<tfoot v-show="list.length!==0">
<tr>
<td onscroll="4">
//点击清空,触发清空功能,把数组直接清空
<button @click="clear" type="button">清空</button>
</td>
</tr>
</tfoot>
</table>
<form v-show="bl">
//这个是用来更改数据的时候才出现的
<input v-model="changeContent" class="txt" type="text"/>
//点击确认更改,就会触发更改函数功能
<button @click="change()" type="button">确认更改</button>
</form>
</div>
</div>
<script type="text/javascript">
//实例化vue
let vm = new Vue({
el:'#app',//找到我需要渲染的目标区域
data:{ //data 表示moudle数据
name:'', //待会需要 name 来渲染昵称
content:'', //待会需要content 来渲染留言内容
list:[], //这个数组 代表我的数据 当我添加的时候 会向这个数组里面添加一个对象
search:'' ,//这个 表示我检索的内容
bl:false,//这个表示我需要更改时的开关
changeContent:''
},
methods:{ // metthods 表示 我定义的一系列 业务方法
add:function(){ //add 是我写的一个添加的方法
this.list.push({ // 当我一执行这个方法的时候 我就向我事先准备好的list 数组里添加一个对象
id:this.list.length+1, //对象成员id 就是list数组长度加一
name:this.name, //对象成员 name 表示 这个name 因为我们是data数据渲染上的 具有响应式,也就是拿的是同一个值
content:this.content //对象成员 content 表示 这个content 因为我们是data数据渲染上的 具有响应式,也就是拿的是同一个值
})
this.name=this.content=''//添加完毕后让 输入框为空
},
del:function(id,index){ //删除功能 点击的时候 del函数接收过来两个参数 id 和 index
this.list.splice(index,1) //使用数组的 splice 方法 删除传过来的索引值为 index对应 的那个数据
},
clear:function(){//清空 功能
this.list=[] //这里把list 数组直接清空 就等于删除所有的数据
},
check:function(id,index,content){ //改变数据
//改变布尔值让 更改框出现
this.bl=true
//并把当前的昵称name等于拿到的当前的这个的昵称
this.name = this.list[index].name
},
change(_id,index){//确认更改功能
//遍历一下这个数组
this.list.forEach((item,index)=>{
//如果当前的这个name 等于我定义好的name
//说明确实是我当前正在更改的这个值
if(item.name === vm.name){
//那么我就让当前的这个内容等于 我更改框的内容
this.list[index].content = vm.changeContent
}
})
//更改完毕 清空更改框的内容,name等于空,不让这个更改框显示
vm.changeContent=''
this.name=''
this.bl=false
}
},
computed:{ //computed 表示计算属性 会同步
cptList(){ //cptlist
let result = []; //定义一个数组,等会把符合条件的数据添加进来用于渲染
this.list.forEach((item,index)=>{ //遍历list 列表
//判断条件 当匹配到带有search变量的输入框内容和数组里的内容相等时 我就拿出来 push到result数组里
if(item.name.includes(this.search) || item.content.includes(this.search)){
result.push(item)
}
})
return result; //这个函数的返回值是一个 数组 是包含符合条件的数组
},
}
})
</script>
多vue实例控制html渲染
理解:就是创建多个vue实例来控制多块的html渲染
计算属性的get 和set
var vm = new Vue({
data: { a: 1 },
computed: {
// 仅读取
aDouble: function () {
return this.a * 2
},
// 读取和设置
aPlus: {
get: function () {
return this.a + 1
},
set: function (v) {
this.a = v - 1
}
}
}
})
vm.aPlus // => 2
vm.aPlus = 3
vm.a // => 2
vm.aDouble // => 4
template元素
当我们需要包裹一个或多个标签但又 不想影响页面结构的时候就可以使用template。
使用:就直接把template 当作标签使用就好 不会被页面渲染 但又可以在其身上使用vue的api
v-if v-else-if
可以实现多个逻辑性的判断是否显示,类似js中的 if else 语法
手动模拟 v-moudel
<!DOCTYPE html>
<html lang="zh">
<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></title>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.0.0-alpha1/css/bootstrap.min.css">
</head>
<body>
<div id="app">
<h3>vue实现v-model之外的双向绑定</h3>
<input type="text" :value="ipt" @input="changeIpt">
<h3>下拉</h3>
<div id="example-5">
<!-- 使用v-model 绑定上selected 这里的selected 受 options 的value值变动而变动 -->
<select v-model="selected">
<option disabled value="">请选择</option>
<!-- 这里遍历数组 渲染options -->
<option
v-for="(item,index) of list"
:key="item.id"
:value="item.value"
>{{item.text}}</option>
</select>
<span>Selected: {{ selected }}/{{cptValue}}</span>
</div>
</div>
<script type="text/javascript">
let vm = new Vue({
el:'#app',
data:{//元数据
ipt:'A',
selected:'bj',
list:[
{id:1,value:'sh',text:'上海'},
{id:2,value:'bj',text:'北京'},
{id:3,value:'sd',text:'山东'},
{id:4,value:'ah',text:'安徽'},
]
},
methods:{
changeIpt(ev){
this.ipt = ev.target.value
}
},
computed:{
cptValue(){
let result='';
// 遍历这个list数组 当当前这个value 等于selected的值时 就让定义的这个字符返回上面 并渲染上去
this.list.forEach((item,index)=>{
if(item.value===this.selected){
//给result 赋值 把遍历到的这个text 赋值给result
result = item.text
}
})
return result;
}
}
})
</script>
</body>
</html>
watch 侦听器
理解 : 当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。 比如很大段数据需要更新时可以使用
样式 和 类名:
类名: :class = { 名字 } 动态设置类名
样式: :style=“background:red”
:style=" ’ background:red ’ "
:style=“ { background:’red‘ ,’ border-width ‘ : ‘red’ } ”
:style =[{ background:red },{ color:’white‘ }]
系统指令
v-html 非转义输出,就是会把html标签解析出来
v-pre 可以跳过 这个元素 及其子元素的vue编译 跳过大量没有指令的节点 加快编译
v-once 只渲染一次
自定义指令
理解:就是自己定义的一个方法,自定义指令就是用来操作dom的
全局定义: Vue. directive(’color‘,(el,binging)=>{})
局部定义 :就是在vue实例里添加一个 directives ,在这个成员里书写函数方法
自定义指令的this 指向window
自定义指令的生命周期
bind(el,binding)=>{} 方法绑定的时候执行
inserted(el,binding)=>{ } 把带有指令的英语添加到dom里的时候执行
updata (el,binding)=>{ } 当数据层有数据更新的时候执行
componentUpdated(el,binding)=>{} 更新完成时执行
day3
过滤器:filter
使用方法:在你需要过滤的data 变量后 加一个 | 方法名 代码如下
<div>{{num | data }}</div>
let vm = new Vue({
data:{
num:2
},
filter:{
data(){
return this.num=this.num+5
}
}
})
数据交互
理解:现在是高级阶段 可以直接在项目依赖里下载一个 axios 插件
导入包就能使用,并且返回值是一个promise
post请求时:
携带参数时需要定义一个 params
params 需要实例化 let params = new URlSearchParams()
使用params.append( ’key‘:’val‘ ) 添加键值对
axios请求里 data携带的参数就可以直接写成 params
get请求时:
携带参数时,在axios 里添加一个params成员 在他里面写 键值对
params:{ a:1,b:,2 }
访问node 接口需要上传文件时
实例化一个fromData let fromdata = new FormData()
使用 fromdata.append(“key”,‘val’) 向里面添加键值对
捕获一下上传文件的 input
使用formdata.append( ‘files’,捕获文件id . files[0] ) // 单个文件
组件的生命周期
beroreCreate(){ } //组件创建前
created(){ } //组件创建后
beforeMound(){ } //组件挂载前
mounde(){ } //组件挂载后
beforeUpdate(){ } //当数据更新前
updated(){ } //数据更新后
beforeDestory(){ } //组件销毁前
destoryed(){ } //组件销毁后
组件
全局注册
Vue.component( ’组件名字‘ ,组件定义时候的名字 )
局部注册
在 vue 实例添加一个components成员在它里面可以注册
=> components:{ ’组件名子‘ :定义时的名字}
day4
css样式冲突
当多个组件在一起使用的时候难免 类名 或 id 名字相同,所以可以在每一组件模板里的style上加一个属性scoped,这个属性可以在每一个类名后加一个无谓的哈希值 以此来防止冲突
组件通讯 父向子传递
在父组件的使用子组件模板里 加在属性的位置 :msg = “msg”
子组件接收的时候,在props里 定义一个 成员 表示接收
父组件里
<child :msg='msg' />
子组件里
exprot default{
props:{
msg:{
type:类型,
default:默认值
}
}
}
组件通讯 子向父传递
在父组件的使用子组件模板里,加在属性的位置,写一个 自定义事件
在父组件里 的 methods 里写一个自定义事件触发后执行的函数
在子组件里找一个合适的时机传递给父组件
父组件里
<child2 @send="getdata"/>
methods:{
getdata(res){
res就是子组件传过来的值
}
}
子组件里
mounted(){ //组件挂载时传递给父组件
//通过 this.$emit 能拿到父组件传过来的方法
this.$emit('send',要传递的值)
}
路由
理解:在vue 里 就是 把准备好的模板,按照接口的形式指定渲染
配置路由:
=>import Vue from ‘vue’ 导入vue 因为路由需要安装到vue身上
=> import VueRouter from ’vue-router‘ 安装vue-router 插件
=>Vue.use(VueRouter) 把路由安装到vue身上
导入模板 例:import Home from ’ 模板的地址 ’
路由配置:let routes = [ { path:’ 接口名字 ‘,component:’ 指定的渲染模板 ’ } ]
路由实例化 let router = new VueRouter({
routes
})
向外导出:export default router
vue的跟实例里:
import router from '路由js 的地址'
let vm = new Vue({
router //把路由配置在vue里 让路由来管理组件的安装与卸载
})
day5
路由的拓展
路由守卫:全局守卫,独享守卫,组件守卫
全局首位就是在 router. js 里全局的位置,书写路由守卫,分为前置守卫,后置守卫
前置:router.beforeEach((to,from,next)=>{
//to:目标路由
//from:当前路由
//next()跳转 一定要调用
// 守卫业务
if(to.path=='/login' || to.path=='/reg' || to.path=='/register'){
//判断是不是登录了
//axios请求 携带 token
next()
}else{
next('/login');
}
})
后置:router.afterEach((to,from)=>{
// 全局后置守卫守卫业务
})
前置守卫就是还没有到达的哪一刻 执行的操作
路由独享守卫
独享守卫只有前置
路由独享就是在每一条路由配置里添加一个beforEnter:(to,from,next)=>{
}
例如:
// src/plugins/router.js
{
path: '/user',
component: User,
beforeEnter: (to,from,next)=>{ //路由独享守卫 前置
console.log('路由独享守卫');
if(Math.random()<.5){
next()
}else{
next('/login')
}
}
},
组件内部守卫
内部会带有3个钩子函数
beforeRouterEnter(to,from,next){
//这里不能获取组件实例,this
//因为当守卫执行之前,组件还没实例化
}
beforeRouteLeave(to,from,next){
//导航离开组件组件的对应路由时调用
//可以访问组件实例 this
}