三、使用Vue脚手架

说明

1、Vue 脚手架是 Vue 官方提供的标准化开发工具(开发平台)。

2、最新的版本是 5.x。

3、文档: Vue CLI

具体步骤

第一步(仅第一次执行):全局安装@vue/cli。

npm install -g @vue/cli

第二步:切换到你要创建项目的目录,然后使用命令创建项目 

vue create xxxx (xxx项目名)

或者vue ui(打开创建项目ui界面)

第三步:启动项目 

npm run serve

备注:

  1. 如出现下载缓慢请配置 npm 淘宝镜像:npm config set registry https://registry.npm.taobao.org
  2. Vue 脚手架隐藏了所有 webpack 相关的配置,若想查看具体的 webpakc 配置,

请执行:vue inspect > output.js

脚手架文件结构:

vue_test

├── node_modules

├── public

│   ├── index.html:主页面

│   └── favicon.ico:页签图标

├── src

│   ├── assets:存放静态资源

│   │   └── logo.png

│   ├── components:存放组件

│   │   └── HelloWorld.vue

│   ├── App.vue:汇总组件

│   └── main.js:入口文件

├── .gitignore:git版本管制忽略的配置

├── babel.config.js:babel的配置文件

├── package.json:应用包配置文件

├── README.md:应用描述文件

├── package-lock.json:包版本控制文件

├── jsconfig.json

└── vue.config.js

代码视图

src下main.js代码

/* 
  该文件是整个项目的入口文件
*/
//引入Vue
import Vue from "vue";
//import Vue from "vue/dist/vue"; //引入完整版Vue.js

//引入App组件,他是所有组件的父组件
import App from "./App.vue";

//关闭vue的生产提示
Vue.config.productionTip = false;

let a = 1;

/* 
  关于不同版本的Vue:
    1、vue.js 与 vue.runtime.xxx.js 的区别:
        (1)、vue.js是完整版的Vue,包含:核心功能 + 模板解析器
        (2)、vue.runtime.xxx.js试运行版的Vue,只包含:核心功能;没有模板解析器。
    
    2、因为vue.runtime.xxx.js 没有模板解析器,所以不能使用template配置项,需要使用
       render函数接收到 createElement函数 去指定具体内容
          完整写法:
              render(createElement) {   
                  return createElement(element, "value");
              }, 
          
          简写写法:
              render: (createElement) => createElement(element, "value"),
              
*/

//创建Vue实例对象-----vm
new Vue({
  el: "#app",
  //下面这行代码一会解释,完成了这个功能:将App组件放入容器中
  //简写:
  render: (h) => h(App),

  //template: `<h1>你好啊</h1>`,
  // components: { App },
});

src下App.vue

<template>
  <div>
    <img src="./assets/logo.png" alt="" />
    <School></School>
    <Studen></Studen>
  </div>
</template>

<script>
//引入组件
import School from "./components/School";
import Studen from "./components/Student";
export default {
  name: "App",
  components: {
    School,
    Studen,
  },
};
</script>

src下components里的 School.vue  和 Student.vue

// ---- School
<template>
  <!-- 组件的结构 -->
  <div class="school">
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
    <button @click="showName">点我显示学校名字</button>
  </div>
</template>

<script>
export default {
  name: "MySchool",
  data() {
    return {
      name: "xx",
      address: "北京",
    };
  },
  methods: {
    showName() {
      alert(this.name);
    },
  },
};
</script>

<style>
/* 组件的样式 */
.school {
  background-color: pink;
}
</style>

// ---- Student
<template>
  <!-- 组件的结构 -->
  <div class="student">
    <h2>学生名称:{{ name }}</h2>
    <h2>学生年龄:{{ age }}</h2>
  </div>
</template>

<script>
export default {
  name: "MyStuden",
  data() {
    return {
      name: "xinze",
      age: 18,
    };
  },
};
</script>

<style>
/* 组件的样式 */
.student {
  background-color: plum;
}
</style>

 public下的index.html

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8" />
    <!-- 针对IE浏览器的一个特殊配置,含义是让IE浏览器以最高的渲染级别渲染页面 -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <!-- 开启移动端的理想视口 -->
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <!-- 配置页签图标 -->
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
    <!-- 配置网页标题 -->
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <!-- 当浏览器不支持 Js 的时候 noscript 中的元素就会被渲染-->
    <noscript>
      <strong
        >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
        properly without JavaScript enabled. Please enable it to
        continue.</strong
      >
    </noscript>
    <!-- 容器 -->
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

关于不同版本的 Vue

1、vue.js 与 vue.runtime.xxx.js 的区别

(1)、vue.js 是完整版的 Vue,包含:核心功能 + 模板解析器

(2)、vue.runtime.xxx.js 试运行版的 Vue,只包含:核心功能;没有模板解析器。

2、因为 vue.runtime.xxx.js 没有模板解析器,所以不能使用 template 配置项,需要使用 render

完整写法:
           render(createElement) {

               return createElement(element, "value");
           },

简写写法:
           render: (createElement) => createElement(element, "value"),

vue.config.js 配置文件

使用 Vue inspect > output.js 可以查看到 Vue 脚手架的默认值。(把默认值输出到 output.js 的文件里)

使用 vue.config.js 可以对脚手架进行个性化定之,详情见:http://cli.vuejs.org/zh

在 vue.config.js 中配置 lintOnSave: false, 可以关闭关闭语法检查

const { defineConfig } = require("@vue/cli-service");

module.exports = defineConfig({
  transpileDependencies: true,
  //关闭语法检查
  lintOnSave: false,
});

在 package.json 里的 "rules": 中配置 "no-unused-vars": "off", 可以关闭波浪线提示

"rules": {
      "no-unused-vars": "off"
    }

