一、is属性
<body>
<div id='app'></div>
</body>
<script src="js/vue.js"></script>
<script>
// 挂载时,可以通过is属性知道组件名来挂载
const listItem = {
template: `<li>111111111111</li>`
}
const App = {
template: `
<div>
<h3>App组件</h3>
<ul>
<li is='listItem'></li>
</ul>
</div>
`,
components: { listItem }
}
new Vue({
render: h => h(App),
}).$mount('#app')
</script>
二、动态组件
<body>
<div id='app'></div>
</body>
- 动态组件 => 动态修改is属性的值,实现动态挂载不同的组件。
<script src="js/vue.js"></script>
<script>
const box = {
template: `<li>111111111111</li>`
}
const item = {
template: `<li>222222222222</li>`
}
const App = {
template: `
<div>
<h3>App组件</h3>
<button @click='fn'>按钮</button>
<ul>
<li :is='cn'></li>
</ul>
</div>
`,
data() {
return { cn: 'box'}
},
methods: {
fn() {
// this.cn = 'item';
if (this.cn === 'box') {
this.cn = 'item';
} else {
this.cn = 'box';
}
}
},
components: { box, item }
}
new Vue({
render: h => h(App),
}).$mount('#app')
</script>
三、动态组件的生命周期
<body>
<div id='app'></div>
</body>
- 动态组件在切换过程中,会频繁的创建和销毁.
- 显示时创建,隐藏时销毁.
<script src="js/vue.js"></script>
<script>
const box = {
template: `<li>111111111111</li>`,
created() {
console.log('box创建')
},
destroyed() {
console.log('box销毁')
}
}
const item = {
template: `<li>222222222222</li>`
}
const App = {
template: `
<div>
<h3>App组件</h3>
<button @click='fn'>按钮</button>
<ul>
<li :is='cn'></li>
</ul>
</div>
`,
data() {
return { cn: 'box'}
},
methods: {
fn() {
// this.cn = 'item';
if (this.cn === 'box') {
this.cn = 'item';
} else {
this.cn = 'box';
}
}
},
components: { box, item }
}
new Vue({
render: h => h(App),
}).$mount('#app')
</script>
四、缓存组件keep-alive
<body>
<div id='app'></div>
</body>
动态组件在切换过程中,会频繁的创建和销毁.
显示时创建,隐藏时销毁.动态组件默认无法保留组件状态,每次切换都是初始状态.
要保留组件状态,可以使用keep-alive包裹动态组件.
keep-alive是一个抽象的内置组件.
包裹之后,组件就不会重复的创建和销毁.created和destroyed只触发一次.keep-alive默认缓存所有渲染过的动态组件.
keep-alive如何实现部分缓存?
利用属性include => 包含某某组件 => 只缓存某某组件
利用属性exclude => 不包含某某组件 => 除了某某组件都缓存.
<script src="js/vue.js"></script>
<script>
const box = {
template: `
<li>
<input type='text' v-model='msg' />
<span>{{msg}}</span>
</li>
`,
data() {
return { msg: '' }
},
created() {
console.log('box创建')
},
destroyed() {
console.log('box销毁')
}
}
const item = {
template: `
<li>
<input type='text' />
</li>
`,
created() {
console.log('item创建')
},
destroyed() {
console.log('item销毁')
}
}
const App = {
template: `
<div>
<h3>App组件</h3>
<button @click='fn'>按钮</button>
<ul>
<keep-alive exclude='item'>
<li :is='cn'></li>
</keep-alive>
</ul>
</div>
`,
data() {
return { cn: 'box'}
},
methods: {
fn() {
// this.cn = 'item';
if (this.cn === 'box') {
this.cn = 'item';
} else {
this.cn = 'box';
}
}
},
components: { box, item }
}
new Vue({
render: h => h(App),
}).$mount('#app')
</script>
五、keep-alive
<body>
<div id='app'></div>
</body>
<script src="js/vue.js"></script>
<script>
// keep-alive对v-if也生效.
const box = {
template: `<li>111<input type='text' /></li>`,
}
const item = {
template: `<li>222<input type='text' /></li>`
}
const App = {
template: `
<div>
<h3>App组件</h3>
<button @click='flag = !flag'>按钮</button>
<ul>
<keep-alive>
<box v-if='flag'></box>
<item v-else></item>
</keep-alive>
</ul>
</div>
`,
data() {
return { flag: true }
},
components: { box, item }
}
new Vue({
render: h => h(App),
}).$mount('#app')
</script>
六、缓存组件的两个生命周期
<body>
<div id='app'></div>
</body>
- 如果动态组件缓存了.如何知道动态组件发生了切换?
- 如何知道当前显示的是哪个组件?
- activated和deactivated是被缓存的动态组件特有的生命周期钩子函数.
- 不被缓存的组件是没有这两个钩子函数.
<script src="js/vue.js"></script>
<script>
const box = {
template: `
<li>
<input type='text' v-model='msg' />
<span>{{msg}}</span>
</li>
`,
data() {
return { msg: '' }
},
// 激活了
activated() {
console.log('box显示了')
},
// 失活了
deactivated() {
console.log('box隐藏了')
}
}
const item = {
template: `
<li>
<input type='text' />
</li>
`,
created() {
console.log('item创建')
},
destroyed() {
console.log('item销毁')
}
}
const App = {
template: `
<div>
<h3>App组件</h3>
<button @click='fn'>按钮</button>
<ul>
<keep-alive>
<li :is='cn'></li>
</keep-alive>
</ul>
</div>
`,
data() {
return { cn: 'box'}
},
methods: {
fn() {
// this.cn = 'item';
if (this.cn === 'box') {
this.cn = 'item';
} else {
this.cn = 'box';
}
}
},
components: { box, item }
}
new Vue({
render: h => h(App),
}).$mount('#app')
</script>
七、路由和单页应用
传统的网页或者App会有很多页面
- 传统的网页都是开发很多的html页面来充当分页
- Vue框架就不好实现多html页面的网页应用
Vue的路由用于实现单页应用
- 单页应用 => SPA => single page appliation => 一个网站只会一个html
单页应用如何开发别的单页?
- 单页应用的分页统统通过Vue组件来开发 => 一个页面对应一个组件
- 因此网站页面的切换 => Vue组件的切换 => 动态组件切换
八、路由创建和挂载
<body>
<div id='app'></div>
</body>
vue路由需要使用一个vue-router的插件来实现。
vue-router是vue的插件,因此需要在引入Vue之后引入
4XX的版本是为Vue3的路由版本.Vue2需要使用3xx的版本.路由的写法(注意路由以下三点):
1:实例化路由.(写路由选项 => 路由组件和路由路径的对应关系)
2:挂载路由实例
3:挂载路由视图(router-view 这是一个动态组件,会自动切换成你的路由组件)路由组件切换的核心逻辑 => 路径改变驱动路由组件切换.
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
const Home = {
template: `
<div>
<h3>首页</h3>
</div>
`
}
const News = {
template: `
<div>
<h3>新闻</h3>
</div>
`
}
const Sport = {
template: `
<div>
<h3>体育</h3>
</div>
`
}
// 实例化路由
const router = new VueRouter({
// 路由组件和路由路径的对应关系 => 路由选项
routes: [
{
// 路由路径
path: '/home',
// 路由组件
component: Home
}, {
// 路由路径
path: '/news',
// 路由组件
component: News
}, {
// 路由路径
path: '/sport',
// 路由组件
component: Sport
}
]
})
const App = {
template: `
<div>
<a href='#home'>首页</a>
<a href='#news'>新闻</a>
<a href='#sport'>体育</a>
<router-view />
</div>
`
};
new Vue({
render: h => h(App),
// 挂载路由
router
}).$mount('#app');
</script>
九、router-link
<body>
<div id='app'></div>
</body>
可以使用router-link内置组件来代替a标签.
router-link最终渲染时,还是被渲染成a标签.
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
const Home = {
template: `
<div>
<h3>首页</h3>
</div>
`
}
const News = {
template: `
<div>
<h3>新闻</h3>
</div>
`
}
const Sport = {
template: `
<div>
<h3>体育</h3>
</div>
`
}
// 实例化路由
const router = new VueRouter({
// 路由组件和路由路径的对应关系 => 路由选项
routes: [
{
// 路由路径
path: '/home',
// 路由组件
component: Home
}, {
// 路由路径
path: '/news',
// 路由组件
component: News
}, {
// 路由路径
path: '/sport',
// 路由组件
component: Sport
}
]
})
const App = {
template: `
<div>
<router-link to='/home'>首页</router-link>
<router-link to='/news'>新闻</router-link>
<router-link to='/sport'>体育</router-link>
<router-view />
</div>
`
};
new Vue({
render: h => h(App),
// 挂载路由
router
}).$mount('#app');
</script>
十、重定向
1.0
<body>
<div id='app'></div>
</body>
可以使用router-link内置组件来代替a标签.
router-link最终渲染时,还是被渲染成a标签.
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
const Home = {
template: `
<div>
<h3>首页</h3>
</div>
`
}
const News = {
template: `
<div>
<h3>新闻</h3>
</div>
`
}
const Sport = {
template: `
<div>
<h3>体育</h3>
</div>
`
}
// 实例化路由
const router = new VueRouter({
// 路由组件和路由路径的对应关系 => 路由选项
routes: [
{
// 路由路径
path: '/home',
// 路由组件
component: Home
}, {
// 路由路径
path: '/news',
// 路由组件
component: News
}, {
// 路由路径
path: '/sport',
// 路由组件
component: Sport
}, {
// 当你的路径是/时,把路径变成/home
path: '/',
// 重定向到home
redirect: '/home'
}
]
})
const App = { //根组件
template: `
<div>
<router-link to='/home'>首页</router-link>
<router-link to='/news'>新闻</router-link>
<router-link to='/sport'>体育</router-link>
<router-view />
</div>
`
};
new Vue({
render: h => h(App),
// 挂载路由
router
}).$mount('#app');
</script>
1.1
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
const Home = {
template: `
<div>
<h3>首页</h3>
</div>
`
}
const News = {
template: `
<div>
<h3>新闻</h3>
</div>
`
}
const Sport = {
template: `
<div>
<h3>体育</h3>
</div>
`
}
// 实例化路由
const router = new VueRouter({
// 路由组件和路由路径的对应关系 => 路由选项
routes: [
{
// 路由路径
path: '/',
// 路由组件
component: Home
}, {
// 路由路径
path: '/news',
// 路由组件
component: News
}, {
// 路由路径
path: '/sport',
// 路由组件
component: Sport
}
]
})
const App = {
template: `
<div>
<router-link to='/'>首页</router-link>
<router-link to='/news'>新闻</router-link>
<router-link to='/sport'>体育</router-link>
<router-view />
</div>
`
};
new Vue({
render: h => h(App),
// 挂载路由
router
}).$mount('#app');
</script>
十一、编程式导航
<body>
<div id='app'></div>
</body>
(挂载store实例后,任何组件都可以同$store来访问这个Vuex实例)
挂载理由实例之后,任何组件都可以通过$router来访问到这个路由实例.
路由实例方法push可以实现跳转.参数是:
1:字符串的path.
2:纯对象.路由实例方法replace也可以实现跳转.参数和push的一致.
和push的区别是不会把当前页面添加到页面栈内.
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
const Home = {
template: `
<div>
<h3>首页</h3>
</div>
`
}
const News = {
template: `
<div>
<h3>新闻</h3>
</div>
`
}
const Sport = {
template: `
<div>
<h3>体育</h3>
</div>
`
}
// 实例化路由
const router = new VueRouter({
// 路由组件和路由路径的对应关系 => 路由选项
routes: [
{
path: '/home',
component: Home,
// 路由选项的命名.
name: 'home'
}, {
path: '/news',
component: News,
name: 'news'
}, {
path: '/sport',
component: Sport,
name: 'sport'
}, {
// 当你的路径是/时,把路径变成/home
path: '/',
// 重定向到home
redirect: '/home'
}
]
})
const App = {
template: `
<div>
<button @click='toPage("home")'>首页</button>
<button @click='toPage("news")'>新闻</button>
<button @click='toPage("sport")'>体育</button>
<router-view />
</div>
`,
methods: {
// 编程式导航
toPage(path) { //哈希值(hash)直接变成home, path 路径跳转方法
location.hash = '#/' + path //原生JS的写法
// 路由实例.
// console.log(this.$router);
// Vue路由的跳转方法。
// this.$router.push('/' + path);
// 传纯对象.路径选项path指定跳转的路径
// this.$router.push({ path: '/' + path});
// 传纯对象,选项name是路由选项的name命名(必须保证路由选项有命名)
// this.$router.push({ name: path }); //常见的方法
// 不会把当前页面加入到页面栈
// this.$router.replace({ name: path });
// 前进
// this.$router.forward();
// 后退
// this.$router.back();
// 指定跳转
// this.$router.go(1);
}
}
};
new Vue({
render: h => h(App),
// 挂载路由
router
}).$mount('#app');
</script>
十二、嵌套路由
<body>
<div id='app'></div>
</body>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
// 嵌套路由 => 路由组件视图内又有另一个路由视图
const Home = {
template: `
<div>
<h3>首页</h3>
<router-link to='/home/phone'>手机</router-link>
<router-link to='/home/computer'>电脑</router-link>
<router-link to='/home/pad'>ipad</router-link>
<router-view />
</div>
`
}
const News = {
template: `
<div>
<h3>新闻</h3>
</div>
`
}
const Sport = {
template: `
<div>
<h3>体育</h3>
</div>
`
}
const Phone = {
template: `<h3>手机</h3>`
}
const Computer = {
template: `<h3>电脑</h3>`
}
const Pad = {
template: `<h3>ipad平板</h3>`
}
// 子路由
const childRoutes = [
{
path: '/home/phone',
component: Phone,
name: 'phone'
}, {
path: '/home/computer',
component: Computer,
name: 'computer'
}, {
path: '/home/pad',
component: Pad,
name: 'pad'
}, {
path: '/',
redirect: '/home/phone'
}
];
// 父路由
const routes = {
// 路由组件和路由路径的对应关系 => 路由选项
routes: [
{
// 路由路径
path: '/',
// 路由组件
component: Home,
// Home组件内的子路由,需要配置children选项
children: childRoutes
}, {
path: '/news',
component: News
}, {
path: '/sport',
component: Sport
}
]
}
// 实例化路由
const router = new VueRouter(routes)
const App = {
template: `
<div>
<router-link to='/'>首页</router-link>
<router-link to='/news'>新闻</router-link>
<router-link to='/sport'>体育</router-link>
<router-view />
</div>
`
};
new Vue({
render: h => h(App),
// 挂载路由
router
}).$mount('#app');
</script>
十三、嵌套路由的路径写法
<body>
<div id='app'></div>
</body>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
// 嵌套路由 => 路由组件视图内又有另一个路由视图
const Home = {
template: `
<div>
<h3>首页</h3>
<router-link to='/home/phone'>手机</router-link>
<router-link to='/home/computer'>电脑</router-link>
<router-link to='/home/pad'>ipad</router-link>
<router-view />
</div>
`
}
const News = {
template: `
<div>
<h3>新闻</h3>
</div>
`
}
const Sport = {
template: `
<div>
<h3>体育</h3>
</div>
`
}
const Phone = {
template: `<h3>手机</h3>`
}
const Computer = {
template: `<h3>电脑</h3>`
}
const Pad = {
template: `<h3>ipad平板</h3>`
}
// 子路由
const childRoutes = [
{
path: 'phone',
component: Phone,
name: 'phone'
}, {
path: 'computer',
component: Computer,
name: 'computer'
}, {
path: 'pad',
component: Pad,
name: 'pad'
}
];
// 父路由
const routes = {
// 路由组件和路由路径的对应关系 => 路由选项
routes: [
{
// 路由路径
path: '/home',
// 路由组件
component: Home,
// Home组件内的子路由,需要配置children选项
children: childRoutes,
// path等于/home时,重定向到'/home/phone'
redirect: '/home/phone'
}, {
path: '/news',
component: News
}, {
path: '/sport',
component: Sport
}, {
path: '/',
redirect: '/home'
}
]
}
// 实例化路由
const router = new VueRouter(routes)
const App = {
template: `
<div>
<router-link to='/'>首页</router-link>
<router-link to='/news'>新闻</router-link>
<router-link to='/sport'>体育</router-link>
<router-view />
</div>
`
};
new Vue({
render: h => h(App),
// 挂载路由
router
}).$mount('#app');
</script>
十四、登录页的嵌套路由
<body>
<div id='app'></div>
</body>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
const Login = {
template: `
<div id='login'>
<input type="text">
<input type="password">
<button @click='$router.push("/home")'>登录</button>
</div>
`
}
const Home = {
template: `
<div id='home'>
<router-link to='/home/music'>音乐</router-link>
<router-link to='/home/news'>新闻</router-link>
<router-link to='/home/sport'>体育</router-link>
<router-view />
</div>
`
}
const Music = {
template: `<h3>音乐</h3>`
}
const News = {
template: `<h3>新闻</h3>`
}
const Sport = {
template: `<h3>体育</h3>`
}
// 子路由
const childrenRoutes = [
{
path: 'music',
component: Music,
name: 'music'
}, {
path: 'news',
component: News,
name: 'news'
}, {
path: 'sport',
component: Sport,
name: 'sport'
}
]
// 父路由
const routes = {
routes: [
{
path: '/login',
component: Login,
name: 'login'
}, {
path: '/home',
component: Home,
name: 'name',
children: childrenRoutes,
redirect: '/home/music'
}, {
path: '/',
redirect: '/login'
}
]
}
// 实例化路由
const router = new VueRouter(routes);
const App = {
template: `
<div id='app'>
<router-view />
</div>
`
}
new Vue({
render: h => h(App),
router
}).$mount('#app')
</script>
十五、嵌套路由的跳转问题
<body>
<div id='app'></div>
</body>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
const Login = {
template: `
<div id='login'>
<input type="text">
<input type="password">
<button @click='toPage'>登录</button>
</div>
`,
methods: {
toPage() {
// this.$router.push('/home');
// this.$router.push('/home/news');
// this.$router.push('/home/music');
// this.$router.push({ name: 'home' });
// 如果跳转到二级路由组件,name需要写二级路由的name.
// this.$router.push({ name: 'music' });
}
}
}
const Home = {
template: `
<div id='home'>
<router-link to='/home/music'>音乐</router-link>
<router-link to='/home/news'>新闻</router-link>
<router-link to='/home/sport'>体育</router-link>
<router-view />
</div>
`
}
const Music = {
template: `<h3>音乐</h3>`
}
const News = {
template: `<h3>新闻</h3>`
}
const Sport = {
template: `<h3>体育</h3>`
}
// 子路由
const childrenRoutes = [
{
path: 'music',
component: Music,
name: 'music'
}, {
path: 'news',
component: News,
name: 'news'
}, {
path: 'sport',
component: Sport,
name: 'sport'
}, {
path: '/',
redirect: 'music'
}
]
// 父路由
const routes = {
routes: [
{
path: '/login',
component: Login,
name: 'login'
}, {
path: '/home',
component: Home,
name: 'home',
children: childrenRoutes
}, {
path: '/',
redirect: '/login'
}
]
}
// 实例化路由
const router = new VueRouter(routes);
const App = {
template: `
<div id='app'>
<router-view />
</div>
`
}
new Vue({
render: h => h(App),
router
}).$mount('#app')
</script>
十六、跳转路由的组件
<body>
<div id='app'></div>
</body>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
const Home = {
template: `
<div>
<h3>首页</h3>
<input type='text' />
</div>
`,
created() {
console.log('home组件创建')
},
// 缓存的路由组件切换时触发.
activated() {
console.log('切换到Home组件')
},
deactivated() {
console.log('Home页面隐藏')
}
}
const News = {
template: `
<div>
<h3>新闻</h3>
</div>
`
}
const Sport = {
template: `
<div>
<h3>体育</h3>
<input type='text' />
</div>
`,
// 组件名
name: 'sport'
}
// 实例化路由
const router = new VueRouter({
// 路由组件和路由路径的对应关系 => 路由选项
routes: [
{
path: '/home',
component: Home
}, {
path: '/news',
component: News
}, {
path: '/sport',
component: Sport,
}, {
// 当你的路径是/时,把路径变成/home
path: '/',
// 重定向到home
redirect: '/home'
}
]
})
const App = {
template: `
<div>
<router-link to='/home'>首页</router-link>
<router-link to='/news'>新闻</router-link>
<router-link to='/sport'>体育</router-link>
<keep-alive exclude='sport'> //exclude 缓存
<router-view />
</keep-alive>
</div>
`
};
new Vue({
render: h => h(App),
// 挂载路由
router
}).$mount('#app');
</script>
十七、路由的组件关系
<body>
<div id='app'></div>
</body>
- Home和News和Sport这些路由组件都是App的子组件
- App可以通过props给这些路由组件传递数据,以及实现状态管理.
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<script>
const Home = {
template: `
<div>
<h3>首页---{{count}}</h3>
<input type='text' />
</div>
`,
props: ['count']
}
const News = {
template: `
<div>
<h3>新闻---{{count}}</h3>
</div>
`,
props: ['count']
}
const Sport = {
template: `
<div>
<h3>体育---{{count}}</h3>
<input type='text' />
</div>
`,
props: ['count']
}
// 实例化路由
const router = new VueRouter({
// 路由组件和路由路径的对应关系 => 路由选项
routes: [
{
path: '/home',
component: Home
}, {
path: '/news',
component: News
}, {
path: '/sport',
component: Sport,
}, {
// 当你的路径是/时,把路径变成/home
path: '/',
// 重定向到home
redirect: '/home'
}
]
});
const App = {
template: `
<div>
<router-link to='/home'>首页</router-link>
<router-link to='/news'>新闻</router-link>
<router-link to='/sport'>体育</router-link>
<button @click='count++'>count++</button>
<router-view :count='count' />
</div>
`,
data() {
return {
count: 0
}
}
};
new Vue({
render: h => h(App),
// 挂载路由
router
}).$mount('#app');
</script>