目录
一、组件化
1.组件的基本概念
组件的本质:自定义标签
组件其实就是把我们的页面差分成一个个的小模块分开编写,增加开发效率,降低难度,复用性更高
2.组件的创建
在vue中组件使用.vue文件来进行表示 .vue文件叫做**单文件组件**
在创建组件的时候 我们是在components文件夹中进行创建的
2.1.vue文件基本页面内容
一个.vue文件中 有三个部分
template -------》写html
script -------》写js逻辑
style -------》写css
3.组件的分类
3.1全局组件---component
有的时候,一个组件在很多个地方都要被重复使用,那么默认情况下,我们使用局部组件的引用调用使用 每次在这样写很麻烦
全局组件:只需要配置一次main.js,那么就可以在当前项目的任意位置直接使用
(全局组件慎用:因为全组件可能会造成组件命名污染)
3.2局部组件---components
局部组件 只能在特定区域使用的组件 谁引用的 谁才能用
<template>
<div>
<!-- 3.使用 -->
<Bottombar></Bottombar>
<List></List>
<Slider></Slider>
</div>
</template>
<script>
// 1.引用 组件的名字要大写
import Bottombar from "./components/BottomBar/BottomBar.vue"
import List from "./components/ListCom/ListCom.vue"
import Slider from "./components/SliderCom/SliderCom.vue"
export default {
name: 'App',//命名空间 给这个组件起个名字
// 2.调用
components:{
// 名字:你引用的组件
Bottombar,List,Slider
}
}
</script>
<style lang="scss">
</style>
4. 组件样式隔离--scoped
使用scoped属性可以让 当前样式仅对当前组件生效,直接写在当前页面的<style scoped>
5.vue组件的data为什么是一个函数?
数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的`data`,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份`data`,就会造成一个变了全都会变的结果。
6.父子组件
组件和组件之间相互嵌套
6.1组件传值
**父组件的数据 子组件不能直接使用**
**子组件的数据 父组件也不能直接使用**
**组件与组件之间是一个完整地 独立地个体 他们之间的数据 默认是不能相互使用的**
6.2正向传值-父组件给子组件数据-props
**props是vue实例的一个属性 他的作用是用来让组件接受外部传递进来的数据**
语法:props:[接收参数1,接受参数2,........n]
写在data methods watch 的同级
6.3 props验证语法
在上面的例子中 大家会发现 我们给子组件传递任意数据类型都可以 但是如果我们想限制父组件给子组件传递的数据类型时候 那么就要使用props验证
props验证可以对传递给子组件的数据 进行约束(数据类型 默认值 等)
props验证 仅仅只在浏览器的控制台中打印出警告 但是不会对页面的展示造成影响(props验证只是给我们开发人员一个数据类型不匹配的 提示)
语法:
props:{
接受参数:{
type:数据类型,//验证类型
default:"默认值"
}
}
6.4逆向传值-子组件给父组件数据-$emit
$emit自定义事件
逆向传值默认是不被允许的 我们需要使用一些歪门邪道
**需要使用自定义事件来完成 $emit()**
注意:很多同学后期在被问到$emit是什么的时候 总会回到他是逆向传值 这个回答是错的 因为$emit是自定义事件 而逆向传值只是他能完成的一个小功能
二、路由
就是可以让我们完成一个SPA单页面应用,传统的页面在跳转切换的时候会造成页面加载白屏,这样一来用户体验非常的差,但是,我们通过spa应用,可以达到类似于原生app的切换效果,切换没有白屏,丝滑切换,用户体验更高
路由的本质:就是根据url的不同来渲染不同的组件页面**
1.路由基本创建
1.1脚手架自动创建
在创建项目的时候 选中router项[光标下移,按"空格"]即可在项目中集成路由
拿到路由项目之后怎么办?
1.删除掉[views]文件夹中的内容
2.删除掉[components]文件夹下的内容
3.在App.vue中删除内容,但是<router-view>[路由入口]千万千万不要删
1.2手工创建方式-一级路由创建
1.在views文件夹中创建对应的路由页面组件
2.配置路由:在router下index.js中进行配置
(2-1)先把你要使用的组件页面引用
(2-2)配置路由规则
3.在app.vue中设置router-view路由出口
2.路由导航
路由导航就是在页面中的一些链接通过点击之后完成页面的跳转
2.1标签的方式---声明式导航
不能使用a标签
router-link这个标签来完成页面之间的跳转 其中有一个to属性就是写你的路径
<div>
<router-link to="/home">首页</router-link>
<router-link to="/fenlei">分类</router-link>
<router-link to="/jingxi">惊喜</router-link>
<router-link to="/gouwuche">购物车</router-link>
<router-link to="/wode">我的</router-link>
</div>
动态类名:在当前路由页面下 vuerouter会给对应的声明式导航添加一个类名 通过这个类名可以设置当前的样式
2.2 js的方式---编程式导航
this.$router.push("/你要去的路径") push跳转的页面可以回退回来
<script>
export default {
methods:{
fun(){
this.$router.push("/jingxi")
}
}
}
</script>
this.$router.replace('/替换路径') replace是替换 跳转之后不能回退
this.$router.go()正数前进 负数后退
举例: this.$router.go(-1); // 路由回退
3.二级或者多级路由创建
二级路由或者多级路由在创建的时候 使用children关键字来进行规则的配置
1.路由页面创建 views文件夹
2.配置二级路由规则
(2-1)在router文件夹下的index.js中先引用二级路由页面
(2-2)配置路由规则 **必须在对应的一级路由规则中使用children关键字来进行配置**
{
path: '/home',//url路径
name: 'home',//给这个路由规则起个名字
component: Home, //引用组件
children:[//配置二级路由规则
{
path: '/era',
name: 'era',
component: Era
},
{
path: '/erc',
name: 'erc',
component: Erc
}
]
},
3.注意 **必须设置二级路由的路由出口 router-view (写在对应一级路由的页面中)**
3.1扩展---二级路由path设置
在上面的笔记中 会发现 我们在配置二级路由的时候 path路径为 /二级 在路由导航的时候 我们在to中直接就写/二级
{
path: '/home',//url路径
name: 'home',//给这个路由规则起个名字
component: Home, //引用组件
children:[//配置二级路由规则
{
path: '/era',
name: 'era',
component: Era
},
{
path: '/erc',
name: 'erc',
component: Erc
}
]
},
那么路由导航
<router-link to="/da">火锅</router-link> 这里直接/二级的path
注意 我们在写二级路由的时候 path 也可以写成 不加/的方式
在路由导航的时候 必须写成 /一级/二级
<router-link to="/meishi/da">火锅</router-link>
<router-link to="/meishi/db">甜品</router-link>
<router-link to="/meishi/dc">自助餐</router-link>
4.路由重定向---redirect
重(重新)定(定位)向(方向)
// 重定向
{
path:"/",
redirect:"/shouye"
}
5.404页面
就是给用户一个页面错误提示的作用
// 404页面必须在所有规则的最下面
{
path: '*',
name: 'no',
component: No
}
三、路由传参(动态路由匹配)
就是把数据从一个路由页面传递到另外一个路由页面中(新闻列表页面 用户点击之后 会跳转到新闻详情页 但是新闻详情页展示的内容应该是用点击的那一条新闻 所以如何把数据从一个页面传递到另外一个页面)
1.params方式
1.在需要接受数据的路由页面规则上 设置接受参数
{
path: '/all/:xiaoming', //设置接收参数
name: 'All',
component: All
},
2.发送
声明式
<router-link v-bind:to='{name:"All",params:{xiaoming:"我是phone传递的数据"}}'>点我使用声明式把数据传递给all页面</router-link>
编程式
在接收的页面使用 this.$route.params.xxx **注意单词**
2. query方式
1.发送:声明式 编程式
2.接收
在想使用数据的页面中 使用 this.$route.query.xxxx
3.总结
路由传参或者是动态路由匹配 他是vue-router 给我们提供的一种 把数据从一个路由页面传递到另外一个路由页面的技术
有两种方式
第一种params 这种方式在传递参数的时候共3步
(1)在接收的路由页面规则中配置接收参数
(2)发送 我是使用name作为跳转地址 使用params来设置发送参数
(3)接收 能想起来就说想不起来就不说 this.$route.params.xxxx
第二种方式query 他在传递数据的时候共两步 发送和接收 和params方式基本相同
唯独在发送数据的时候 他不但可以使用name作为跳转地址 还可以使用path
在接收的时候 语法也略有不同 他使用this.$route.query.xxxx
4.query方式与params方式传参区别
1.url展示形态
params方式 传递参数的时候相对安全一些 因为不显示传递的数据key
query方式 在传递的时候会显示数据key和val 相对来说没有parmas安全
2.刷新丢失
parmas方式 刷新会丢失 (上线之后)
query方式 刷新不会丢失
3.语法区别
5.$router与$route的区别
$router代表的是 路由对象 他所涉及的范围是全部项目页面
$route代表 当前路由页面对象
6.路由懒加载
在没有使用路由懒加载的时候 第一次加载会把所有的路由页面全部加载完 在显示页面 有的时候 用户的设备网络不好的时候 导致渲染时间过长 用户就会在第一次进入我们项目的时候 有白屏问题(用户体验不好)
异步组件方式
component: (resolve) => require(['你引用组件页面的路径'], resolve)
import导入方式
component: () => import('../views/About.vue')
四、路由钩子/路由守卫/导航守卫/路由卫士
在路由跳转的特定时期自动触发的一些函数 (这些钩子函数通常是在页面跳转的时候 对项目中的用户权限进行设置的)
1.全局守卫
所有页面在跳转的时候都会触发
1.1全局前置守卫---beforeEach()
在所有路由跳转之前 触发的钩子函数(此时路由还没有跳转完成)
2.全局后置守卫--- afterEach(()
所有路由跳转之后 触发的钩子函数 (此时已经进入到了跳转之后的新页面)
// to 去哪里
// from 从哪个路由来的
// next 下一步(必须要写 不写的话 就会卡在这个钩子中不想下进行了)
// 全局前置
router.beforeEach((to,from,next)=>{
console.log(to);
console.log(from);
if(to.path=="/phone"||to.path=="/shop"){
next()
}else{
alert("您没有登录请您登录后再访问")
next("/phone")
}
})
// 全局后置
router.afterEach((to,from)=>{
console.log("全局后置守卫")
})
export default router
2.路由独享守卫---beforeEnter
指定页面在跳转的时候触发
只会对一个路由规则生效(路由独享写在那个规则之上 就对哪一个生效)
// 路由独享守卫
beforeEnter(to,from,next){
console.log(to);
console.log(from);
next()
}
3.组件守卫(组件内)
仅仅对某些组件在路由跳转的时候生效
3.1进入组件时候---beforeRouteEnter
3.2离开组件的时候---beforeRouteLeave
// 进入组件
beforeRouteEnter(to,from,next){
console.log("我进来了")
console.log(to)
console.log(from)
next()
},
//离开组件
beforeRouteLeave(to,from,next){
console.log(to)
console.log(from)
if(confirm("您确定离开吗?")){
next()
}else{
next(false)
}
},
五、 vuex
vuex就是在vue中的统一状态(数据)管理工具
1.vuex创建
在创建的时候选择vuex(空格 回车)即可
2.vuex5大属性
2.1state---数据源
state属性的作用 就是在vuex中存放数据的 我们今后在vuex的所有数据都写在state中
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {//就是数据源 存放数据的地方
text:"我是字符串",
num:18,
bool:true,
arr:[1111,2222,3333],
obj:{
name:"xixi",
age:18
}
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
}
})
使用state的数据
因为vuex是统一状态管理 所以在项目下的任何数据 都可以直接使用state的数据
语法: this.$store.state.xxx
方式1 直接读取
<template>
<div class="about">
<h1>This is an about page---{{this.$store.state.text}}</h1>
</div>
</template>
方式2 使用计算属性间接读取
<template>
<div class="about">
<h1>This is an about page---{{this.$store.state.text}}</h1>
<h1>计算属性方式-- {{newbool}}</h1>
</div>
</template>
<script>
export default{
computed:{
newbool(){
return this.$store.state.bool
}
}
}
</script>
2.2module---模块
随着项目的体积逐渐增大 那么变量与今后的其他操纵就会在vuex的文件中 增多 导致这个文件中的内容原来越冗余 后期也几乎无法维护
为了避免上述情况 所以我们可以使用vuex的模块把内容进行拆分
1.在store文件夹下创建文件夹用来存放我们拆分的模块
2.创建模块文件 写入如下内容
可以直接从store下的index里面复制过来
let aboutm={
state: {//就是数据源 存放数据的地方
text:"我是字符串",
bool:true,
},
getters: {
},
mutations: {
},
actions: {
},
}
// 必须暴露
export default aboutm
3.在store下的index.js 中关联并使用我们创建的模块
import Vue from 'vue'
import Vuex from 'vuex'
// 1.引用模块
import homem from "./modules/homem.js"
import aboutm from "./modules/aboutm.js"
Vue.use(Vuex)
export default new Vuex.Store({
modules: {//2配置模块
homem,
aboutm
}
})
4,如果vuex被拆成了模块的话 那么我们要使用数据 必须使用
this.$store.state.模块名.xxxx
2.3mutations---修改数据
mutations的作用就是在vuex中修改state的,若想修改state的数据必须使用mutations来修改
**mutations是一个属性,这个属性中包含的是一个个修改的函数,mutaitons想使用,那么我们需要在组件中使用commit()来进行调用**
let aboutm={
state: {//就是数据源 存放数据的地方
text:"我是字符串",
bool:true,
},
getters: {
},
mutations: {
我是修改函数1(){
},
我是修改函数1(){
},
我是修改函数1(){
}
},
actions: {
},
}
// 必须暴露
export default aboutm
组件内使用commit调用
methods:{
add(){
// 调用vuex的修改
// this.$store.commit("你调用的mutations名字随便写",你想给mutations的数据 可选)
this.$store.commit("NUM_LIST_ADD_DATA")
},
del(){
this.$store.commit("NUM_LIST_DEL_DATA")
}
},
创建mutations中的内容
let homem={
state: {//就是数据源 存放数据的地方
num:666
},
getters: {
},
mutations: {
// state是一个形参可以随便写但是建议写state
// 这个形参的作用就是代表上面的数据源
NUM_LIST_ADD_DATA(state){
state.num++
},
NUM_LIST_DEL_DATA(state){
state.num--
},
},
actions: {
},
}
// 必须暴露
export default homem
mutations的payload(载荷)
在我们使用commit()的时候 第一个参数是你要调用的修改动作名 第二个参数是你要给mutations传递的数据
methods:{
add(){
// 调用vuex的修改
// this.$store.commit("你调用的mutations名字随便写",你想给mutations的数据 可选)
this.$store.commit("NUM_LIST_ADD_DATA",{inputval:this.inputval})
},
del(){
this.$store.commit("NUM_LIST_DEL_DATA",{inputval:this.inputval})
}
},
在mutations中可以读取这个第二个参数
mutations: {
// state是一个形参可以随便写但是建议写state
// 这个形参的作用就是代表上面的数据源
// 第二个参数就是payload (载荷) payload就是接受commit的第二个参数
NUM_LIST_ADD_DATA(state,payload){
state.num=state.num+payload.inputval
},
NUM_LIST_DEL_DATA(state,payload){
state.num=state.num-payload.inputval
},
},
2.4扩展---vuex数据修改刷新丢失
监听页面刷新,如果刷新,那么就把vuex的数据存储到本地存储中,然后当页面在此加载得的时候,把本地存储存的原始vuex的数据拿出来,替换当前的state数据
created () {
//判断是否有store这个本地存储的数据
if (sessionStorage.getItem("store") ) {
// 如果有 那么把vuex的数据替换 把当前的state 和上次刷新存储的state合并起来
this.$store.replaceState(Object.assign({}, this.$store.state,JSON.parse(sessionStorage.getItem("store"))))
sessionStorage.removeItem("store")
}
//在页面监听绑定一个beforeunload事件(页面刷新事件)
// 当页面刷新的时候使用本地存储存一个store的数据 把vuex的数据全部取出来 转成字符串存起来
window.addEventListener("beforeunload",()=>{
sessionStorage.setItem("store",JSON.stringify(this.$store.state))
})
}
2.5actions---异步触发器
actions是vuex的一个属性,他的作用就是在vuex中进行异步操作的触发(**很多同学后期总爱说actions是异步请求,但是要注意他不是异步请求,他是进行异步操纵的触发,异步请求只是它触发的众多异步操纵的其中一种**)
语法:要触发actions使用dispatch
(dispath触发actions进行异步触发,把请求来的数据通过commit交给mutations修改state,在页面读取展示)
1.在组件内使用dispatch()触发vuex的actions进行异步请求的发送
<template>
<div>
<button @click="fun()">点我使用vuex发送请求</button>
</div>
</template>
<script>
export default {
methods:{
fun(){
// 如果我们要使用vuex进行数据的发送
// this.$store.dispatch("你触发的actions的名字",{参数的key:参数的val})
this.$store.dispatch("AXIOS_CESHI",{url:"/data/user"})
}
}
}
</script>
<style>
</style>
2.需要在对应的actions创建你要触发的异步触发器
actions: {
// actions中也是一个个的方法 每个方法就是一个异步触发器
// context代表的就是vuex store对象
AXIOS_CESHI(context,payload){
// 在actions中就可以写请求
$http({
url:payload.url,
method:"get"
}).then((ok)=>{
console.log(ok.data)
})
}
},
3.把请求来的数据通过context.commit()触发修改
actions: {
// actions中也是一个个的方法 每个方法就是一个异步触发器
// context代表的就是vuex store对象
AXIOS_CESHI(context,payload){
// 在actions中就可以写请求
$http({
url:payload.url,
method:"get"
}).then((ok)=>{
console.log(ok.data)
context.commit("AXIOSDATA",{data:ok.data})//把请求来的数据通过commit触发mutations
})
}
},
4创建对应mutations修改state
mutations: {
AXIOSDATA(state,payload){
state.arr=payload.data
}
},
2.6getters---vuex的计算属性
vue的计算属性是computed,对data的数据进行依赖,处理之后返回新的计算之后的结果
vuex的getters也是计算属性,只是他和上面的computed最大的区别就是:
vuex的getters处理的数据可以在任何组件直接使用;
vue的computed,处理的数据只能在当前组件使用
getters: {
// state就是上面的数据源
newtext(state){
return state.text.toUpperCase()
}
},
**使用: this.$store.getters.xxx**
六、前后台交互
## 什么是前台什么是后台 什么是前端什么是后端?
前端指的是数据展示 后端指的是数据处理
1.分类
1.1原生ajax
1.2jqueryAjax
对上面的XHR对象进行了封装 方便使用
(1)下载jquery npm install --save jquery
(2)引用jquery
<template>
<div>
<h1>jqueryajax请求数据</h1>
</div>
</template>
<script>
// 引用jquery
import $ from "jquery"
export default {
}
</script>
<style>
</style>
(3)使用jquery
<template>
<div>
<h1>jqueryajax请求数据</h1>
<h1>{{data}}</h1>
</div>
</template>
<script>
// 引用jquery
import $ from "jquery"
export default {
data(){
return {
data:{}
}
},
mounted(){
$.ajax({
url:"/user_list/ceshidemo",
type:"GET",
dataType:"json",
success:(ok)=>{
console.log(ok)
this.data=ok
}
})
}
}
</script>
1.3axios
也是对XHR对象进行封装 当时它是使用符合当下的promise来进行的封装
(1)下载 cnpm install --save axios
(2)引用 import axios from "axios"
(3)使用
axios({
// 地址
url:"/movie/list/data_list",
// 有的同学写的时候写成methods了 有s也可以 原因是因为默认get 他不认识你带s的这个属性所以执行默认了
method:"get"
}).then((ok)=>{
console.log(ok.data.subjects)
// 把请求来的数据赋值给arr
this.arr=ok.data.subjects
}).catch((err)=>{
console.log(err)
})
1.4fetch
fetch和上面三个都不一样 因为他没有使用XHRajax对象 而是es最新的请求标准 但是既然是最新的 那么兼容性有很大问题
七、axios
axios 是目前最优秀的 HTTP 请求库之一,虽然 axios 已经封装的非常好了,我们可以直接拿过来用。但是在实际的项目中,我们可能还需要对 axios 在封装一下,以便我们更好的管理项目和各个接口。
1.axios常见api
1.1axios.request
该方法是axios项目的核心处理方法,实现用户自定义配置、应用拦截器、发送请求核心功能
1.2 get方式--params发送参数
// axios.get("请求地址",{params:{发送数据key:发送的val}}).then((ok)=>{
// // 成功回调
// }).catch((err)=>{
// // 失败回调
// })
axios.get("/api/userlist/get",{params:{name:"xixi"}}).then((ok)=>{
console.log(ok)
}).catch((err)=>{
console.log(err)
})
}
1.3post方式--data发送参数
// axios.post("请求地址",{data:{发送的key:发送的val}}).then((ok)=>{
// // 成功回调
// }).catch((err)=>{
// // 失败回调
// })
axios.post("/api/userlist/post",{data:{name:"xixi"}}).then((ok)=>{
console.log(ok)
}).catch((err)=>{
console.log(err)
})
**但是大家会发现后台接收不到我们发送的数据**
原因是因为:
在发送post的时候Content-type(**表示请求和响应中的媒体类型信息。它用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据**)常见有三种形式:
- Content-Type: **application/json** 就是给后台的数据是一个json对象
- Content-Type: **application/x-www-form-urlencoded** 表单数据编码为键值对,&分隔 如:name=java&age = 23
- Content-Type: **multipart/form-data** 通常文件上传
现在最主流的是**application/json**形式**axios默认就是这种方式** 就像上面我们写的post代码 直接把后该要的参数放到data中就可以了
但是有时候后端要求Content-Type必须以application/x-www-form-urlencoded形式,那么通过上面application/json传递的参数,后端是收不到的,我们必须对参数数据进行所谓的**序列化**处理才行,让它以普通表单形式(键值对)发送到后端,而不是json形式
1.4用qs模块来序列化参数
我们也能通过第三方依赖来序列化参数,就更加方便简洁,下载qs模块。
1.下载 npm install --save qs
2.引用 import qs from “qs”
3.在传递数据的时候使用qs序列化
// 引用qs
import qs from 'qs';
// 序列化数据
let key=qs.stringify({
name:"xixi"
})
// 传递
axios.post("/api/userlist/post",key).then((ok)=>{
console.log(ok)
}).catch((err)=>{
console.log(err)
})
}
1.5 delete put 等方式
delete 同get
axios.delete("/api/userlist/delete",{params:{name:"xixi"}}).then((ok)=>{
console.log(ok)
}).catch((err)=>{
console.log(err)
})
put方式 同post
import axios from "axios"
// 引用qs
import qs from 'qs';
// 序列化数据
let key=qs.stringify({
name:"xixi"
})
// 传递
axios.put("/api/userlist/put",key).then((ok)=>{
console.log(ok)
}).catch((err)=>{
console.log(err)
})
}