Vue2.0学习
一 、VUE学习
简介
1.两个特性
-
数据驱动视图
数据的变化会导致视图的更新
-
双向数据绑定
数据源变化,视图也会更新
视图中的数据变化也会同步到数据源
Vue2使用Object.defineProperty()来监听数据的变化,实现数据驱动视图。
3.MVVM
-
什么是mvvm
model view viewmodel
model数据源
view当前页面的dom
viewmodel表示vue的实例可以实现model和view的双向绑定
基本使用
1.基本实例化
- 基本使用
1.绑定el和使用$mount()函数绑定作用一致
2.$mount()可以复用,而el在内部进行了绑定
<body>
<div id="app">{{ msg }}</div>
<!-- {{}}可以替换数据 -->
<script>
const vm = new Vue({
el: "#app", //控制哪个dom,
data: {
// 使用哪些数据
msg: "hellovue"
}
})
</script>
</body>
- 需要创建一个根div app熟悉这习惯
2.调试
dev tool,谷歌插件
3.指令
1.内容渲染指令
-
指令包含
1.v-text 替换为文本 2.{{}} 替换为文本 3.v-html 可以解析html标签并替换
-
基本使用
<body>
<div id="app">
<p v-text="msg2">嗨嗨</p>
<p >嗨嗨{{msg}}</p>
<p v-html="msg2">嗨嗨</p>
</div>
<!-- {{}}可以替换数据 -->
<script>
const vm = new Vue({
el: "#app", //控制哪个dom
data: {
// 使用哪些数据
msg2:"<h1>hello</h1>"
}
})
</script>
</body>
- 差异对比
1.v-text 和{{}}
将值替代为普通文本
{{}}不会覆盖原有文本
v-text会覆盖原有的文本
2.v-html会解析值的html标签信息
谨慎使用,用户可能用它来进行攻击
2.属性绑定指令
- 指令包含
v-bind:xxx="" 简写为 :
-
可以在插值和属性中使用
简单的js表达式,
调用函数的返回结果,
进行简单的字符串拼接等等
3.事件绑定指令
- 指令包含
v-on:xxx="" 简写为 @
-
函数的简写
1.可以省略function 2.可以使用箭头函数 methods:{ hello:function(){return 1;}, hello2(){alert(2)}, hello3:()=>alert(3) }
-
方法中访问当前对象
1.通过this访问当前对象 2.通过vm,实例化的对象名称访问当前对象 countadd1(){this.count+=1}, countadd2(){vm.count+=2;}
-
绑定事件的时候可以选择传递参数,函数定义的时候定义了参数,绑定的时候必须传递参数
-
不传参的情况下默认有个参数为event e
<button @click="countadd(9)">+9</button> countadd(n){this.count+=n},
-
源生事件绑定
源生的dom事件如onclick,oninput,onkeup 将on提前,v-on:click,v-on:input 或者@click,@input
-
事件参数event
1.如果没有传入参数,可以使用形参e接受事件目标 <button @click="countadd1">+1</button>
countadd1(e){console.log(e)},
2.如果传入了参数,需要接受源生事件dom参数,需要使用$event
<button @click="countadd1($event)">+1
countadd1(e){console.log(e)},
3.使用e.target获取事件的目标
+ 事件修饰符
内外层绑定了同名函数
.prevent组织标签默认行为,可以自定义事件
.stop阻止事件冒泡传播
.capture由当前向内冒泡反冒泡
.self只在当前元素触发事件
.once只触发一次
.passive不想阻止事件的默认行为
+ 按键修饰符
1.按键码
在按键的时候判断按键是否是某个特殊的键
替代原来的按键码,按键码被摈弃了,新的浏览器不在支持按键码
字母的话有数字组成特定的按键码
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
2.系统修饰符
在响应键盘和鼠标事件的时候必须同时按下系统按键才响应
.ctrl
.alt
.shift
.meta
.exact修饰符
需要精准按键,仅仅按下某系统按键的时候才触发
鼠标按键修饰符,鼠标左键,中键,右键的点击事件时候触发
.left
.right
.middle
4.双向绑定指令
-
v-model 在不操纵dom的情况下操纵表单数据
-
v-model内部会判断input的类型,或者从属于哪一种表单元素
-
input,textarea,button等使用v-model,可以操纵值和变量事件
-
value的绑定是单向绑定,数据源变化可以致使视图变化,视图变化不会导致数据变化
-
v-model
input radio,checked都可以 textarea 内容 select option
-
v-model的修饰符
.number 自动转换成数字 在字符串拼接时候数字化 .trim 自动去掉两边空白 .lazy 在change更新非input事件更新 比如输入、删除后失去焦点的时候
5.条件渲染指令
-
条件渲染指令v-if和v-show
-
v-if和v-show对比
v-if 默认为false,则不渲染,更省资源 v-show 频繁切换的时候,使用,避免重复渲染
-
v-if的相关if else
v-if v-else v-if v-else-if …… v-else
6.列表渲染指令
-
v-for的基本使用
-
遍历数组
1.遍历数组 <div v-for="it in list"> <p>{{it.id}}-{{it.name}}</p> </div> 2.额外用index获得元素的下标0开始 <div v-for="(it,index) in list"> <p>{{it.id}}-{{it.name}}-{{index+1}}</p> </div> data: { list:[{id:"#1",name:"张三"}, {id:"#2",name:"王五"}, {id:"#3",name:"赵四"},] },
-
遍历对象
可以通过v-for遍历对象 value表示值,name表示键,index表示下标 <div v-for="(value, name, index) in object"> {{ index }}. {{ name }}: {{ value }} </div>
-
v-for的时候可以访问父级区域的数据,根元素的Vue对象的data数据均可访问
-
官方推荐绑定:key
最好是绑定id,在.vue文件中使用v-for不绑定key报错,key只能是字符串或数字
index和key绑定没有意义,因为index和数据不强制绑定
-
数组变更的方法,会双向绑定渲染到v-for
push() pop() shift() unshift() splice() sort() reverse()
-
可以结合一些函数,和计算属性,对数据进行筛选等操作
filter()`、`concat()` 和 `slice()
-
列表渲染的小操作
1.循环渲染
4.过滤器 侦听器 计算属性
https://www.bilibili.com/video/BV1zq4y1p7ga?p=64
1.过滤器filter
-
基本使用和定义
1.使用 | 过滤符号 加过滤器名进行过滤 2.在filters(和methods同级)里定义过滤器函数 3.过滤器必须需要有返回值 4.过滤器会默认将|前的源数据作为参数,在过滤器函数中可以接受到 {{msg | daxie}} filters:{ daxie(val){ console.log("guolv"+val); return val; } },
-
私有过滤器和全局过滤器
1.基本概念 在vue实例下filters定义的是私有过滤器,不可以被其他vue实例使用 可以使用Vue.filter(name,function)定义注册一个全局过滤器给多个vue实例调用 2.构造 Vue.filter(name,function(val){})接受两个参数,第一个是过滤器的名称,第二个是过滤函数 //可以简写 3.作用域 全局过滤器和私有过滤器重名,根据作用域,就近原则调用私有过滤器
-
过滤器使用
1.可以使用过滤器,格式化一些内容,比如将时间格式化年元日时分秒 2.过滤器可以调用a|b|c,将a过滤b后再传入c再过滤 3.过滤器可以传参数,第一参数位置默认为传入数据源|前的内容 4.Vue3中摒弃了过滤器
2.侦听器watch
-
侦听器的作用
侦听数据的变化
-
基本属性和用法
1.在watch里面定义函数 2.函数名和数据的名称相同 3.有两个参数,一个新值,一个旧值 <div id="app"> <input type="text" v-model="msg"> </div> Vue.config.devtools = true const vm = new Vue({ el: "#app", //控制哪个dom data: { // 使用哪些数据 msg:"hello world" }, watch:{ msg(newval,oldval){ console.log(newval+":"+oldval); } }, })
-
对象形式的侦听器和immediate属性
1.如果需要创建一个刷新页面就处理的侦听器需要使用对象形式创建 2.将immediate属性设置为true就可以刷新页面就进入侦听状态 3.使用immediate,没更新,获得的数据为undefined const vm = new Vue({ el: "#app", //控制哪个dom data: { // 使用哪些数据 msg:"hello world" }, watch:{ msg:{ handler(newval,oldval){ console.log(newval+":"+oldval); console.log("启动了") }, immediate:true } }, })
-
deep深度监听
1.为了方便使用方法定义法,如果需要特殊需求,则使用对象定义法定义watch 2.侦听对象内部的数据变化,深度监听,需要使用对象定义法进行侦听,将对象定义法中的deep属性设置为true watch:{ msg:{ handler(newval,oldval){ console.log(newval); console.log(oldval) }, immediate:true, deep:true } },
3.计算属性computed
-
计算属性作用
1.本质上是一个属性,通过一系列的函数计算获得 2.可以作为vue对象的属性直接使用
5.axios数据请求
https://www.bilibili.com/video/BV1zq4y1p7ga?p=75
1.简介
1.用于发起网络请求的库
2.axios的返回值是一个Promise对象
3.后端接口程序返回了一个data是真实数据
4.axios除了真实数据之外套了壳,补充至config,data,headers,request,status,statusText
2.基本用法
axios({
method:"get",
url:"http://127.0.0.1:5000"
}).then((res)=>{console.log(res)})
3.跨域问题
1.不同源导致的跨域问题,端口,主机号不同均会导致跨域,限制数据请求的正常进行
2.可以前端vue设置代理解决
3.后端服务器(springboot注解,flask)设置代理
4.nginx反向代理解决
5.基于jsonp的内嵌script实现跨域
4.get和post请求
-
get使用params传递参数
axios({ method: "GET", url: "http://127.0.0.1:5000/getperson", params: { //get name: "张家辉", age:11, method:"GETmethod" }, }).then((res) => { console.log(res); this.person=res.data })
-
post使用data传递参数
axios({ method: "POST", url: "http://127.0.0.1:5000/getpersonPost", data: { //get name: "刘嘉良", age:12, method:"POSTmethod" }, }).then((res) => { console.log(res); this.person2=res.data })
5.async/await修饰axios
-
使用场景
必须要使用async修饰外层函数才可以用await await可以使得变量接受promise的返回值,这里即axios成功时的返回值 async f2(){ const data=await axios({ method: "POST", url: "http://127.0.0.1:5000/getpersonPost", data: { //get name: "刘嘉良", age:12, method:"POSTmethod" }, }) console.log(data) this.person3=data.data; }
6.axios.get, axios.post简写
-
语法
async f2() { const {data: per1 } = await axios.get("http://127.0.0.1:5000/getperson", { params: { //get name: "张三", age: 3, method: "GET" } }) this.person = per1; const {data: per2 } = await axios.post("http://127.0.0.1:5000/getpersonPost", { name: "张三", age: 3, method: "GET" }) this.person2=per2; }
6.组件
https://www.bilibili.com/video/BV1zq4y1p7ga?p=90
1.单文件组件Vue
1.单文件组件.vue文件
2.组成部分
template html模板 template不会被渲染,只是个虚拟的标签;
script js vue实例相关操作;
style css样式
3.组件中的data必须是一个函数,返回一个数据对象
data(){
return {
name:"hellovue",
hello:"你好"
}
}
4.组件中只有一个根元素如果没有需要写一个根元素
<template>
<div id="app">
<p>{{ name }}</p>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
name: "hellovue",
};
},
methods: { },
};
</script>
<style lang="less"></style>
2.私有局部组件的使用步骤
1.导入需要的组件
import Left from "./components/Left.vue";
2.使用components进行组件注册
3.以标签的形式使用组件
<template>
<div id="app">
<p>{{ name }}</p>
<p>{{ hello }}</p>
<Left></Left>//3.
</div>
</template>
<script>
import Left from "./components/Left.vue";//1.
export default {
name: "App",
data() {
return {
name: "hellovue",
};
},
components:{
Left,Right//2.
},
};
</script>
<style lang="less">
</style>
3.全局组件的注册
1.只需要注册一次全局的vue中都可以使用这个组件
2.步骤:在main.js中导入,使用vue.component方法注册
3.直接在各个vue组件中可以使用
import Quan from './components/Quan.vue'
Vue.component('myQuan',Quan);
4.组件名称
1.分为声明名称和注册名称
声明名称为组件指定的name属性
name属性首字母要大写
注册名称为局部注册或全局注册中导入并指定的名称
2.优先显示
优先展示声明的name属性的组件名称
如果没有name,则展示注册名称
5.组件的props
-
作用
提高组件的复用性
-
用法
1.父传子 <template> <div id="app" class="quandiv"> <p>{{ name }}</p> <p>{{init}}</p> </div> </template> <script> export default { name: "App", data() { return { name: "this is Quan", }; }, props:['init'], }; </script> <Quan init='9' ></Quan>总结 2.两种声明方式[]{} props: ['title', 'likes', 'isPublished', 'commentIds', 'author'] props: { title: String, likes: Number, isPublished: Boolean, commentIds: Array, author: Object, callback: Function, contactsPromise: Promise // or any other constructor } 3.普通绑定和v-bind <blog-post title="My journey with Vue"></blog-post> <blog-post v-bind:title="post.title"></blog-post> 4.绑定一个对象的所有属性 <blog-post v-bind="post"></blog-post>等效于 <blog-post v-bind:id="post.id" v-bind:title="post.title" ></blog-post> 6.不直接修改props props: ['initialCounter'], data: function () { return { counter: this.initialCounter } } 7.props{ init:{ default:0,type:number,required:true } }
-
小结
1.在子组件中定义和使用,在父组件中赋值,父传子,子组件可以操作该数据 2.可以使用[]和{}的方式定义,其中[]无绑定的限制,使用{}可以定义数据类型 3.可以使用普通绑定和v-bind或:的绑定方式,其中普通方式绑定的是字符串,v-bind绑定的是js表达式 4.可以绑定布尔,数字,字符串,数组,方法,对象等作为props的赋值 5.将一个对象的所有属性绑定,直接v-bind="post"进行赋值 6.props是"只读"的,不要直接修改修改props,在子组件中,赋值给data,修改和使用data而不修改props 7.用对象定义法{}定义其他属性 default 定义默认值 type 定义默认数据类型 required 必须传入的真假
6.组件之间的样式冲突
1.使用scoped解决组件之间的重名样式冲突,不影响其他组件的样式
<style lang="less" scoped>
.rightdiv{
background: green;
height: 200px;
width: 200px;
display: inline-block;
}
</style>
2.在父组件中修改子组件的样式,
修改第三方组件库中的组件样式,使用deep
vue组件中,在style设置为scoped时,里面写的样式对子组件是不生效的,此时可以使用 /deep/ 深度选择器。 (不使用scoped,/deep/不生效)
<style scoped lang="less">
.devlist-content .top /deep/ .el-input__inner {
background-color: transparent;
color:#fff;
border: 1px solid #404753;
}
/deep/ .el-table th {
background-color: rgb(36, 37, 42);
color: #fff;
}
</style>
7.vue生命周期
https://www.bilibili.com/video/BV1zq4y1p7ga?p=104
vue组件的显示过程
vue组件,依赖vue-template-compiler 模板编译器编译后显示
创建阶段:new vue=>beforeCreate=>beforeMount=>mounted=>
运行阶段:beforeUpdate=>updated=>
销毁阶段:beforeDestroy=>destroryed
new Vue:初始化事件和生命周期函数
1.create
beforeCreate:什么也做不了
(create) :初始化props,data,methods
created :此之后可以操作props,data,methods等数据,经常在此之后发起请求,处理数据了
判断是否有el
么有el使用$mount(el)的方式找到要操纵的元素
在内存中编译和创建html结构
2.mount
beforeMount :一般不会使用
(mount) :内存中的虚拟html dom被渲染
mounted :此之后操纵虚拟dom
3.update
beforeUpdate:数据发生了变化,但虚拟dom没有重新渲染
(update) :重新渲染dom
updated :dom被重渲染,可以操纵变化后的虚拟dom了
4.destroy
beforeDestroy :将要销毁,并未销毁
(destroy) :组件销毁,销毁侦听器,数据,子组件等
destroyed :组件销毁,生命周期结束
8.组件通信
https://www.bilibili.com/video/BV1zq4y1p7ga?p=110
1.父向子传值
使用props自定义属性进行传值
<Son :msg="message"></Son> 3
data(){
return {
message:'hello'
}
}
//son:
<template>
<p> {{msg}}</p>
</template>
props:['msg'] 1
1.子组件定义props
2.为了props使用安全,使用data接受props
3.父组件通过在子组件中绑定信息的形式给子组件传值
2.子向父传值
使用自定义事件
//=================父组件
<son @change="getcount"></son>
data(){
return{
msgfromson:''
}
},
methods:{
getcount(value){
this.msgfromson=value,
}
}
//=================子组件
data(){
return {
count=1,
}
},
methods:{
this.$emit('change',this.count);
}
1.父亲声明事件change
2.父亲绑定change的处理函数
3.子组件通过$emit发送数据到change事件响应
3.组件之间数据共享
1.使用eventbus事件总线进行通信
//================================
1.创建一个eventbus.js
2.发送方使用bus.$emit('事件名称',数据)
3.接收方bus.$on('事件名称',处理函数),通常在在created中接受
/=================================
import Vue from 'vue'
export default new Vue()
/=================================
<script>
import bus from './eventbus.js'
export default {
},
mounted(){
bus.$emit('share','嘿嘿来了啊')
},
};
</script>
/=================================
<script>
import bus from "./eventbus.js";
export default {
data() {
return {
frombro: "",
};
},
created() {
bus.$on("share", val=>{console.log(val);
console.log('bro:'+this.frombro)
this.frombro=val;
});
}
};
</script>
解决:vue中使用eventBus遇到数据不更新的问题
https://blog.csdn.net/u010007013/article/details/89515208
4.共享方案总结
1.父向子props自定义属性
2.子向父emit自定义事件
3.父子之间可以用v-model
4.兄弟eventbus
5.后代provide、inject
6.全局的数据共享vuex
9.ref操纵dom元素
https://www.bilibili.com/video/BV1zq4y1p7ga?p=118
1.ref的作用
为了简化操作dom的操作
2.ref获取当前vue中的dom
1.给组件取ref名称name
2.通过this.$refs.name获取元素
<template>
<div class="rootdiv">
<h1 ref="myh1">{{title}}</h1> //================1.
</div>
</template>
<script>
export default {
data() {
return {
title:'root组件'
};
},
mounted(){
console.log(this.$refs.myh1)//================2.
}
};
</script>
3.ref获取子组件的dom
1.父组件中给子组件ref名
2.可以操纵自组件中的数据,调用子组件中的方法
======================父组件
<count ref="refcount"></count>
=======================操纵
this.$refs.refcount.resetcount();//调用方法
this.$refs.refcount.count=0//获取数据
4.this.$nextTick
1.场景:数据更新,但是dom没有重新渲染,则可能无法通过ref操纵最新的dom元素
2.通过this.$nextTick(cb),等dom重新渲染之后再操作
3.不适合放在updated()中因为每次数据变化均会更新,可能数据更新,组件又更新了
this.$refs.refcount.count=0//有问题
this.$nextTick(()=>{this.$refs.refcount.count=0})//没问题
10.数组方法
1.foreach
循环,无法终止
2.some
某一个满足条件就可终止遍历,通过return true
3.every
判断数据每一个都满足某个条件
数组总结:https://www.cnblogs.com/chaoanquan/p/16253946.html
11.动态组件
https://www.bilibili.com/video/BV1zq4y1p7ga?p=146
1.动态组件简介
动态控制组件的显示和隐藏
2.基本使用
=================================
1.正常进行组件的注册,引用
2.使用component标签占位
3.指定component的is属性绑定组件
================================
<template>
<div id="app">
<component :is="'Right'"></component>
</div>
</template>
<script>
import Left from "./components/Left.vue";
import Right from "./components/Right.vue";
export default {
name: "App",
data() {return { }; },
components:{Left,Right },
};
</script>
3.keep-alive的使用
1.问题:component的切换过程中原组件会被销毁,替换的组件会被创建
2.解决方案:使用keep-alive标签进行包裹,内部的组件被隐藏了,不会被销毁
3.此外,keep-alive会带来另外的生命周期状态:
deactivated:被缓存
activated:被激活
<keep-alive>
<component :is="now"></component>
</keep-alive>
4.include,exclude
1.include:指定哪些被缓存
2.exclude:指定哪些不被缓存
3.不要同时使用这两个
<keep-alive include="Left,Right">
<component :is="now"></component>
</keep-alive>
12.插槽
https://www.bilibili.com/video/BV1zq4y1p7ga?p=151
1.插槽简介
组件中的某一块,未确定用户动态填充内容,使用slot占位,即插槽
子组件================================
<template >
<div id="app" class="leftdiv">
<slot></slot>
<p>{{ name }}</p>
</div>
</template>
父组件=================================
<Left>
<p>这是用户区域内容</p>
</Left>
2.v-slot
1.需要给每个插槽一个名字,否则vue会默认起名为default
2.内容会默认放到default
3.使用v-slot放到具体的某个插槽中
4.v-slot只能对组件complete和templete起作用
5.v-slot的简写形式为#
6.插槽中可以有默认内容
子组件==========================
<template >
<div id="app" class="leftdiv">
<slot name="slot1"></slot>
<p>{{ name }}</p>
<slot name="slot2">这是默认内容</slot>
</div>
</template>
父组件==========================
<Left>
<template v-slot:slot1>
<p>这是用户区域slot1内容</p>
</template>
<template #slot2>
<p>这是用户区域slot2内容</p>
</template>
</Left>
3.具名插槽
1.当有多个slot的时候,为了位置的准确,需要为每个slot起名
2.默认为default,如果没有指定插槽的名称,会填充到所有的名为default的插槽中
4.作用域插槽
1.在子组件中插槽中,可以定义一些自定义数据
2.#绑定具名后,可以使用一个形参对象接收所有自定义的数据
3.形参可以自定义,最好是scope,行业默认
子组件================================================
<template >
<div id="app" class="leftdiv">
<slot name="slot1"></slot>
<p>{{ name }}</p>
<slot name="slot2" msg="来自插槽2的默认信息">这是默认内容</slot> //定义msg
</div>
</template>
父组件=================================================
<template>
<div id="app">
<Left>
<template v-slot:slot1>
<p>这是用户区域slot1内容</p>
</template>
<template #slot2="scope"> //作用域插槽
<p>这是用户区域slot2内容</p>
<p>{{scope.msg}}</p> //使用信息msg
</template>
</Left>
</div>
</template>
4.可以动态绑定数据作用域插槽,也可以解构数据
子组件===============================
<template >
<div id="app" class="leftdiv">
<p>{{ name }}</p>
<slot name="slot2" msg="来自插槽2的msg" :user="userinfo">这是默认内容</slot>
</div>
</template>
data() {
return {
userinfo:{
name:'张三',
age:18
}
};
},
父组件=============================
<Left>
<template #slot2="{msg,user}">
<p>这是用户区域slot2内容</p>
<p>{{msg}}</p>
<p>{{user.name}}</p>
</template>
</Left>
13.自定义指令
https://www.bilibili.com/video/BV1zq4y1p7ga?p=160
1.简介
1.v-on,v-if,v-show等,类似的,可以自定义指令
2.有全局自定义指令,全局可用
私有自定义指令,当前组件可用
2.私有和全局自定义指令
1.私有
1.在每个组件的directives节点下可以定义自定义指令,进行一些功能
2.有bind组件绑定的时候触发,和update组件dom更新的时候触发
3.bind,update可以简写为对象的形式
<template>
<div id="app">
<p>name:{{ name }}</p>
<input type="button" value="切换" @click="change" /><br />
<Left>
<template #slot2="{msg,user}">
<p>这是用户区域slot2内容</p>
<p>{{msg}}</p>
<p>{{user.name}}</p>
<p v-name="color">空的</p>
</template>
</Left>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
name: "AppVue",
color:'blue'
};
},
directives:{
name:{
bind(el,binding){
el.style.background=binding.value;
console.log(binding.value)
},
update(){
el.style.background=binding.value;
console.log(binding.value)
}
}
//=============================简写
name(el,binding){
el.style.background=binding.value;
console.log(binding.value)
},
}
};
</script>
2.全局
1.使用main.js中使用Vue.directive定义指令
不简写========================
Vue.directive('color', {
bind(el, binding) {
el.style.color = binding.value;
},
update(el, binding) {
el.style.color = binding.value;
}
}
)
简写===============================
Vue.directive('color',
function (el, binding) {
el.style.color = binding.value;
},
)
X.VUE案例
案例1 列表渲染
-
循环渲染中的问题
1.input checkbox等表单元素使用v-model进行双向绑定 2.使用v-if v-else选择渲染动态切换的已启用已禁用的状态,考虑性能选择是否用v-show 3.在插值里写简单的js表达式,不可以写复杂语句,最终是一个值,不要有多条语句
-
动态生成checked
1.使用label 和 label中的for属性绑定input的id,可以扩大复选框的操作区域 2.使用v-for动态生成的时候会出现for绑定重名的情况,需要借用id动态生成for的绑定 label :for="'cb'+item.id"
-
删除操作
1.除了后台,可以使用list+数组filter的方法,传入id并进行判断,重新绑定,进行重渲染,实现删除的效果
-
添加操作
1.可以使用.prevent组织默认行为并写自己定义的行为 2.可以使用return ,终止函数的行为 3.表单的默认提交行为会刷新页面
二、 Vue-router
https://www.bilibili.com/video/BV1zq4y1p7ga?p=174
1.前端路由简介
1.什么是路由
Hash地址和组件的对应关系
2.什么是hash地址
url#符号及往后的东西叫hash地址会变化(锚链接会切换hash地址)
3.前端路由工作
用户进行相关操作,会监听到hash地址的变化,并把相关的组件渲染到页面中去
- 简易的前端路由的启发
https://www.bilibili.com/video/BV1zq4y1p7ga?p=177
前端路由模拟所需:
1.使用动态组件标签,动态切换组件实现页面切换
2.使用window.onhashchange监听hash地址的变化
3.使用local.hash读取hash值
2.Vue Router安装和导入
Vue提供的路由组件,安装步骤如下:
1.安装vue router包
2.创建路由模块
3.导入并挂载路由模块
4.声明路由链接和占位符
1.=================================
npm install vue-router@3.5.2 -s
2.=================================
1.创建src/router/index.js文件,这就是路由节点
2.在index.js文件中初始化:
在vue cli会自动生成/src/router/index.js
===============================
//1.导入包
import Vue from 'vue';
import VueRouter from 'vue-router'
//2.把vue router安装为插件
Vue.use(VueRouter)
//3.创建实例对象
const router=new VueRouter()
export default router
===================================
3.=====================================
//在main.js文件下挂载router节点
import router from './router/index.js'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router
}).$mount('#app')
4.================================
1.在需要展示的页面中对应位置写上占位符router-view,组件会渲染到该位置
=========================================
<template>
<div id="app">
<p>{{ name }}</p>
<p>{{ hello }}</p>
<a href="#/Left">Left </a>
<a href="#/Right">Right </a>
<router-view></router-view>
</div>
</template>
========================================
2.在router/index.js文件中声明路由关系,添加routes节点
=========================================
const router=new VueRouter({
routes:[
{path:'/left',component:Left},
{path:'/right',component:Right},
]
})
==========================================
Tips
1.可以使用router-view占位
2.可以使用router-link代替a链接
差异==================
1.使用to代替href
2.不用写#
使用==================
<a href="#/left">Left </a>
<router-link to="/left">这是router link left</router-link>
3.使用redirect重定向,可写一个默认路由,或者重定向一个路由
const router=new VueRouter({
routes:[
{path:'/',redirect:'/left'},
{path:'/left',component:Left},
{path:'/right',component:Right},
]
})
3.Vue Router的简单使用
https://www.bilibili.com/video/BV1zq4y1p7ga?p=180
4.嵌套路由
https://www.bilibili.com/video/BV1zq4y1p7ga?p=183
1.简介
通过路由实现组件的嵌套展示,组件的嵌套展示
2.实现
1.子组件中的节点声明
2.子组件的组件导入
3.嵌套路由的抒写
4.嵌套路由的默认路由,重定向
//===================================================
<template>
<div id="app" class="rightdiv">
<p>{{ name }}</p>
<router-link to="tap1">二级组件1</router-link> //1
<router-link to="tap2">二级组件2</router-link>
<router-view></router-view> //1
</div>
</template>
<script>
import Tap1 from './Tap1.vue' //2
import Tap2 from './Tap2.vue' //2
export default {
name: "Right",
data() {
return {
name: "this is right",
};
},
components:{Tap1,Tap2 } //2
};
</script>
//=======================================
//1.导入包
import Vue from 'vue';
import VueRouter from 'vue-router'
import Left from '@/components/Left.vue'
import Right from '@/components/Right.vue'
import Tap1 from '@/components/Tap1.vue'
import Tap2 from '@/components/Tap2.vue'
//2.把vue router安装为插件
Vue.use(VueRouter)
//3.创建实例对象
const router=new VueRouter({
routes:[
{path:'/',redirect:'/left'},
{path:'/left',component:Left},
//3==========================================
{ path:'/right',
component:Right,redirect:'/right/tap1',//4=======
children:[
{path:'tap1',component:Tap1},
{path:'tap2',component:Tap2}
]},
]
})
export default router
5.动态路由
https://www.bilibili.com/video/BV1zq4y1p7ga?p=186
1.简介
概念引入:
路径参数:hash路径中的参数,#后的叫路径参数,用this.$route.params
查询参数:?后的参数叫查询参数,用this.$route.query获取查询参数
2.基础使用
1.正常导入组件,和普通路由一样
2.父组件中路由自己写参数
3.路由中使用冒号定义动态参数项
4.获取参数项的值,有以下的方式:
1.通过子组件中this.$route.params.参数名 获取参数
2.路由中开启props设置为true,开启路由传参
//==============================2
<template>
<div id="app">
<p>{{ name }}</p>
<p>{{ hello }}</p>
<a href="#/left">Left </a>
<a href="#/right">Right </a>
<!-- ======================================动态路由2 -->
<router-link to="/space/1">洛基</router-link>
<router-link to="/space/2">雷神</router-link>
<router-link to="/space/3">海拉</router-link>
<router-view></router-view>
</div>
</template>
//==============================3
routes:[
{path:'/space/:id',component:Space},//3============
{path:'/',redirect:'/left'},
{path:'/left',component:Left},
{path:'/right',component:Right,redirect:'/right/tap1',children:[
{path:'tap1',component:Tap1},
{path:'tap2',component:Tap2}
]},
]
//=================================4.1
<template>
<div id="app" class="spacediv">
<p>{{ name }}</p>
<p>spaceid:{{this.$route.params.id}}</p>
<router-view></router-view>
</div>
</template>
//===========================4.2
//4.2.1子组件中开启props,并使用
<template>
<div id="app" class="spacediv">
<p>{{ name }}</p>
<p>spaceid:{{this.$route.params.id}}</p>
<p>props spaceid:{{id}}</p> //4.2.1===========
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "Space",
props:['id'], //4.2.1==============
data() {
return {
name: "this is space",
};
},
};
</script>
//=====================4.2.2 路由中开启props
{path:'/space/:id',component:Space,props:true},
3.tips
this.$route.path是不完整的路径 ,不包含查询参数
this.$route.fullPath包含查询参数
6.导航
1.编程式导航
-
概念
和普通的点击链接进行导航,这种叫声明式导航相区别,可以使用编程式导航
vue提供了this.$route系列的api叫编程式导航
-
常用api
1.$this.route.push('hash地址') 会增加一条历史记录 2.$this.route.replace('hash地址') 会替换当前的历史记录 3.$this.route.go(数值n) 前进n层,负数则后退 4.可以在行内html标签内使用编程式跳转,这时候this要省略,直接用$router //1============================= <input type="button" value="跳转到海姆达尔" @click="hai"/> hai(){this.$router.push('/space/4');} //2============================= <input type="button" value="跳转到海姆达尔" @click="hai"/> hai(){this.$router.replace('/space/4');} //3================================= this.$router.forward() this.$router.back() this.$router.go(n) n>0 前进n n=0 刷新 n<0 后退
2.导航守卫
https://www.bilibili.com/video/BV1zq4y1p7ga?p=190
简介
可以控制访问权限,进行一定的拦截
1.全局守卫
1.在router中的index.js中使用router.beforeEach进行全局守卫
2.to即将访问的路由信息
from即将离开的路由信息
next使用next()放行否则不可跳转
router.beforeEach((to,from,next)=>{
console.log(to);
console.log(from);
next();
})
2.next的放行方式
1.next() //放行
2.next('hash地址') //跳转到某一页面
3.next(false) //当前页面
4.登录验证案例
1.
三、Vuex
https://www.bilibili.com/video/BV1ea411A7GF/?spm_id_from=333.788.recommend_more_video.4
1.简介
为了方便大型项目的数据共享,减少数据父子关系对数据共享的限制
将store作为中间站,不再进行复杂的数据传递
vuex中的数据是响应式的,可以实现数据和视图的响应
2.安装
注意vue和vuex的版本是相互对应的!
1.npm install vuex -s安装
2.src/store/store.js创建文件
3.初始化2.中的文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
4.挂载到main.js中
import store from './store/store.js'
Vue.config.productionTip = false
new Vue({
store,
render: h => h(App),
}).$mount('#app')
3.核心概念
1.State
https://www.bilibili.com/video/BV1ea411A7GF?p=5
state vuex的基础数据
1.在store.js中进行数据定义
2.通过两种方式使用使用mapState展开到computed中
1.数据定义=============================
export default new Vuex.Store({
state: {
count: 0
},
})
2.数据使用============================
2.1this.$store.state.count=====================
console.log(this.$store.state.count);
2.2 mapState 结合计算属性
import { mapState } from 'vuex';//js中导入
computed:{
...mapState(['count'])//计算属性中展开,这样就可以直接使用count
},
2.Mutation
https://www.bilibili.com/video/BV1ea411A7GF?p=7
不要直接修改state中的数据,不利于数据维护
不要在mutation中执行异步任务
vuex中使用mutation来修改state中的数据
1.有参数的mutation
2.无参数的mutation
3.使用mapmutations的方式使用mutation,在methods中展开
1.无参数的mutation========================
//store.js定义
mutations: {
add (state) {
state.count++
},
}
//组件中使用
handleadd(){
this.$store.commit('add');
}
2.有参数的mutation=======================
//store.js定义
mutations: {
minus(state,name){
state.count-=name;
}
}
//组件中使用
handleminus(){
this.$store.commit('minus',2)
}
3.mapmutations==================
组件中的methods中展开
methods: {
...mapMutations(['minus']),
handleminus(){
this.minus(2);
}
},
3.Action
https://www.bilibili.com/video/BV1ea411A7GF?p=10
mutation只能执行同步任务,需要在action中进行异步任务
action中是间接执行mutation中的函数
1.定义mutation(第一个参数必要,第二个可以自定义参数)
2.使用this.$store.disparch触发mutation(可以自定义参数,类比mutation)
3.触发的另外方式mapActions,在methods中展开
1.=================mutation定义
mutations: {
add (state) {
state.count++
},
},
actions:{
addasync(context,name){
setTimeout(() => {
context.commit('add',name);
}, 1000);
}
}
2.触发mutation=============================
this.$store.dispatch('addasync',3);
3.mapActions==================
import { mapState,mapActions } from 'vuex';
methods: {
...mapActions(['addasync']),
handleadd(){
// this.$store.commit('add');
// this.$store.dispatch('addasync',3);
this.addasync(4);
}
},
4.Getter
https://www.bilibili.com/video/BV1ea411A7GF?p=13
类似于state的计算属性
1.getter的定义和使用
2.使用mapGetters展开到计算属性,然后当做计算属性一样用
1.getter的定义和使用==================
state: {
count: 0
},
getters:{
getcount:(state)=>state.count,
},
//使用:
this.$store.getters.getcount
2.mapGetters======================
computed:{
...mapState(['count']),
},
<p>countget:{{getcount}}</p>
5.Module
可以将store中分块
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
4.WebStorage穿插
1.各种存储的区别
cookie session 参与网络通信,存储于本地 H4的策略
sessionStorage cookieStorage 都是web本地存储,不参与网络通信 H5的策略
cookie 存储在客户端 webstorage用以替代cookie,只能存键值对
session 存储在服务器端,用户和服务器长时间没有会话就失效,可以存对象
cookie有一些限制,所以H5改成webstorage:
1.存储大小 只能20个
2.需要在客户端服务器中传输,消耗资源
3.安全性问题
localstorage 存储在本地,永久有效
**sessionstorage **存储在本地,关闭页面就失效
2.使用方式
2.1 cookie session
2.2 localstorage sessionstorage
只能存储字符串,如果要存对象需要使用JSON.stringify();JSON.parse();进行转换
key(n) | 该方法用于返回存储对象中第n个key的名称 |
---|---|
setItem(key, value) | 该方法接收一个键名和值作为参数,将会把键值对添加到存储中,如果键名存在,则更新其对应的值 |
getItem(key) | 该方法接收一个键名作为参数,返回键名对应的值 |
removeItem(key) | 该方法删除键名为key的存储内容 |
clear() | 该方法清空所有存储内容 |
length | 该属性返回Storage存储对象中包含的item的数量 |
四、Vue-cli
1.创建、配置、启动
1.创建过程
1.使用vue create xxx创建项目尽量不要中文
2.选项:最后一个手动
yushe ([Vue 2] babel, eslint)
Default ([Vue 2] babel, eslint)
Default (Vue 3 Preview) ([Vue 3] babel, eslint)
Manually select features
3.手动选择
? Please pick a preset: Manually select features
? Check the features needed for your project:
(*) Choose Vue version
(*) Babel
( ) TypeScript
( ) Progressive Web App (PWA) Support
( ) Router
( ) Vuex
(*) CSS Pre-processors
( ) Linter / Formatter
( ) Unit Testing
( ) E2E Testing
4.配置信息放在哪儿,选独立的配置值
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
> In dedicated config files
In package.json
5.? Save this as a preset for future projects? (y/N)选择预设
2.项目启动
$ cd 目录
$ npm run serve开发
$ npm run build上线
ctrl+c停止
2.目录文件介绍
1.public中:
默认一个图标
index.html启动页面,vue组件会被注入到这之中形成页面
2.src:
源代码目录
assets 静态资源,如图片等
components 封装的组件
main.js 项目的入口文件
app.vue 根组件,如果需要修改
项目的运行过程
1.同过main.js将app.vue渲染到html
2.app.vue中内嵌了其他封装好的组件
3.main.js行为:将app.vue替换index中的app div
new Vue({
render: h => h(App),
}).$mount('#app')
$mount的作用,指定操纵的元素效果相当于指定vue对象的el
Webpack
1.基础学习
1.基本使用
创建一个隔行变色的效果
1.新建目录,在目录下按cmd进入命令行,npm init -y命令,初始化配置文件package.json,
2.目录中新建src文件夹,新建一个index.html,index.js
3.初始化页面结构,创建无序列表
4.安装jquery,使用npm install jQuery -S,会安装到dependencies中
5.使用ES6导入jquery
2.安装webpack
-
后缀介绍
-S --save开发阶段和上线都要用
-D --save-dev开发阶段使用仅仅
npmjs.com中查询使用哪个后缀
-
安装命令
使用 npm install webpack@5.42.1 webpack-cli@4.7.2 -D
-
在项目中配置webpack
1.项目根目录中创建webpack.config.js,初始化
module.exports={ //有development和production mode:'development' }
2.package.json scripts节点下新建dev可以使用npm run dev
"scripts": { "dev":"webpack" },
-
导出后装包
1.除了模块其他可以复制 2.复制完了后使用npm i装包
Now
https://www.bilibili.com/video/BV1zq4y1p7ga?p=177
Tips
1.模块化导入的时候,当不指定文档名会默认导入文件夹中的index.js文件