ref 属性

    1、被用来给元素或子组件注册引用信息(id的代替者)

    2、应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)

    3、使用方法:

        打标识:<h1 ref="xxx">...</h1> 或 <School ref="xxx"></School>

        获取:this.$refs.xxx

App.vue

<template>
  <div>
    <h1 v-text="mas" ref="title"></h1>
    <button @click="showName" ref="bth">点我打印元素</button>
    <!-- 组件标签的ref命名不能为 组件名标签名相同 -->
    <School ref="sch" />
  </div>
</template>

<script>
//引入School组件
import School from "./components/School";
export default {
  name: "App",
  components: { School },
  data() {
    return {
      mas: "欢迎学习Vue",
    };
  },
  methods: {
    showName() {
      console.log(this.$refs.title); //真实DOM元素
      console.log(this.$refs.bth); //真实DOM元素
      console.log(this.$refs.sch); //School组件的实例对象(vc)
    },
  },
};
</script>

配置项 props 

功能:让组件接收到外部传过来的数据

        (1)、传递数据:

            <Demo name="xxx" :age="18">

                Demo === 组件标签   name === 想传递的属性

                想要传递的参数为数字获得表达式 可以添加 :单向绑定  : === v-bind:

        (2)、接收数据:

            第一种方式(只接受):        //用的最多

                props:["name","age"]

            第二种方式(限制类型):

                props:{

                    name:String,

                    age:Number

                }

            第三种方式(限制类型、限制必传性、指定默认值):

                props:{

                    name:{

                        type:String,    //类型

                        required:true   //限制必传性

                    },

                    age:{

                        type:Number,

                        default:99      //没有传参时指定默认值

                    }

                }

                required:true 和 default:99没必要出现在一个属性里

        备注:

            props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,

            若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据

App.vue 

<template>
  <div>
    <!-- 这次传参的时候 也可以用到绑定语法 -->
    <Student ref="stu" name="xinze" sex="男" :age="18" />
    <hr />
  </div>
</template>

<script>
//引入School组件
import Student from "./components/Student";
export default {
  name: "App",
  components: { Student },
};
</script>

Student.vue

<template>
  <div class="student">
    <h1>{{ msg }}</h1>
    <h2>名字:{{ name }}</h2>
    <h2>性别:{{ sex }}</h2>
    <h2>年龄:{{ age + 1 }}</h2>
    <h2>可修改的年龄:{{ MyAge }}</h2>
    <button @click="MyAge++">点我年龄+1</button>
  </div>
</template>

<script>
export default {
  name: "MyStudent",
  data() {
    return {
      msg: "个人信息",
      MyAge: this.age,
    };
  },
  //简单声明接收
  /* props: ["name", "sex", "age"], */

  //对象接收(可以控制接收类型)
  /* props: {
    name: String,
    sex: String,
    age: Number,
  }, */

  //对象接收:在限制传参类型的基础上  再加  是否必传 和 不传的时候现实的默认值
  props: {
    name: {
      type: String, //类型为String
      required: true, //设置这个属性就必须 传参
    },
    sex: {
      type: String,
      default: "男", //这个属性是:在没有接收到传参值的情况下 默认赋值
    },
    age: {
      type: Number,
      required: true,
    },
  },
};
</script>

<style>
.student {
  background: pink;
}
</style>

 mixin混入(合)

 功能:可以把多个组件公用的配置提取成一个混入对象
    使用方式:
        第一步定义混合,例如:
            {
                data(){....},
                methods:{....},
                ....
            }
        第二部使用混入,例如:
            (1)、全局混入:Vue.mixin(xxx)
            (2)、局部混入:mixins:['xxx']

mixin.js(定义混入)

export const hunhe1 = {
  methods: {
    showName() {
      alert(this.name);
    },
  },
  mounted() {
    console.log(this, "挂载完毕");
  },
};
export const hunhe2 = {
  data() {
    //这里的data 谁调用了 就会参与赋值
    //赋值过程中 如过调用的data中 有相同的属性 就不会参与赋值 采取使用原身的属性
    return {
      x: 100,
      y: 200,
    };
  },
};

main.js(引入全局)

//引入vue
import Vue from "vue";
//引入组件App
import App from "./App.vue";

//引入 混入  全局引入
import { hunhe1, hunhe2 } from "./tools/mixin";
//使用引入的混入
Vue.mixin(hunhe1);
Vue.mixin(hunhe2);

//关闭vue的生产提示
Vue.config.productionTip = false;

//创建vm
new Vue({
  el: "#app",
  render: (h) => h(App),
});

App.vue

<template>
  <div>
    <Student />
    <School />
    <hr />
  </div>
</template>

<script>
import School from "./components/School";
//引入School组件
import Student from "./components/Student";
export default {
  name: "App",
  components: { Student, School },
};
</script>

School.vue (引入局部)

<template>
  <div class="school">
    <h2 @click="showName">学校名称:{{ name }}</h2>
    <h2>地址{{ sex }}</h2>
  </div>
</template>

<script>
//引入混入    局部引用
/* import { hunhe1 } from "../tools/mixin";
import { hunhe2 } from "../tools/mixin"; */

export default {
  name: "MySchool",
  data() {
    return {
      name: "清华",
      sex: "北京",
    };
  },

  /*  mixins: [hunhe1, hunhe2], //调用引入的 混入 */
};
</script>

<style>
.school {
  background: plum;
}
</style>

Student.vue (引入局部)

<template>
  <div class="student">
    <h2 @click="showName">名字:{{ name }}</h2>
    <h2>性别:{{ sex }}</h2>
  </div>
</template>

<script>
//引入混入    局部引用
/* import { hunhe1 } from "../tools/mixin";
import { hunhe2 } from "../tools/mixin"; */

export default {
  name: "MyStudent",
  data() {
    return {
      name: "xinze",
      sex: "男",
      x: 666,
    };
  },

  /*  mixins: [hunhe1, hunhe2], //调用引入的 混入 */
};
</script>

