<template>
<div>
<p>组件:{
{ title }}-{
{ num }}p>
<div>
<p>{
{ count }}p>
<button @click="count +=1 ">按钮button>
div>
<button @click="sendMessageHandle">传递数据button>
div>
template>
<script>
export default {
data(){
return{
count:0,
message:"我是Hello的数据"
}
},
props:{
title:{
type:String,
default:"默认数据"
},
num:{
type:Number,
default:0
}
},
methods:{
sendMessageHandle(){
this.$emit("onMyEvent",this.message)
}
}
}
script>
<style>
style>
1. 引入
import Hei from "./components/Hei";
2. 依赖注入
components: {
Hei, // 注入
}
3. 以标签的形式使用
<Hello />
组件的使用是独立的(独立被实例化)。组件的数据空间是相互隔离的。
要求data必须是一个函数,才能保证组件是独立实例化的。
data() {
return {
......
};
},
......
组件之间可以随意引用。
父组件:
<Hello title="组件基础" :num="0" />
-------------------------------------------------------------
子组件:
<p>组件:{
{ title }}-{
{ num }}p>
......
props:{
title:{
type:String, # 包装类
default:"默认数据"
},
num:{
type:Number, # 包装类
default:0
}
}
props传递参数没有类型限制,参数的个数也没有限制。
子组件:
<button @click="sendMessageHandle">传递数据button>
......
data(){
return{
count:0,
message:"我是Hello的数据"
}
},
methods:{
sendMessageHandle(){
this.$emit("onMyEvent",this.message) # message -> data
}
}
-------------------------------------------------------------
父组件:
<p>{
{ helloMessage }}p>
<Hello @onMyEvent="getHelloMessageHandle"/>
......
data(){
return{
helloMessage:""
}
},
methods: {
getHelloMessageHandle(data){
console.log(data);
this.helloMessage = data;
}
}
插槽是组件传递数据的另外一种方式。不仅可以传递数据,还可以传递视图。插槽多用于封装组件。
父组件:
<template>
<div id="app">
<MyComponent>
<div>MyComponent双标签内的内容就是插槽——默认不显示,只显示子组件的内容:“插槽”div>
MyComponent>
div>
template>
<script>
import MyComponent from "./components/MyComponent"
export default {
name: 'App',
components: {
MyComponent
}
}
script>
----------------------------------------------------
子组件:
<template>
<div>
<h3>插槽h3>
<div>
<slot>slot>
div>
div>
template>
<script>
export default {
}
script>
<style>
style>
实现效果:
父组件将
<div>MyComponent双标签内的内容就是插槽——默认不显示,只显示子组件的内容:“插槽”div>
传递给子组件显示
即变量写在哪里就在哪里声明。
比如msg变量:
父组件:
<template>
<div id="app">
<MyComponent>
<div>{
{ msg }}div>
MyComponent>
div>
template>
<script>
import MyComponent from "./components/MyComponent"
export default {
name: 'App',
data(){
return{
msg:"我是插槽内容"
}
},
components: {
MyComponent
}
}
script>
这里的变量msg写在父组件中就在父组件中声明,而不是在子组件中声明。
父组件:
<template>
<div id="app">
<MyComponent>
MyComponent>
div>
template>
<script>
import MyComponent from "./components/MyComponent"
export default {
name: 'App',
components: {
MyComponent
}
}
script>
----------------------------------------------------
子组件:
<template>
<div>
<h3>插槽h3>
<div>
<slot>默认值/后备内容slot>
div>
div>
template>
<script>
export default {
}
script>
<style>
style>
父组件如果在引入的MyComponent标签中什么也不给,那么最终将显示子组件slot标签中的内容——默认值,也称后备内容。如果父组件中引入的MyComponent标签中给了内容,那么该内容将替换slot标签及其内容——覆盖显示。
插槽可以有多个,我们可以使用名字来区分。
父组件:
<template>
<div id="app">
<MyComponent>
<template v-slot:header>
<div>头部div>
template>
<template v-slot:body>
<div>内容div>
template>
<template v-slot:footer>
<div>底部div>
template>
MyComponent>
div>
template>
-------------------------------------------------------------
子组件:
<template>
<div>
<h3>插槽h3>
<div>
<slot name="header">默认值/后备内容slot>
<hr>
<slot name='body'>默认值/后备内容slot>
<hr>
<slot name="footer">默认值/后备内容slot>
div>
div>
template>
注意v-slot指令只能在template标签中使用。
数据定义在子组件中,但不通过子组件显示,而是传递给父组件显示。
父组件:
<template>
<div id="app">
<MyComponent>
<template v-slot:default="slotProps">
<h3>{
{slotProps.demo}}h3>
template>
MyComponent>
div>
template>
<script>
import MyComponent from "./components/MyComponent"
export default {
name: 'App',
components: {
MyComponent
}
}
script>
--------------------------------------------------------
子组件:
<template>
<div>
<h3>插槽h3>
<div>
<slot :demo="data">slot>
div>
div>
template>
<script>
export default {
data(){
return{
data:"测试"
}
}
}
script>
这种用法常见于子组件有数据但不知道如何显示,而父组件知道如何显示。那么子组件就把数据传递给父组件去显示。
<template>
<div id="app">
<div>
<Dynamic/>
div>
div>
template>
<script>
import Dynamic from "./components/Dynamic";
export default {
components: {
Dynamic
}
};
script>
----------------------------------------
Dynamic.vue:
<template>
<div>
<h3>动态组件h3>
<button @click="changeHandler">切换视图button>
<keep-alive>
<component :is="componentId">component>
keep-alive>
div>
template>
<script>
import Child1 from "./Child1";
import Child2 from "./Child2";
export default {
data() {
return {
componentId: Child1,
};
},
components: {
Child1,
Child2,
},
methods: {
changeHandler() {
if (this.componentId === Child1) {
this.componentId = Child2;
} else {
this.componentId = Child1;
}
},
},
};
script>
----------------------------------------
Child1.vue:
<template>
<div>
<h3>Child1h3>
div>
template>
----------------------------------------
Child2.vue:
<template>
<div>
<h3>Child2h3>
<p>{
{msg}}p>
<button @click="clickHandler">修改button>
div>
template>
<script>
export default {
data() {
return {
msg:"第一次的输入"
};
},
methods: {
clickHandler(){
this.msg="用户已经输入的数据"
}
}
};
script>
针对组件的加载方式提出:
//传统组件加载方式:
import MyComponent from "./MyComponent ";
//异步组件加载方式:
const MyComponent = () => import ("./MyComponent");
区别就在于传统方式组件在js代码加载后既被加载,而异步组件加载是一种“懒”加载方式——按需加载。异步组件加载可以将无需首次显示的组件延迟加载,以获得速度上的提升。
Vue构建的一种全局使用对象的方式。这种对象使用方式超越了组件的名字空间,可以在全局名字空间下借助$符号完成对js对象的调用。
常见的引用有:
new Vue({
......,
data() {
baby:"my girl friend"
},
methods:{
dating(){
return "cradle-snatcher love"
}
}
}).$mount('#app')
在Vue实例的子组件中(所有组件都是它的子组件)引用
<p>{
{$root.baby}}p>
<p>{
{$root.dating()}}p>
<p>{
{$parent.objDefinedInParent}}p>
很显然边界处理的方式容易引起强耦合,一般不建议使用。
Vue的路由主要是应用在单页面应用SPA中。传统的页面跳转主要通过a标签打开一个全新的页面,而Vue的路由使得视图发生更换但页面不发生跳转。
Vue的路由插件Vue Router是官方维护的。
官网的参考手册:https://router.vuejs.org/zh/installation.html
# save参数表示将安装的版本等信息以组件依赖(dependencies)保存进package.json
npm install vue-router --save
如果在一个模块化工程中使用它,必须要通过 Vue.use() 明确地安装路由功能:
编辑src/main.js
import VueRouter from 'vue-router'
Vue.use(VueRouter)
然后就可以启动项目npm run serve
Home.vue:
<template>
<div>
<h3>首页h3>
div>
template>
--------------------------------------------------------------
User.vue:
<template>
<div>
<h3>用户界面h3>
div>
template>
import Vue from 'vue'
import App from './App.vue' //注意:App.vue是默认第一个加载的vue组件
import './registerServiceWorker'
import VueRouter from 'vue-router'
import Home from "./pages/Home.vue"
import User from "./pages/User.vue"
Vue.use(VueRouter)
Vue.config.productionTip = false
//定义路由
const routes = [
{
path:"/",
component:Home
},
{
path:"/user",
component:User
}
]
//创建路由对象
const router = new VueRouter({
routes
})
new Vue({
router, //挂载路由
render: h => h(App),
}).$mount('#app')
<template>
<div id="app">
<router-view>router-view>
div>
template>
在App.vue中添加router-link标签:
<template>
<div id="app">
<router-link to="/">首页router-link> |
<router-link to="/user">用户router-link>
<router-view>router-view>
div>
template>
//定义路由
const routes = [
{
path:"/user/:userId",
component:User
}
]
<router-link to="/user/8888">用户router-link>
<h3>用户界面:{
{$route.params.userId}}h3>
传递的路径参数有没有限制?没有。
比如传递的数量就没有限制:
const routes = [
{
path:"/user/:userId/:name/:age",
component:User
}
]
----------------------------------------------------------
<router-link to="/user/8888/beeworkshop/31">用户</router-link>
----------------------------------------------------------
<template>
<div>
<h3>用户ID:{
{
$route.params.userId}}</h3>
<h3>用户姓名:{
{
$route.params.name}}</h3>
<h3>用户年龄:{
{
$route.params.age}}</h3>
</div>
</template>
就是将路由的定义拆分到main.js之外的其他文件中去。具体组织如下
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from "../pages/Home.vue"
import User from "../pages/User.vue"
Vue.use(VueRouter)
//定义路由
const routes = [
{
path:"/",
component:Home
},
{
path:"/user/:userId/:name/:age",
component:User
}
]
//创建路由对象
const router = new VueRouter({
routes
})
//导出路由对象
export default router
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import router from "./router" //默认导入index.js
Vue.config.productionTip = false
new Vue({
router, //挂载路由
render: h => h(App),
}).$mount('#app')
<template>
<div id="app">
<router-link to="/">首页router-link> |
<router-link to="/user/8888/beeworkshop/31">用户router-link>
<router-view>router-view>
div>
template>
import Bee from "../pages/Bee" //默认导入扩展名为.vue的组件
import BigBee from "../pages/bee/BigBee"
import SmallBee from "../pages/bee/SmallBee"
//定义路由
//定义 /bee/bigbee 和 /bee/smallbee
const routes = [
{
//URL的父级路径
path:"/bee",
component:Bee,
//URL的子路径(children中可以再嵌套children)
children:[
{
//path不再需要加“/”开头
path:"bigbee",
component:BigBee
},
{
path:"smallbee",
component:SmallBee
}
]
}
]
注意:符号@也可表示src/这个目录——@ is an alias to /src
。
<template>
<div id="app">
<router-link to="/bee">Bee主分类router-link>
<router-view>router-view>
div>
template>
<template>
<div>
<h3>演示路由嵌套:蜜蜂分类h3>
<router-link to="/bee/bigbee">大router-link> |
<router-link to="/bee/smallbee">小router-link>
<router-view>router-view>
div>
template>
router-link最终是渲染为a标签。
那以编程方式如何实现路由跳转?
<template>
<div>
<h3>大蜜蜂h3>
<button @click="clickHandler">去首页button>
div>
template>
<script>
export default {
methods: {
clickHandler(){
this.$router.push("/")
//this.$router.replace("/")
}
},
}
script>
那么
this.$router.replace("/") 和 this.$router.push("/")
有什么区别呢?
* replace是替换没有缓存,用户无法返回之前的网页。
* push(形成类似栈的结构)是有缓存的,用户可以返回之前的网页。