元素作为承载分发内容的出口。内容定义在父组件中,子组件可以拿去渲染。
slot=“插槽名”
或者 v-slot:插槽名
指定插入的插槽名,
使用 name 指定操作的名称slot-scope="传入的数据对象"
或者 v-slot:插槽名=“传入的数据对象”
指令的指令值。<template>
<!-- 数据驱动 -->
<div id="app">
<!-- 2.5.xxxx -->
<v-child :visible="isShow" :list="list">
<!--匿名插槽 建议插槽内容写在template中 -->
<template>
<button @click="submit">确定</button>
</template>
<!--具名插槽 2.5.x,slot="插槽名称" -->
<template slot="footer" >
<div>
底部内容
</div>
</template>
<!--
作用域插槽:
slot-scope="自定义名称"
自定义名称:包含子组件传入到父组件的数据对象
-->
<template slot="box" slot-scope="scoped">
<span>
<button @click="edit(scoped.index)">编辑</button>
<button @click="del(scoped.index)">删除 </button>
</span>
</template>
</v-child>
<!-- 2.6.xxxx -->
<v-child :visible="isShow" :list="list">
<!-- 建议插槽内容写在template中,匿名插槽的内容 -->
<template>
<b @click="isShow=false">bbbb</b>
</template>
<!--具名插槽: v-slot:插槽名称 -->
<template v-slot:footer>
<div>
底部内容
</div>
</template>
<!--
v-slot:插槽名称 = "包含子组件传入到父组件的数据对象"
-->
<template v-slot:box="scoped">
<span>
<button>编辑</button>
<button @click="del(scoped.index)">删除</button>
</span>
</template>
</v-child>
</div>
</template>
<script>
import vChild from "./components/child";
export default {
components: {
vChild
},
data(){
return{
isShow:true,
list:[{
title:"title1"
},{
title:"title2"
}]
}
},
methods:{
submit(){
this.isShow=false
},
del(i){
this.list.splice(i,1)
},
edit(i){
}
}
};
</script>
<template>
<div class="list" v-show="visible">
<h2>标题</h2>
<!-- 匿名插槽 -->
<slot></slot>
<div>其他内容</div>
<ul>
<li v-for="(item,index) in list" :key="index">
<span>{
{
item.title}}</span>
<!-- 以自定义属性形式向父组件传入数据 -->
<slot name="box" :index="index" :item="item"></slot>
</li>
</ul>
<!-- name = 具名插槽的名称 -->
<slot name="footer"></slot>
</div>
</template>
<script>
export default {
props:{
visible:Boolean,
list:Array
}
};
</script>
import Vue from 'vue'
import Router from 'vue-router'
// 引入路由组件,@->src目录的绝对地址
import Index from '@/pages/Index'
import About from "@/pages/about"
// 安装路由
Vue.use(Router)
let router = new Router({
// 定义 路由
routes: [
// 每一个对象就是一个路由
{
path: '/',//路由路径
component: Index,//该路由对应的渲染组件
},{
path:"/about",
component:About
}
]
})
export default router
<ul>
<li>
<!-- <router-link to="/">首页</router-link> -->
<router-link :to="{path:'/'}" activeClass="act" exact>首页</router-link>
</li>
<li>
<router-link to="/about" activeClass="act">about</router-link>
</li>
</ul>
this.$router.push/replace/go
methods:{
// 使用$router进行编程式导航
toIndex(){
// console.log(this.$router)
// 跳转到首页
this.$router.push("/")
},
toAbout(){
// push:可以回退回来
// this.$router.push("/about");
// replace:不能回退
this.$router.replace("/about");
// this.$router.replace({
path:"/about"});
},
back(){
// 前进(参数是正数)或者后退(参数是负数)若干个页面
this.$router.go(-1)
}
}
{
// * 任意其他地址
path:"*",
component:NotFound
}
{
path:"*",
redirect:"/",// redirect:重定向地址
}
{
// 命名路由,给路由取名字
path: '/menu',
name: "menu",
component: Menu
}
:
后面是动态路由参数的名称 {
path:"/goods/:goodsid",
component:Goods
}
// $route:当前路由对象,包含路由信息(动态路由参数)
let goodsid = this.$route.params.goodsid;
$route和$router
的区别####$router
:全局路由器,一般用来导航$route
:当前路由对象,包含路由信息(动态路由参数params)动态路由组件复用,页面不更新问题
export default {
data() {
return {
info: {
}
};
},
// 动态路由组件被复用(/goods/123->/goods/456),组件被复用,而不是销毁重建
mounted() {
this.getDetail();
},
// 监听 $router的辩护,重新获取数据
watch: {
$route() {
this.getDetail();
}
},
methods: {
getDetail() {
// 获取动态路由参数
// $route:当前路由对象,包含路由信息(动态路由参数)
let goodsid = this.$route.params.goodsid;
console.log(goodsid);
$.get(`/static/data/good${
goodsid}.json`, res => {
console.log(res);
this.info = res;
});
}
}
};
// 对象形式传入动态路由参数,必须使用命名路由
this.$router.push({
name:"goods",params:{
goodsid:456}})
<li><router-link to="/menu?a=1">/menu?a=1</router-link></li>
<li><router-link to="/menu?a=2">/menu?a=2</router-link></li>
console.log(this.$route.query.a)
{
path: '/',
components: {
/*
key:router-view 的name值
value:对应的渲染组件
*/
index:Index,
menu:Menu
},
}
<router-view name="index" />
<router-view name="menu" />
嵌套路由
{
path: '/',
component: Layout,
// 定义嵌套路由
children: [{
path: "index",//一级路由path + 当前的path (不加 /)
component: Index
}, {
path: "menu",
component: Menu
},{
path:"*",
redirect:"/index"
}]
}
<!-- Layout 下面的二级路由 -->
<router-view></router-view>
{
path: "/login",
component: ()=>(import("@/pages/Login"))
},
children: [{
path: "index",//一级路由path + 当前的path (不加 /)
// 有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。
component: ()=>(import(/* webpackChunkName: "group-a" */ "@/pages/Index"))
}, {
path: "menu",
component: ()=>(import(/* webpackChunkName: "group-a" */ "@/pages/Menu"))
},{
path:"*",
redirect:"/index"
}]
// 全局前置守卫(前置:导航被确认前)
/**
* to:即将进入的路由
* from:即将离开的路由
* next:不加参数 执行下一个守卫,一次导航确保执行next
* 地址参数:终止本次导航,开启一轮新导航
* false: 取消本次导航
*/
router.beforeEach((to,from,next)=>{
console.log(to,from)
let isLogin = true;
// document.title = to.meta.title;
// 已登陆
if(isLogin){
// console.log(to.path)
if(to.path=="/login"){
next(false);
}else{
next();
}
}else{
// 未登录
// console.log("1")
//
if(to.path=="/login"){
next();
}else{
next("/login")
}
}
})
//所有组件内守卫和异步路由组件被解析之后
router.beforeResolve((to,from,next)=>{
console.log("beforeResolve");
next();
})
// 导航被确认后的守卫,没有next
router.afterEach((to,from)=>{
console.log("afterEach")
})
{
path: "/login",
component: ()=>(import( "@/pages/Login")),
meta:{
title:"登陆页"
},
beforeEnter(to,from,next){
console.log("login 专享")
next();
}
},
beforeRouteEnter(to, from, next) {
// 这个钩子中访问不到组件实例
console.log(this);
// next((vm)=>{
// console.log(vm);
// });
// let goodsid = this.$route.params.goodsid;
// console.log(goodsid);
$.get(`/static/data/good${
goodsid}.json`, res => {
console.log(res);
// vm 就是组件实例,使用回调函数来访问
next(vm => {
vm.info = res;
});
});
}
// 解决动态路由组件被复用的问题,路由组件被复用触发
beforeRouteUpdate(to,from,next){
console.log(to.params.cateid)
next()
},
// 离开路由组件
beforeRouteLeave (to, from, next) {
// ...
let flag = confirm("确定离开吗?");
if(flag){
next();
}else{
next(false)
}
}
beforeRouteLeave
守卫。beforeEach
守卫。beforeRouteUpdate
守卫 (2.2+)。beforeEnter
。beforeRouteEnter
。beforeResolve
守卫 (2.5+)。导航被确认
。afterEach
钩子。 // 设置解决跨域问题的代码
proxyTable: {
// "/api":已 /api开头的请求会被代理进行跨域问题解决
"/api":{
target:"http://localhost:3000",//代理的目标地址(真实地址)
changeOrigin:true,//是否跨域
// pathRewrite:{
// "^/api":"/api"
// }
}
/* "/test":{
target:"http://localhost:3000",//代理的目标地址(真实地址)
changeOrigin:true,//是否跨域
pathRewrite:{
"^/test":"",//去除真实请求中不存在二点 /test
}
} */
},
npm i axios
axios({
url:"/api/getgoodsinfo",//请求地址,(target地址+ url 才是真正的地址)
method:"get",//请求方法
// 参数
params:{
id:1
}
}).then((res)=>{
console.log(res);
})
axios({
url:"/api/userlogin",
method:"post",
data:this.info
}).then(res=>console.log(res))
axios.get("/api/getgoodsinfo",{
params:{
id:1
}
}).then((res)=>{
console.log(res);
})
axios.post('/api/userlogin',this.info);
methods: {
getBanner() {
return axios.get("/api/getbanner");
},
getInfo() {
return axios.get("/api/getgoodsinfo", {
params: {
id: 1
}
});
}
}
axios.all([this.getBanner(), this.getInfo()]).then(axios.spread((res1, res2) => {
console.log(res1,res2)
}));
实例可以被认为是axios的独立拷贝,进行单独设置
// 创建新独立axios 实例
let instance = axios.create({
baseURL: “/api”,
timeout: 5000,
})
let instance1 = axios.create({
baseURL: “/apis”
})
instance.get("/getbanner").then(res => console.log(res));
// 设置请求拦截器,回调函数,发送请求时执行的函数
// config 请求参数
axios.interceptors.request.use(config => {
// Do something before request is sent
config.headers.Authorization = localStorage.getItem("token")
/* if(!(config.url=="/api/userlogin"&&config.method=="post")){
config.headers.Authorization = localStorage.getItem("token")
} */
console.log(config)
// return的 config对象,真正发送请求时的请求对象
return config;
}, error => {
// Do something with request error
return Promise.reject(error);
});
// 响应拦截器
// response:响应数据
axios.interceptors.response.use(response => {
// Do something before response is sent
console.log(response)
return response.data;
}, error => {
// Do something with response error
return Promise.reject(error);
});
npm i vuex
src/store/index.js
import Vue from "vue"
import Vuex from "vuex"
// 安装插件
Vue.use(Vuex);
// store-> vuex 实例
let store = new Vuex.Store({
// 定义state(所有组件都可以共享的数据)
state:{
count:1
}
})
export default store
main.js
import Vue from 'vue'
import App from './App'
+ import store from "./store"
Vue.config.productionTip = false
console.log(store)
/* eslint-disable no-new */
new Vue({
el: '#app',
+ store,// 组件应用vuex实例
components: {
App },
template: ' '
})
单一状态树
——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据
源 (SSOT (opens new window))”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。 let store = new Vuex.Store({
// 定义state(所有组件都可以共享的数据)
state:{
count:1
},
// state 的计算属性
getters:{
//参数state-> vuex的state
sqrt(state){
return state.count*state.count;
}
}
})
computed:{
count(){
return this.$store.state.count;
},
sqrt(){
return this.$store.getters.sqrt
}
},
// 定义mutation,修改state的唯一办法是通过提交mutation
mutations:{
// add是mutation的名称,也是函数的名字(当add这个mutation被提交commit时,add函数会执行)
// 参数state-> vuex的state
add(state){
console.log("add ")
// 修改state
state.count++;
},
// payload->负载,提交参数
minus(state,payload){
state.count-=payload
},
// 对象提交方法
mul(state,payload){
console.log(payload)
state.count*=payload.n
}
methods: {
addFn() {
// 提交名为add的mutation
// commit(mutation名称)
this.$store.commit("add");
},
minus() {
// commit(mutation名称,负载数据)
this.$store.commit("minus",2)
},
mul(){
// 提交名为 mul的mutation,数据是 n:2
this.$store.commit({
type:"mul",//mutation名称
n:2,//数据
})
}
}
//组件中使用
ADD() {
this.$store.dispatch("ADD");
}
//在action中提交mutation
actions:{
ADD({
commit},payload){
console.log(context)
// context.commit("add")
setTimeout(()=>{
commit("add")
},1000)
}
}
let state = ()=>{
return {
count:100}}//函数返回对象
let mutations={
add(state){
state.count++;
}
}
let actions={
ADD({
commit}){
commit("add")
}
}
// cart 模块的配置
let cart = {
namespaced:true,//开启命名空间,提交模块的mutation必须带上模块的名称(独立的)(不开启命名空间,某个mutation被提交,所有同名的mutation都会执行,)
state,
mutations,
actions
}
export default cart
import cart from "./modules/cart"
import mutations from "./mutations"
let store = new Vuex.Store({
strict:true,//严格模式
// 定义模块
modules:{
// key:模块名称
// value:模块配置
cart:cart
},
state:{
... },
getters:{
... },
mutations,
actions:{
...}
}
})
computed: {
/* count1(){
return this.$store.state.cart.count;
}, */
// 计算属性count1 返回的是state中 cart模块的count
...mapState({
count1:state=>state.cart.count}),
}
methods: {
...mapMutations("cart",["add"]),
addFn1(){
// 提交根模块的 mutation add
this.$store.commit("add")
//只触发cart模块的 add mutation
this.$store.commit("cart/add")
// this.add()
}
}
import {
mapState,mapGetters,mapMutations,mapActions} from "vuex"
mapState,mapGetters
computed: {
/* count:function() {
return this.$store.state.count;
},
msg()*{
return this.$store.state.msg;
}*/
// 添加 名为count的计算属性,返回state 中count
// 映射 this.count 为 store.state.count
...mapState(["count","msg"]),
/* sqrt() {
return this.$store.getters.sqrt;
} */
// 映射 this.sqrt 为 store.getters.sqrt
...mapGetters(["sqrt"])
},
mapMutations,mapActions
/* add(){
this.$store.commit("add");
}, */
...mapMutations(["add","minus"]),
addFn() {
// 提交名为add的mutation
// commit(mutation名称)
// this.$store.commit("add");
// this.add 映射提交 名为 add的mutation
this.add();
},
/* minus(n){
this.$store.commit("minus", n);
}, */
minusFn() {
// commit(mutation名称,负载数据)
// this.$store.commit("minus", 2);
// 提交名为 minus的mutation,payload为2
this.minus(2)
},
mul() {
this.$store.commit("mul",3)
},
...mapActions(["ADD"]),
/* ADD(){
this.$store.dispatch("ADD");
}, */
ADDFn() {
this.ADD();
}