<style>
.student {
  background: pink;
}
</style>

插件

功能:用于增强Vue
    本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
    定义插件:
        对象.install = function (Vue, options){
            //1、添加全局过滤器
            Vue.filter(....)

            //2、添加全局指令
            Vue.directive(....)

            //3、配置全局混入(合)

            //4、添加实例方法
            Vue.prototype.$myMethod = function(){....}
            Vue.prototype.$myProperty = xxx
        }
    使用插件:
        引入:
            import xxx from "xxx";
        开启
            Vue.use()

plugins.js(定义插件)

export default {
  //定义 一个插件ue
  install(Vue) {
    console.log("@@@install");
    //创建全局自定义指令  自动获取焦点
    Vue.directive("fbind", {
      //指令与元素成功绑定时(一上来) 调用bind()
      bind(element, binding) {
        element.value = binding.value;
      },
      //当元素插入DOM模块后 调用inserted()
      inserted(element, binding) {
        element.focus();
      },
      //指令所在的模板被重新解析时。调用update()
      update(element, binding) {
        element.value = binding.value;
      },
    });
    // 设置全局过滤器  获取字符的前四位
    Vue.filter("mySlice", function (value) {
      return value.slice(0, 4);
    });
    //定义混入      给所有 vm vc实例对象添加连个属性
    Vue.mixin({
      data() {
        //这里的data 谁调用了 就会参与赋值
        //赋值过程中 如过调用的data中 有相同的属性 就不会参与赋值 采取使用原身的属性
        return {
          x: 100,
          y: 200,
        };
      },
    });

    //给vue原型身上添加一个方法(vm和vc都能用)
    Vue.prototype.hello = () => {
      alert("你好!");
    };
  },
};

main.js(引入插件)

//引入vue
import Vue from "vue";
//引入组件App
import App from "./App.vue";
//引入插件
import insatll from "./plugins";

//关闭vue的生产提示
Vue.config.productionTip = false;

//使用(应用)插件    要在vm实例之前使用插件
Vue.use(insatll);

//创建vm
new Vue({
  el: "#app",
  render: (h) => h(App),
});

使用插件

一、
<template>
  <div class="school">
    <h2>学校名称:{{ name }}</h2>
    <h2>地址{{ sex }}</h2>
    <input type="text" v-fbind:value="name" />
  </div>
</template>

<script>
export default {
  name: "MySchool",
  data() {
    return {
      name: "清华",
      sex: "北京",
    };
  },
};
</script>

<style>
.school {
  background: plum;
}
</style>

二、
<template>
  <div class="student">
    <h2>名字:{{ name | mySlice }}</h2>
    <h2>性别:{{ sex }}</h2>
    <button @click="hello">欢迎</button>
  </div>
</template>

<script>
export default {
  name: "MyStudent",
  data() {
    return {
      name: "xinze",
      sex: "男",
    };
  },
  methods: {
    holle() {
      this.hello;
    },
  },
};
</script>

<style>
.student {
  background: pink;
}
</style>

scoped 样式


    作用:让样式在局部生效,防止冲突
    写法:<style scoped>

一、
<template>
  <div class="demo">
    <h2>学校名称:{{ name }}</h2>
    <h2>地址{{ sex }}</h2>
  </div>
</template>

<script>
export default {
  name: "MySchool",
  data() {
    return {
      name: "清华",
      sex: "北京",
    };
  },
};
</script>

<style scoped>
/* 默认css样式  声明了lang="xxx"  可以使用别的样式  scoped在当前组件可用 */
.demo {
  background: plum;
}
</style>


二、

<template>
  <div class="demo">
    <h2>名字:{{ name }}</h2>
    <h2 class="qwe">性别:{{ sex }}</h2>
  </div>
</template>

<script>
export default {
  name: "MyStudent",
  data() {
    return {
      name: "xinze",
      sex: "男",
    };
  },
};
</script>

<style lang="less" scoped>
//默认css样式  声明了lang="xxx"  可以使用别的样式  scoped在当前组件可用
.demo {
  background: pink;
  .qwe {
    font-size: 40px;
  }
}
</style>

组件的自定义事件

绑定事件监听

        <Header @addTodo="addTodo"/>
        或者
        <Header ref="header"/>
        this.$refs.header.$on('addTodo', this.addTodo)

触发事件

        this.$emit('addTodo', todo) 

说明 

1、一种组件间通信的方式,适用于 子组件 ===> 父组件

2、使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(时间的回调在A中)

3、绑定自定义事件:

第一种方式,在夫组件中:<Demo @xinze="test"/>或<Demo v-on:xinze="test">

第二种方式,在夫组件中:

<Demo ref = "demo">
......
mounted(){
    this.$refs.xxx.$on("xinze",this.test)
}
若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。

4、触发自定义事件:this.$emit("xinze",参数)

5、解绑自定义事件:this.$off("xinze")

6、组件上也可以绑定原生DOM事件,需要使用原生事件.native修饰符。

7、注意:通过this.$refs.xxx.$on("xinze",回调函数)绑定自定义事件时,回调要么配置在methods中,要么使用箭头函数,否则this指向会出问题!

 

 App.vue

<template>
  <div class="app">
    <h1>{{ msg }}</h1>
    <h2>学生姓名:{{ stuName }}</h2>
    <!-- 通过父组件给自子组件传递函数的props实现:子给夫传递数据 -->
    <School :getSchoolNmae="getSchoolNmae" />

    <!-- 通过父组件给子组件绑定一个自定义事件实现:子给夫传递数据 (第一种写法,使用@或v-on)-->
    <!-- <Student @xinze.once="getStudentName" /> -->

    <!-- 
    绑定一个自定义事件  @事件名="函数名"    
    绑定原生DOM事件 @click.native  不能直接传原生DOM事件 不然vue会认定为他是自定义事件  原生DOM事件需要加上 .navite
    -->
    <Student @xinze="getStudentName" @demo="m1" @click.native="show" />

    <!-- 通过父组件给子组件绑定一个自定义事件实现:子给夫传递数据 (第二种写法,使用ref)-->
    <!-- <Student ref="student" /> -->
  </div>
