vue笔记7
16.动态组件
页面中的某个地方,在不同的组件之间进行动态切换,除了使用条件渲染(v-if/v-show)还能使用动态组件来实现。
vue提供了component标签来实现;
在component标签的is属性的属性名决定在当前位置使用哪个组件来进行渲染。
<component is="Box"></component> ==><Box></Box>
可以给is属性绑定data中的变量,通过改变该变量的值,来达到切换不同组件的目的:
<component :is="mycomponent"></component>
<template>
<div id="app">
<button @click="fn">xx</button>
<components :is="com"></components>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
import HelloWorld2 from './components/HelloWorld2.vue'
export default {
name: 'app',
data(){return{
flag:true,
com:"HelloWorld",
}},
components: {
HelloWorld,"HelloWorld2"
},
methods:{
fn(){
this.flag=!this.flag
this.com=this.flag?"HelloWorld":"HelloWorld2"
}
}
}
</script>
17.缓存组件
动态组件的每次切换,都会创建一个新的组件对象。
在上一个组件进行的操作数据等,在切换后不会保存。
使用keep-alive可以缓存动态切换的组件。
<keep-alive><component :is="Box"></component></keep-alive>
keep-alive的两个属性:
- include决定哪些组件可以被缓存
- exclude:除当前组件外,其他组件被缓存
- 可以传入字符串或者正则表达式(传入正则表达式时,需要给属性加v-bind表示是JS语法环境)
<keep-alive exclude="a,b">
<!-- 除了name为a或者b的组件,其余组件都缓存 -->
<component :is="view"></component>
</keep-alive>
<!-- 使用正则表达式,需使用v-bind 缓存名字为a || b的组件-->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
动态组件的钩子函数:
deactivated:只有被缓存的组件才有,被 keep-alive 缓存的组件停用时调用。
activated:只有被缓存的组件才有,被 keep-alive 缓存的组件激活时调用。
<script>
export default {
data() {
return {
idcard: "",
pwd:""
}
},
methods:{
send(){
console.log(this.idcard,this.pwd)
}
},
mounted() {
console.log("只有第一次创建时才会执行")
},
activated() {
console.log("页面刷新渲染一次就执行一次")
}
}
</script>
18.异步组件
异步加载并缓存组件:
1、 异步加载组件:用不到的组件不会加载,因此网页打开速度会很快,当你用到这个组件的时候,才会通过异步请求进行加载;
官方解释:Vue允许将组件定义为一个异步解析(加载)组件定义的工厂函数,即Vue只在实际需要渲染组件时,才会触发调用工厂函数,并且将结果缓存起来,用于将来再次渲染。
2、 组件缓存起来:通过异步加载的组件会缓存起来,当你下一次再用到这个组件时,丝毫不会有任何的疑迟,组件很快会从缓存中加载出来。
-
方法一:通过webpack2.0的按需加载 //1 全局:
Vue.component('component-name',function(resolve){
//require 语法告诉 webpack自动将编译后的代码分割成不同的块
//这些块将通过 Ajax 请求自动下载
require(['./my-async-componnet'],resolve)
})
//注册全局组件名,但只有一个名字,没有实体,相当于空的
//当需要这个组件时,调用上面的工厂函数,触发webpack的异步加载模块方法
//然后异步请求一个模块,请求成功后,这个模块内容即为组件实体部分,并对应地方渲染,加载内容也缓存下来。
//2 局部
new Vue({
components: {
'component-name':function(resolve) {
require(['./my-component'], resolve)
}
}
})
-
方法二:通过webpack2+es2015返回一个promise(主流 ) //1 全局:
Vue.component('component-name',
()=> import('./my-async-componnet')//这个 `import` 函数会返回一个 `Promise` 对象
)
//2 局部:
new Vue({
components: {
'component-name': () => import('./my-async-componnet')//这个 `import` 函数会返回一个 `Promise` 对象。
}
})
-
方法三:高级异步组件 //工厂对象可以返回一个如下对象,对象里面的一些配置参数
const AsyncComponent = () => ({
// 需要加载的组件 (这个 `import` 函数会返回一个 `Promise` 对象。)
component: import('./MyComponent.vue'),
// 异步组件加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
// 如果提供了超时时间且组件加载也超时了,
// 则使用加载失败时使用的组件。默认值是:`Infinity`
timeout: 3000
})
-
示例 <script>
import Box from './Box.vue';
// import Box2 from './Box2.vue'
// import Box3 from './Box3.vue'
import LoadingComponent from "./LoadingComponent.vue"
import ErrorComponent from "./ErrorComponent.vue"
export default {
components: {
Box,
Box2: (resolve) => {
return require(["./Box2.vue"], resolve)
},
Box3: () => import("./Box3.vue"),
Box4: () => ({
// 需要加载的组件 (应该是一个 `Promise` 对象)
component: import('./Box4.vue'),
// 异步组件加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
// 如果提供了超时时间且组件加载也超时了,
// 则使用加载失败时使用的组件。默认值是:`Infinity`
timeout: 3000
})
}
}
</script>
19.组件总结
//模板上用的代码:
插值表达式:{{}}
文本插入指令,不识别标签:v-text
文本插入指令,识别标签:v-html
阻止当前标签被识别:v-pre
实例化Vue时被移除:v-clock
属性绑定:v-bind ===>语法糖:":"
事件绑定指令:v-on ===>语法糖:"@"
事件修饰符 : .stop=》阻止冒泡
.once=》事件在触发一次之后解绑
.capture =》使事件在捕获阶段触发
.self=》当元素本身作为目标对象时才触发事件
.native =》给子组件添加原生事件
.passive =》不拦截默认事件
自定义指令:v-xxx directive
条件指令:v-if/v-else v-show
循环指令:v-for
双向绑定指令:v-model
属性传递:attr
事件传递:listener
插槽:新:v-slot 旧:slot
//组件内的代码
data:()=>{} //数据
props:[],//组件属性
comments:{},//组件挂载
directives:{},//自定义指令
filters:{},//过滤器
watch:{},//监听
computed:{},//计算属性
//生命周期函数
beforeCreate(){},//vm实例化之前,不能操作vm
created(){},//vm实例化完成
beforeMount(){},//vm挂载到DOM之前
mounted(){},//vm挂载到DOM
beforeUpdate(){},//数据更新之前
updated(){}//数据更新
beforeDestroy(){}//vm销毁之前
destroyed(){}//vm销毁之后
this可以访问哪些东西?
this.data;//访问到data中的数据
this.$emit(fu(),reg);//反向传值,触发父组件绑定的函数
this.$root;//访问到根组件
this.$parent;//访问当前组件的父组件
this.$children;//访问当前组件的子组件(返回值是数组)
this.$destroy();//销毁当前实例
this.$refs;// dom操作 访问绑定了ref属性的节点
this.$nextTick(fn);//该函数将会在组件挂载之后被调用
this.$on;//绑定事件
this.$off;//事件解绑
this.$bus;//中央事件总线,将新的vm绑定在Vue的原型上后,所有组件都可以通过this.$bus访问
20.路由
1.路由的定义:
这里的路由并不是指我们平时所说的硬件路由器,这里的路由就是SPA(单页应用)的路径管理器。再通俗的说,vue-router就是WebApp的链接路径管理系统。 vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。路由模块的本质 就是建立起url和组件之间的映射关系。
不能使用a标签,这是因为用Vue做的都是单页应用(当你的项目准备打包时,运行npm run build 时,就会生成dist文件夹,这里面只有静态资源和一个index.html页面),所以你写的标签是不起作用的,你必须使用vue-router来进行管理。
后端路由:对于前端的网络请求,不同的pathname,去执行后端的不同业务
前端路由:不同的网址对应各自的页面
vue的前端路由:SPA应用要做出路由效果,就得判断当前网址,然后切换组件
vue-router就是专门做切换组件的功能,它是一个单独的技术,依赖vue
vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。
2.路由的引入
-
cdn引入: -
通过node.js下载路由插件 //安装到项目中:
npm i vue-router --save-dev//注意:这种下载不好,因为打包之后容易出问题
npm i vue-router --save或者 npm i vue-router --S
//在main.js入口文件中引入
import Vue from "vue"
import VueRouter from "vue-router"//引入路由工具
import App from "./App.vue"
Vue.use(VueRouter)//注入路由,就是运行路由的相关函数和给vue绑定东西:比如$router
//创建路由工具
const router=new VueRouter({
//routes路由器 生成很多网址对应的切换组件
routes:[{path:"/home",component:()=>import("./home.vue")},//具体路由路径
{path:"/about",component:()=>import("./about.vue")}]
})
new Vue({
router,//把路由挂载到页面
render(h){return h(App)}
}).$mount("#app")
//使用,在App.vue中写 <router-view></router-view>
//路由网址匹配到的组件 会渲染到当前组件的这个标签上
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
-
通过vue脚手架创建含路由的vue环境 //首先要已经全局安装脚手架
//创建vue项目
vue create app
//选择Manually select features
//空格勾选router
//创建项目
3.router-view和router-link标签
- router-view:路由网址匹配的组件,会渲染到当前组件的
<router-view></router-view> 标签中。 - router-link:相当于a标签,可以跳转到某个路由。(a标签能够刷新页面,主要用于外部跳转,router-link标签主要用于当前站内跳转)
<router-link to="/xx"></router-link>
4.this.$router 和this.$route 的区别
在任何组件内通过 this.$router 访问路由器,也可以通过 this.$route 访问当前路由(路由传参使用)
this.$router 相当于一个全局的路由器对象,包含了很多属性和对象(比如 history 对象),任何页面都可以调用其 push(), replace(), go() 等方法。
this.$route 表示当前路由对象,每一个路由都会有一个 route 对象,是一个局部的对象,可以获取对应的 name, path, params, query 等属性。
5.声明式导航router-link路由传参
<router-link to="/xx"></router-link> :表示目标路由的链接。当被点击后,内部会立刻把 to 的值传到 router.push() ,所以这个值可以是一个字符串或者是描述目标位置的对象。
<!-- 字符串 to属性不是对象时,只能匹配路由的path -->
<router-link to="/home">Home</router-link>
<!-- 渲染结果 -->
<a href="home">Home</a>
<!-- 使用 v-bind 的 JS 表达式 -->
<router-link v-bind:to="'home'">Home</router-link>
<!-- 不写 v-bind 也可以,就像绑定别的属性一样 -->
<router-link :to="'home'">Home</router-link>
<router-link :to="path">Home</router-link>
<!-- 同上 -->
<router-link :to="{ path: 'home' }">Home</router-link>
<router-link :to="{ name: 'user'}">User</router-link>
参数传递
-
通过直接在路由后面写上?id=值的形式 <router-link to="/game?id=1">游戏</router-link>
<router-link :to="'/game?id=' + id">游戏</router-link>
//
<router-link to="/xx?name=karen&pwd=123">go</router-link>
渲染后对应的路由为:http://localhost:8090/#/my?id=1 在对应的my.vue组件,可以通过this.$route.query 来访问传递的参数 <template>
<div>这是我的页面</div>
</template>
<script>
export default {
created() {
console.log(this.$route.query); //打印 {id: "1"}
}
}
</script>
-
通过 / 后面拼接参数的形式 <router-link to="/my/9">我的页面</router-link>
<router-link :to="'/my/' + id">我的页面</router-link>
渲染后路由为:http://localhost:8090/#/my/1(现在id的值为1) 这种方式需要在route.js中配置路由时,在路径path: ‘/my’ 后边需要拼接:id接收router-link id的值 {
path: '/my/:id',
name: 'my',
component: () => import('@/views/my.vue')
}
在my.vue组件中可以通过this.$route.params访问到id属性 <template>
<div>这是我的页面</div>
</template>
<script>
export default {
console.log(this.$route.params); //打印 {id: "1"}
}
}
</script>
3.通过v-bind 给to属性绑定一个对象,对象中通过path和query属性去标明路径 和 参数 <router-link :to="{ path: '/my', query: { id: id } }">点击去我的页面</router-link>
此时渲染的路由为:http://localhost:8090/#/my?id=1 路由配置为: path: ‘/my’ ,不要匹配参数 在my.vue组件中可以通过this.$route.query访问到id属性 <template>
<div>这是我的页面</div>
</template>
<script>
export default {
name: '',
components: {},
data() {
return {
}
},
created() {
console.log(this.$route.query); //打印 {id: "1"}
}
}
</script>
4、通过v-bind 给to属性绑定一个对象,对象中通过name和params属性去标明路径 和 参数 – 声明式导航命名路由–动态路由传参
<router-link :to="{ name: 'my', params: { id: id } }">点击去我的页面</router-link>
此时渲染的路由为:http://localhost:8090/#/my
路由配置为: path: ‘/my’ ,不需要匹配参数,但是要给路由加上name属性
const routes = [{
{
path: "/my",
name:"my",
component: () => import("../my.vue")
}
]
在my.vue组件中可以通过this.$route.params访问到id属性
<template>
<div>这是我的页面</div>
</template>
<script>
export default {
name: '',
components: {},
data() {
return {
}
},
created() {
console.log(this.$route.params); //打印 {id: "1"}
}
}
</script>
6.编程式导航传参
通过JS代码进行路由跳转称为编程式导航
基本形式是:this.$router.push({path:"/xx",query:{name:"karen",pwd:123}})
-
基础传参方式: toMy() {
// 第一层路由可以不加/
this.$router.push('/my'); // 字符串,路由规则中定义的path与push中参数对应
this.$router.push('/my/' + this.id); // 拼接参数
路由配置为:path: '/my/:id'
渲染路径:http://localhost:8080/dist/#/my/6
取参params
this.$router.push('/my?id=' + this.id); // 拼接参数
路由配置为:path: '/my'
渲染路径:http://localhost:8080/dist/#/my?id=6
取参query
}
-
对象跳转方式path与name this.$router.push({ path: '/my' })
this.$router.push({ name: 'my' })
渲染路径:http://localhost:8080/#/my
路由配置为: {path: '/my' , name: 'myow',component:()=>import('@/vires/my.vue')}
this.$router.push({ path: '/my/' + this.id });
渲染路径:http://localhost:8080/#/my/9
路由配置为: {path: '/my/:id' , name: 'myow',component:()=>import('@/vires/my.vue')}
-
传参跳转name 和 params (编程式导航命名路由) toMy() {
this.$router.push({ name: 'my', params: { id: this.id } });
}
//渲染路径:http://localhost:8090/#/my
路由配置为: {path: '/my' , name: 'my',component:()=>import('@/views/my.vue')}
在my.vue中通过this.$route.params访问到id参数值
-
传参跳转path和 query toMy() {
this.$router.push({ path: '/my', query: { id: this.id } });
}
渲染路径:http://localhost:8090/#/my?id=1
路由配置为: {path: '/my' , name: 'my',component:()=>import('@/views/my.vue')}
在my.vue中通过this.$route.query访问到id参数值
7.query传参和params传参的区别?
1、query传参:匹配path || 匹配name,
params传参:匹配name
params传参特殊情况:当用 / 拼接参数的时候 匹配的是path,对应页面是params取参
2、query传参:url栏后边会拼接参数(?参数名1=参数值1&参数名2=参数值2),
params传参:url栏后边不会拼接参数
params传参特殊情况:如果路由配置更改为/:变量 url栏会拼接参数
3、query传参:刷新页面参数不会丢失,
params传参:刷新页面参数会丢失
params传参特殊情况:如果路由配置更改为/:变量 接收了参数 那么不会丢失
4、query传参:通过this.route.query取参
params传参:通过this.route.params取参
8.路由嵌套
重定向:redirect //表示跳转到该路由时,自动转到某个重定向的路由
配置嵌套的路由时,路径之前不加"/";//加"/“表示的时从根路径开始,即路径会从端口号之后开始拼接,不加”/",才是从当前路径开始拼接
路径/*表示通配所有路径,一般用于进行404页面的路由设置。写在最后,路由从上往下进行匹配,匹配成功之后的就不再匹配。
语法:
/**一个路由对象的设计中中包含:
path(路由匹配的路径)
component(匹配路径时对应渲染的组件)
redirect(匹配路径时重新匹配另外的路径)
children(子路由们的数组)
name(路由的名字,方便直接通过名字来匹配路由):
routes=[{path,component,redirect,children,name},{path,component,redirect,children,name}]
**/
const routes = [{
path: '/',
component: () => import("../views/root.vue"),
redirect:"/goods_rank",// 访问/时默认重新访问/goods_rank
children: [{//子路由
name:"goods_rank",
path: "goods_rank",
component: () => import("../views/root/goods_rank.vue"),
//goods_rank组件加载的条件是路由匹配上了: localhost:8080/goods_rank
children: [{
name:"goods_rank_all",
path: "goods_rank_all",
component: () => import("../views/root/goods_rank/goods_rank_all.vue")
//goods_rank_all组件加载的条件是路由匹配上了: localhost:8080/goods_rank/goods_rank_all
},
{
path: "goods_rank_highpraise",
name:"goods_rank_highpraise",
component: () => import("../views/root/goods_rank/goods_rank_highpraise.vue")
},
{
path: "goods_rank_middlepraise",
name:"goods_rank_middlepraise",
component: () => import("../views/root/goods_rank/goods_rank_middlepraise.vue")
},
{
path: "goods_rank_badepraise",
name:"goods_rank_badepraise",
component: () => import("../views/root/goods_rank/goods_rank_badepraise.vue")
},
{
path: "*",
component: () => import("../views/root/goods_rank/goods_rank_all.vue")
}
]
},
{
path: "goods_inventory",
name:"goods_inventory",
component: () => import("../views/root/goods_inventory.vue")
},
{
path: "goods_new",
name:"goods_new",
component: () => import("../views/root/goods_new.vue")
},
{
path: "goods_set",
name:"goods_set",
component: () => import("../views/root/goods_set.vue")
}
]
}]
组件中进行跳转时:
//4种语法:
//1
<router-link to="/当前代码所在组件的路由地址/去哪一个子路由的地址">go</router-link>
this.$router.push({path:"/当前代码所在组件的路由地址/去哪一个子路由的地址"})
//2
<router-link to="去哪一个子路由的地址">go</router-link>
this.$router.push({path:"去哪一个子路由的地址"})
//注意:前面的/要写上,代表绝对路由,不写的话代表相对于当前路由,而不是当前父组件路由
//3
<router-link :to="{name:'注册的路由的name'}">go</router-link>
this.$router.push({name:'注册的路由的name'})
例:
<router-link to="/goods_rank/goods_rank_highpraise">go</router-link>
this.$router.push({path:"/goods_rank/goods_rank_highpraise"})
<router-link :to="{name:'goods_rank_highpraise'}">go</router-link>
this.$router.push({name:'goods_rank_highpraise'})
补充:
//replace跟push很像,但不会向 history 添加新记录,而是替换当前的history记录
this.$router.replace({path:"/home"})
this.$router.go(1)// 在浏览器记录中前进一步,等同于 history.forward()
this.$router.go(-1)// 后退一步记录,等同于 history.back()
this.$router.go(3)// 前进 3 步记录
this.$router.go(-100)// 如果 history 记录不够用,那就默默地失败呗
9.路由模式
**hash模式:**在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取; 特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。 hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.xxx.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。
**history模式:**history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。 history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.xxx.com/items/id。后端如果缺少对 /items/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。
const router=new VueRouter({
mode:"hash",//"history"
routes:[{path:"/home",component:()=>import("./home.vue")},
{path:"/about",component:()=>import("./about.vue")}]
})
补充:v-model的修饰符
v-model.trim :去掉前后的空格v-model.lazy :将底层input事件变为change事件,光标失焦和内容改变才会使data的数据改变。v-model.number :当输入的数据为纯数字时,将输入的数据转为数字类型。(默认是String)
|