</template>

<script>
import School from "./components/School";
//引入School组件
import Student from "./components/Student";
export default {
  name: "App",
  components: { Student, School },
  data() {
    return {
      msg: "你好~",
      stuName: "",
    };
  },
  methods: {
    getSchoolNmae(schooleName) {
      console.log("app接收到了学校名:", schooleName);
    },
    getStudentName(stundentName, ...params) {
      //...params 会把其余的参数封装成一个数组
      console.log("app接收到了学生名:", stundentName, "其余参数:", params);
      this.stuName = stundentName;
    },
    m1() {
      console.log("demo事件被执行");
    },
    show() {
      alert(11);
    },
  },
  mounted() {
    /* 绑定自定义事件 */
    //this.$refs.student.$on("xinze", this.getStudentName);
    /* 绑定自定义事件 直接写函数  记住不能写 普通函数是有自身的this  而箭头函数是往外找的this */
    /* this.$refs.student.$on("xinze", (stundentName) => {
      console.log(this);
      this.stuName = stundentName;
    }); */
    //this.$refs.student.$once("xinze", this.getStudentName); //绑定自定义事件 (一次性)
  },
};
</script>
<style>
.app {
  background-color: pink;
  padding: 5px;
}
</style>

Stundent.vue

<template>
  <div class="student">
    <h2>名字:{{ name }}</h2>
    <h2>性别:{{ sex }}</h2>
    <h2>当前num值:{{ num }}</h2>
    <button @click="add()">点我num++</button>
    <button @click="tranStudentName">把学生名传入app中</button>
    <button @click="unbind">解绑xinze事件</button>
    <button @click="del">点我删除当前vc实例</button>
  </div>
</template>

<script>
export default {
  name: "MyStudent",
  data() {
    return {
      name: "xinze",
      sex: "男",
      num: 1,
    };
  },
  methods: {
    tranStudentName() {
      //使用自定义事件    this。$emit(事件名,(传参))
      //this.$emit("xinze", { name: this.name, a: 444, b: 333, c: 111 });
      this.$emit("xinze", this.name, 444, 333, 111);
      this.$emit("demo");
    },
    unbind() {
      this.$off("xinze"); //解绑一个自定义事件
      //this.$off("xinze", "demo"); //解绑多个自定义事件
      //this.$off(); //解绑所有的自定义事件
    },
    add() {
      console.log("add()被回了");
      this.num++;
    },
    del() {
      this.$destroy(); //销毁了当前Student的组件实例,销毁后所有Student实例的自定义事件全都不奏效。
    },
  },
};
</script>

<style lang="less" scoped>
//默认css样式  声明了lang="xxx"  可以使用别的样式  scoped在当前组件可用
.student {
  background: plum;
  padding: 5px;
  margin-top: 30px;
}
</style>

School.vue

<template>
  <div class="school">
    <h2>学校名称:{{ name }}</h2>
    <h2>地址{{ sex }}</h2>
    <button @click="tranSchoolName">把学校名传入app中</button>
  </div>
</template>

<script>
export default {
  name: "MySchool",
  props: ["getSchoolNmae"],
  data() {
    return {
      name: "清华",
      sex: "北京",
    };
  },
  methods: {
    tranSchoolName() {
      this.getSchoolNmae(this.name);
    },
  },
};
</script>

<style scoped>
/* 默认css样式  声明了lang="xxx"  可以使用别的样式  scoped在当前组件可用 */
.school {
  background: palevioletred;
  padding: 5px;
}
</style>

全局事件总线

Vue 原型对象上包含事件处理的方法

        $on(eventName, listener): 绑定自定义事件监听

        $emit(eventName, data): 分发自定义事件

        $off(eventName): 解绑自定义事件监听

        $once(eventName, listener): 绑定事件监听, 但只能处理一次

所有组件实例对象的原型对象的原型对象就是 Vue 的原型对像

        VueComponent.prototyp.__proto__ === Vue.prototype

        所有组件对象(vc)都能看到 Vue (vm)原型对象上的属性和方法

        Vue.prototype.$bus = new Vue(), 所有的组件对象都能看到$bus 这个属性对象

什么是全局事件总线

        包含事件处理相关方法的对象(只有一个)

        一种组件间通信的方式,适用于任意组件间通信

安装全局事件总线

new Vue({
	.....
	beforeCreate(){
		Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
	},
	.....
})

使用事件总线

        接收数据:A组件想接受数据,则在A组件中给$bus绑定自定义事件,时间的回调留在A组件自身

 mounted() {
    //挂载前  给全局事件总线上绑定一个getName事件
    this.$bus.$on("getName", (val) =>
      console.log("我是Shool组件,我收到了:", val)
    );
  },
  或者 
  methods(){
  	demo(val){
      console.log("我是Shool组件,我收到了:", val)
    }
  }
  ......
  mounted() {
    this.$bus.$on("getName", this.demo(val));
  }, 

提供数据 :this.$bus.$emit("xxx",数据)

最好在beforeDestroy钩子中用$off去解绑当前组件所用到的事件

 beforeDestroy() {
    //销毁前  解绑自身给全局事件总线身上绑定的事件
    this.$bus.off("getName");
  },

main.js

//引入vue
import Vue from "vue";
//引入组件App
import App from "./App.vue";

//关闭vue的生产提示
Vue.config.productionTip = false;

//创建vm
new Vue({
  el: "#app",
  render: (h) => h(App),
  beforeCreate() {
    //Vue实力创建前
    Vue.prototype.$bus = this; //安装全局事件总线
  },
});

School.vue

<template>
  <div class="school">
    <h2>学校名称:{{ name }}</h2>
    <h2>地址{{ sex }}</h2>
  </div>
</template>

<script>
export default {
  name: "MySchool",
  data() {
    return {
      name: "清华",
      sex: "北京",
    };
  },
  mounted() {
    //挂载前  给全局事件总线上绑定一个getName事件
    this.$bus.$on("getName", (val) =>
      console.log("我是Shool组件,我收到了:", val)
    );
  },
  beforeDestroy() {
    //销毁前  解绑自身给全局事件总线身上绑定的事件
    this.$bus.off("getName");
  },
};
</script>

<style scoped>
/* 默认css样式  声明了lang="xxx"  可以使用别的样式  scoped在当前组件可用 */
.school {
  background: palevioletred;
  padding: 5px;
}
</style>

Student.vue

<template>
  <div class="student">
    <h2>名字:{{ name }}</h2>
    <h2>性别:{{ sex }}</h2>
    <button @click="tranName">点我给School发送学生名</button>
  </div>
</template>

<script>
export default {
  name: "MyStudent",
  data() {
    return {
      name: "xinze",
      sex: "男",
    };
  },
  methods: {
    tranName() {
      this.$bus.$emit("getName", this.name);
    },
  },
};
</script>

<style lang="less" scoped>
//默认css样式  声明了lang="xxx"  可以使用别的样式  scoped在当前组件可用
.student {
  background: plum;
  padding: 5px;
  margin-top: 30px;
}
</style>

消息订阅与发布

使用说明

1、一种组件间通信的方式,适用于任意组件间通信

2、使用步骤:

安装 pubsub.js:npm i pubsub-js

引入包:import pubsub from 'pubsub-js'

3、接收数据:A组件想接受数据,则在A组件中订阅消息,订阅消息的回调留在A组件自身。

mounted() {
    this.pubId = pubsub.subscribe("hello", (msgName, data) => {
     //订阅一个名为 hello的消息  他的回调函数有两个参数 第一个时 消息名,第二个开始才是你传入的数据
      console.log("有人发布了hello消息,hello消息的回调执行了", msgName, data);
    });
  },
  或者 
  
  methods(){
    demo( msgName, data){
       console.log("有人发布了hello消息,hello消息的回调执行了", msgName, data);
    }
  }
  ......
  mounted() {
    this.pubId = pubsub.subscribe("hello",demo
  }, 

4、提供数据:pubsub.publish('xxxx',数据)

methods: {
    tranName() {
      /* this.$bus.$emit("getName", this.name); */
      pubsub.publish("hello", 666); //发布一个消息 消息名时helo  ,额外参数 666
    },
  },

5、最好在beforDestory钩子中,用pubsub.unsubscribe(pid)取消订阅

pubsub.unsubscribe(this.pubId);     //pubId时创建订阅的时候接收到的

School.vue

<template>
  <div class="school">
    <h2>学校名称:{{ name }}</h2>
    <h2>地址{{ sex }}</h2>
  </div>
</template>

<script>
//引入 pubsub库(消息订阅与发布)
import pubsub from "pubsub-js";
export default {
  name: "MySchool",
  data() {
    return {
      name: "清华",
      sex: "北京",
    };
  },

  mounted() {
    //挂载前  给全局事件总线上绑定一个getName事件
    /* this.$bus.$on("getName", (val) =>
      console.log("我是Shool组件,我收到了:", val)
    ); */

    this.pubId = pubsub.subscribe("hello", (msgName, data) => {
      //订阅一个名为 hello的消息  他的回调函数有两个参数 第一个时 消息名,第二个开始才是你传入的数据
      console.log("有人发布了hello消息,hello消息的回调执行了", msgName, data);
    });
  },
  beforeDestroy() {
    //销毁前  解绑自身给全局事件总线身上绑定的事件
    /*  this.$bus.off("getName"); */
    pubsub.unsubscribe(this.pubId);
  },
};
</script>

<style scoped>
/* 默认css样式  声明了lang="xxx"  可以使用别的样式  scoped在当前组件可用 */
.school {
  background: palevioletred;
  padding: 5px;
}
</style>

Student.vue

<template>
  <div class="student">
    <h2>名字:{{ name }}</h2>
    <h2>性别:{{ sex }}</h2>
    <button @click="tranName">点我给School发送学生名</button>
  </div>
</template>

<script>
//引入 pubsub库(消息订阅与发布)
import pubsub from "pubsub-js";
export default {
  name: "MyStudent",
  data() {
    return {
      name: "xinze",
      sex: "男",
    };
  },
  methods: {
    tranName() {
      /* this.$bus.$emit("getName", this.name); */
      pubsub.publish("hello", 666); //发布一个消息 消息名时helo  ,额外参数 666
    },
  },
};
</script>

<style lang="less" scoped>
//默认css样式  声明了lang="xxx"  可以使用别的样式  scoped在当前组件可用
.student {
  background: plum;
  padding: 5px;
  margin-top: 30px;
}
</style>

nextTick()

1、语法:this.$nextTick(回调函数)

2、作用:在下一次DOM 更新结束后执行其指定的回调。

3、什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick()所指定的会点函数中进行。

说明:因为vue 你只要改了数据 就会从新解析 DOM 如果你刚改数据就执行某些操作,那么等下次解析DOM 的时候就会失去功能设置了nextTice里的回调函数里的操作 会在 下一次解析完DOM 才执行

// $nextTick() 会在模板解析下一次执行里面的函数
      this.$nextTick(() => this.$refs.inputFocus.focus());

Vue封装的过渡与动画

1、作用:再插入、更新或移除DOM元素时,再合适的时候给元素添加样式类名。

2、图示:

3、写法:

  • 准备好样式:

    • 元素进入时的样式:

      • v-enter:进入的起点

      • v-enter-active:进入过程中

      • v-enter-to:进入的终点

    • 元素离开的样式:

      • v-leave:离开的起点

      • v-leave-active:离开过程中

      • v-leave-to:离开的终点

  • 使用<transition>包裹要过度的元素,并配置name属性:

name 可以替换掉 动画类名开头 的 v

<transition name="h1" appear>
    <!-- appear 初始执行 -->
    <h1 v-show="isShow">你好~</h1>
</transition>
  • 备注:若有多个元素需要过度,则需要使用:<transition-group>,且每个元素都要指定key

动画

<template>
  <div>
    <button @click="isShow = !isShow">点我显示隐藏</button>
    <!-- transition 标签是动画标签 不会被解析 仅供vue实现动过效果用的  -->
    <!-- 标签下仅支持写一个根元素  
    开始动画的时候会自动调用 .v-enter-active 
    结束动画时会自动调用    .v-leave-active
    如果标签内写了 name属性 那么name里的值就可以替换掉上面的 v
    -->
    <transition name="h1" appear>
      <!-- appear 初始执行 -->
      <h1 v-show="isShow">你好~</h1>
    </transition>
  </div>
</template>

<script>
export default {
  name: "Test-1",
  data() {
    return {
      isShow: true,
    };
  },
};
</script>

<style scoped>
h1 {
  background-color: pink;
}
.h1-enter-active {
  animation: goto 0.5s linear;
}
.h1-leave-active {
  animation: goto 0.5s linear reverse;
}

@keyframes goto {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0%);
  }
}
</style>

过渡

<template>
  <div>
    <button @click="isShow = !isShow">点我显示隐藏</button>
    <!-- 
      如果有多个根元素 需要变化标签为  transition-group
      不过需要把每个根元素加一个 key 来识别
       -->
    <transition-group name="h1" appear>
      <!-- appear 初始执行 -->
      <h1 v-show="isShow" key="1">你好~</h1>
      <h1 v-show="!isShow" key="2">你好~</h1>
    </transition-group>
  </div>
</template>

<script>
export default {
  name: "Test-2",
  data() {
    return {
      isShow: true,
    };
  },
};
</script>

<style scoped>
h1 {
  /* 第一种 谁用 给谁属性里添加 */
  /* 设置过度 0.5s  linear 匀速 */
  /* transition: 0.5s linear; */
  background-color: pink;
}
/* 第二种动画 执行 */
.h1-enter-active,
.h1-leave-active {
  transition: 0.5s linear;
}
/* 进入的起点  和离开的终点*/
.h1-enter,
.h1-leave-to {
  transform: translateX(-100%);
}
/* 进入的终点 和离开的起点*/
.h1-enter-to,
.h1-leave {
  transform: translateX(0);
}
</style>

第三方动画库

<template>
  <div>
    <button @click="isShow = !isShow">点我显示隐藏</button>
    <!-- 
      第三发库
      引入
      将官方说的类名加入到name中
      appear  初始执行
      enter-active-class  开始执行  后面可加 库里面的类名
      leave-active-class  结束执行  后面可加 库里面的类名
       -->
    <transition-group
      name="animate__animated animate__bounce"
      appear
      enter-active-class="animate__swing"
      leave-active-class="animate__backOutUp"
    >
      <!-- appear 初始执行 -->
      <h1 v-show="isShow" key="1">你好~</h1>
      <h1 v-show="isShow" key="2">你好~</h1>
    </transition-group>
  </div>
</template>

<script>
//引入
import "animate.css";
export default {
  name: "Test-3",
  data() {
    return {
      isShow: true,
    };
  },
};
</script>

<style scoped>
h1 {
  background-color: pink;
}
</style>

Vue脚手架配置代理

方法一

在vue.config.js中添加如下配置:

devServer: {
    proxy: "http://localhost:5000",
  },

说明:

1、优点:配置简单,请求资源时直接发给前端(8080)即可。

2、缺点:不能配置多个代理,不能灵活的控制请求是否走代理

3、工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器(优先匹配前端资源(8080))

方法二

编写vue.config.js配置具体代理规则:

//开启代理服务器(方式二)可以配置多个代理
  devServer: {
    proxy: {
      "/xinze": {   //匹配所有以 "/xinze"开头的请求路径
        target: "http://localhost:5000",    //代理目标的基础路径
        pathRewrite: { "^/xinze": "" },     //将开头为 "/xinze" 转为 ""
        //ws: true, //用于支持websocket   默认为true
        //changeOrigin: true, //默认为true 用于控制请求头中的host值
        //写了true 隐藏自身端口号 访问那个 就是那个的端口号 false 表明自身的端口号
      },
      "/demo": {
        target: "http://localhost:5001",
        pathRewrite: { "^/demo": "" },
        //ws: true, //用于支持websocket
        //changeOrigin: true, // 用于控制请求头中的host值
      },
    },
  },
/*
changeOrigin设置为true时,服务器收到的请求头中的host为: localhost :5000
change0rigin设置为false时,服务器收到的请求头中的host为: localhost:8080
change0rigin默认值为true
*/
​

说明:

1、优点:可以配置多个代理,且可以灵活的控制请求是否走代理。

2、缺点:配置略微繁琐,请求资源时必须加前缀。

App.vue

<template>
  <div>
    <button @click="getStudents">获取学生信息</button>
    <button @click="getCars">获取汽车信息</button>
  </div>
</template>

<script>
//引入 axios
import axios from "axios";    
export default {
  name: "App",
  methods: {
    getStudents() {
      axios.get("http://localhost:8080/xinze/students").then(
        (response) => {
          console.log("请求成功了", response.data);
        },
        (error) => {
          console.log("请求失败了", error.message);
        }
      );
    },
    getCars() {
      axios.get("http://localhost:8080/demo/cars").then(
        (response) => {
          console.log("请求成功了", response.data);
        },
        (error) => {
          console.log("请求失败了", error.message);
        }
      );
    },
  },
};
</script>

vue.config.js

const { defineConfig } = require("@vue/cli-service");

module.exports = defineConfig({
  transpileDependencies: true,
  //关闭语法检查
  lintOnSave: false,
  //开启代理服务器(方式一)
  /*  devServer: {
    proxy: "http://localhost:5000",
  }, */
  //开启代理服务器(方式二)可以配置多个代理
  devServer: {
    proxy: {
      "/xinze": {
        target: "http://localhost:5000",
        pathRewrite: { "^/xinze": "" },
        //ws: true, //用于支持websocket   默认为true
        //写了true 隐藏自身端口号 访问那个 就是那个的端口号 false 表明自身的端口号
        //changeOrigin: true, //默认为true 用于控制请求头中的host值
      },
      "/demo": {
        target: "http://localhost:5001",
        pathRewrite: { "^/demo": "" },
        //ws: true, //用于支持websocket
        //changeOrigin: true, // 用于控制请求头中的host值
      },
    },
  },
});

 vue 项目中常用的 2 个 Ajax 库

axios

通用的 Ajax 请求库, 官方推荐,使用广泛

安装:npm i axios 

引用:import axios from "axios";

vue-resource插件

        Vue里的发送ajax请求 插件

        安装:npm i vue-resource

        使用:

//引入vue-rusource
import vueResource from "vue-resource";
//使用插件
Vue.use(vueResource);

vue 插件库, vue1.x 使用广泛,官方已不维护。(不推荐)

插槽

说明

1、作用:让父组件可以向子组件指定位置插入 html结构,也是一种组件间通信的方式,适用于

父组件 ===> 子组件

2、分类:默认插槽、具名插槽、作用域插槽

3、使用方式:

  • 默认插槽

    父组件中:
        <category>
            <div>html结构</div>
        </category>
    ​
    子组件中:
        <template>
            <div>
    <!-- 定义一个插槽(挖个坑,等组件的使用者进行填充) 如果没传入值 就会显示标签体内的内容-->
                <slot>插槽默认值</slot>
            </div>
        </template>
  • 具名插槽

    父组件中:
        <category>              //slot="xxx" 对应插槽的 name
            <div slot="center">html结构</div>
        </category>
     <!-- 这里可以写v-slot:footer来指定插槽  但是这种写法仅支持 template标签 -->
        <template  v-slot:footer>   //v-slot:xxx 对应插槽的 name
                
       </template>
    子组件中:
        <template>
            <div>
    <!-- 定义一个插槽(挖个坑,等组件的使用者进行填充) 如果没传入值 就会显示标签体内的内容-->
    <!-- 这里的name属性是根据 传入结构的时候如果需要命名该 name值 才能指定的插入当前插槽 -->   
                <slot name="center">插槽默认值</slot>
                <slot name="footer">插槽默认值</slot>    
            </div>
        </template>
  • 作用域插槽

    • 理解:数据在组件自身,但根据数据生成的结构需要组件的使用者来决定。(game数据在Category组件中,但使用数据所遍历出来的结构有App组件做决定)

    • 具体编码

      父组件---》
      <!-- 
       接收作用域插槽里的绑定的参数方法:
      1、scope="{games}" {} 是吧该插槽绑定的数据转外参数使用
          这种使用的前提必须实在template中接受
      2、slot-scope="{ games }"   这个可以在普通元素标签中接受
      3、v-slot="{ games }"      也可以在普通元素标签中接受
      备注:作用域插槽 也可以具名(name)
      写法: v-slot:插槽名=“games”
      -->
      <category title="游戏">   方法一
          <template scope="{games}">
              <ul>
                  <li v-for="(item, index) in games" :key="index">{{ item }}</li>
             </ul>
          </template>
      </category>
      ​
      <category title="游戏">       方法二
          <template slot-scope="{ games }">
              <ol>
                  <li v-for="(item, index) in games" :key="index">{{ item }}</li>
              </ol>
          </template>
      </category>
      ​
      <category title="游戏">       方法三
          <template v-slot="{ games }">
              <h4 v-for="(item, index) in games" :key="index">{{ item }}</h4>
          </template>
      </category>
      ​
      ---》子组件
      <!--
      作用域插槽: 给插槽绑定一个参数 ,
      使用者需要接收该插槽里的参数(接受方法有三种)
      但是接收名必须跟这边的插槽对应上才能拿到该插槽
      备注:作用域插槽 也可以具名(name)
      -->
      <template>
          <div>
              <slot :games="games">插槽默认值</slot>
          </div>
      </template>
      ​
      <script>
      export default {
        name: "Category-list",
        data() {      数据在子组件中
          return {
            games: ["红色警戒", "穿越火线", "劲舞团", "超级玛丽"],
          };
        },
      };
      </script>

默认插槽

App.vue

<template>
  <div class="container">
    <category title="美食" :ListData="foods">
      <img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="" />
    </category>
    <category title="游戏" :ListData="games">
      <ul>
        <li v-for="(item, index) in games" :key="index">{{ item }}</li>
      </ul>
    </category>
    <category title="电影" :ListData="films">
      <video
        controls
        src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
      ></video>
    </category>
  </div>
</template>

<script>
import Category from "./components/Category.vue";
export default {
  components: { Category },
  name: "App",
  data() {
    return {
      foods: ["火锅", "烧烤", "小龙虾", "牛排"],
      games: ["红色警戒", "穿越火线", "劲舞团", "超级玛丽"],
      films: ["《教父》", "《拆弹专家》", "《你好,李焕英》", "《功夫》"],
    };
  },
};
</script>
<style lang="css">
.container {
  /* 设置弹性布局  默认想右水平方向排序 */
  display: flex;
  /*定义项目在主轴上的对齐方式  设置属性剧中*/
  justify-content: space-around;
}
</style>

components/Category.vue

<template>
  <div class="category">
    <h3>{{ title }}分类</h3>
    <!-- 定义一个插槽(挖个坑,等组件的使用者进行填充) 如果没传入值 就会显示标签体内的内容-->
    <slot>我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
  </div>
</template>

<script>
export default {
  props: ["title", "ListData"],
  name: "Category-list",
};
</script>

<style>
.category {
  background-color: pink;
  width: 200px;
  height: 300px;
}
h3 {
  text-align: center;
  background-color: palevioletred;
}
img,
video {
  width: 100%;
}
</style>

具名插槽

App.vue

<template>
  <div class="container">
    <category title="美食" :ListData="foods">
      <img
        slot="center"
        src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg"
        alt=""
      />
      <div class="foot" slot="footer">
        <a href="#">更多美食</a>
      </div>
    </category>

    <category title="游戏" :ListData="games">
      <ul slot="center">
        <li v-for="(item, index) in games" :key="index">{{ item }}</li>
      </ul>
      <div class="foot" slot="footer">
        <a href="#">单机游戏</a>
        <a href="#">网络游戏</a>
      </div>
    </category>

    <category title="电影" :ListData="films">
      <video
        slot="center"
        controls
        src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
      ></video>
      <!-- 这里可以写v-slot:footer来指定插槽  但是这种写法仅支持 template标签 -->
      <template v-slot:footer>
        <div class="foot">
          <a href="#">经典</a>
          <a href="#">热门</a>
          <a href="#">推荐</a>
        </div>
        <h4>欢迎前来观影</h4>
      </template>
    </category>
  </div>
</template>

<script>
import Category from "./components/Category.vue";
export default {
  components: { Category },
  name: "App",
  data() {
    return {
      foods: ["火锅", "烧烤", "小龙虾", "牛排"],
      games: ["红色警戒", "穿越火线", "劲舞团", "超级玛丽"],
      films: ["《教父》", "《拆弹专家》", "《你好,李焕英》", "《功夫》"],
    };
  },
};
</script>
<style lang="css">
.container,
.foot {
  /* 设置弹性布局  默认想右水平方向排序 */
  display: flex;
  /*定义项目在主轴上的对齐方式  设置属性剧中*/
  justify-content: space-around;
}
img,
video {
  width: 100%;
}
h4 {
  text-align: center;
}
</style>

components/Category.vue

<template>
  <div class="category">
    <h3>{{ title }}分类</h3>
    <!-- 定义一个插槽(挖个坑,等组件的使用者进行填充) 如果没传入值 就会显示标签体内的内容-->
    <!-- 这里的name属性是根据 传入结构的时候如果需要命名该 name值 才能指定的插入当前插槽 -->
    <slot name="center">
      我是一些默认值,当使用者没有传递具体结构时,我会出现1
    </slot>
    <slot name="footer">
      我是一些默认值,当使用者没有传递具体结构时,我会出现2
    </slot>
  </div>
</template>

<script>
export default {
  props: ["title", "ListData"],
  name: "Category-list",
};
</script>

<style>
.category {
  background-color: pink;
  width: 200px;
  height: 300px;
}
h3 {
  text-align: center;
  background-color: palevioletred;
}
</style>

具名插槽

App.vue

<template>
  <div class="container">
    <!-- 接收插槽里的绑定的参数方法:
      1、scope="{games}" {} 是吧该插槽绑定的数据转外参数使用
        这种使用的前提必须实在template中接受
      2、slot-scope="{ games }" 这个可以在普通元素标签中接受
      3、v-slot="{ games }"     也可以在普通元素标签中接受
     -->
    <category title="游戏">
      <template scope="games">
        <ul>
          <li v-for="(item, index) in games.games" :key="index">{{ item }}</li>
        </ul>
      </template>
    </category>

    <category title="游戏">
      <template slot-scope="{ games }">
        <ol>
          <li v-for="(item, index) in games" :key="index">{{ item }}</li>
        </ol>
      </template>
    </category>

    <category title="游戏">
      <template v-slot="{ games }">
        <h4 v-for="(item, index) in games" :key="index">{{ item }}</h4>
      </template>
    </category>
  </div>
</template>

<script>
import Category from "./components/Category.vue";
export default {
  components: { Category },
  name: "App",
  data() {
    return {};
  },
};
</script>
<style lang="css">
.container,
.foot {
  /* 设置弹性布局  默认想右水平方向排序 */
  display: flex;
  /*定义项目在主轴上的对齐方式  设置属性剧中*/
  justify-content: space-around;
}
img,
video {
  width: 100%;
}
h4 {
  text-align: center;
}
</style>

components/Category.vue

<template>
  <div class="category">
    <h3>{{ title }}分类</h3>
    <!-- 定义一个插槽(挖个坑,等组件的使用者进行填充) 如果没传入值 就会显示标签体内的内容-->
    <!-- 
    作用域插槽: 给插槽绑定一个参数 ,
    使用者需要接收该插槽里的参数(接受方法有三种)但是接收名必须跟这边的插槽对应上才能拿到该插槽-->
    <slot :games="games"> 我是一些默认值 </slot>
  </div>
</template>

<script>
export default {
  props: ["title", "ListData"],
  name: "Category-list",
  data() {
    return {
      games: ["红色警戒", "穿越火线", "劲舞团", "超级玛丽"],
    };
  },
};
</script>

<style>
.category {
  background-color: pink;
  width: 200px;
  height: 300px;
}
h3 {
  text-align: center;
  background-color: palevioletred;
}
img,
video {
  width: 100%;
}
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XinZeBig

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值