【Vue全家桶】--- 第三章:Vue脚手架(Vue CLI)

文章目录

  • 第三章:使用Vue脚手架(Vue CLI)
    • 3.1、初始化脚手架
      • 3.1.1、说明
      • 3.1.2、具体步骤
      • 3.1.3、模板项目的结构及配置
      • 3.1.4、第一个脚手架实例
    • 3.2、ref属性与props属性
      • 3.2.1、ref属性
      • 3.2.2、props属性
    • 3.3、mixin(混入)
    • 3.4、插件
    • 3.5、scoped样式
    • 3.6、TodoList
    • 3.7、webStorage
    • 3.8、组件的自定义事件
    • 3.9、全局事件总线(GlobalEventBus)
    • 3.10、消息订阅与发布(pubsub)
    • 3.11、nextTick
    • 3.12、Vue封装的过度与动画

第三章:使用Vue脚手架(Vue CLI)

3.1、初始化脚手架

3.1.1、说明

  1. 脚手架全名:Command line interface
  2. Vue 脚手架是Vue 官方提供的标准化开发工具(开发平台)
  3. 文档: https://cli.vuejs.org/zh/。

3.1.2、具体步骤

前提:先安装Nodejs

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

npm install -g @vue/cli

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

vue create xxxx

第三步:启动项目(在当前目录下执行)

npm run serve

备注:

  • 如出现下载缓慢请配置 npm 淘宝镜像:npm config set registry https://registry.npm.taobao.org

  • Vue 脚手架隐藏了所有webpack 相关的配置,若想查看具体的webpakc 配置, 请执行:vue inspect > output.js

3.1.3、模板项目的结构及配置

结构

├── node_modules 
├── public
│   ├── favicon.ico: 页签图标
│   └── index.html: 主页面
├── src
│   ├── assets: 存放静态资源
│   │   └── logo.png
│   │── component: 存放组件
│   │   └── HelloWorld.vue
│   │── App.vue: 汇总所有组件
│   │── main.js: 入口文件
├── .gitignore: git版本管制忽略的配置
├── babel.config.js: babel的配置文件
├── package.json: 应用包配置文件 
├── README.md: 应用描述文件
├── package-lock.json:包版本控制文件

配置

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函数去指定具体内容

2.修改默认配置文件(vue.config.js)

  1. 使用vue inspect > output.js可以查看到Vue脚手架的默认配置。
  2. 使用vue.config.js可以对脚手架进行个性化定制,详情见:https://cli.vuejs.org/zh
  3. lintOnSave: false //关闭语法检查

3.暴露方式

第一种方式(分别):export const school = Vue.extend({})

第二种方式(同一):export {school}

第三种方式(默认==>推荐):export default school 简化 export default Vue.extend({})

第三种更精简方式


3.1.4、第一个脚手架实例

main.js

/* 
该文件时整个项目的入口文件
*/
//引入Vue (残缺版vue)
import Vue from 'vue'
//完整版Vue
//import Vue from 'vue/dist/vue'
/* 
引入App组件,它是所有组件的父组件
*/
import App from './App.vue'
//关闭vue生产提示
Vue.config.productionTip = false


//创建Vue实例对象    vm
new Vue({
   el: '#app',
   //将App组件放入容器中
  /*  render(createElement) {

      return createElement('h1', '你好')
   } */
    render: h => h(App)
}) 

App.vue




SchoolName.vue

  




Student.vue

  



index.html

DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
		
    <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>硅谷系统title>
  head>
  <body>
		
    <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>
    
  body>
html>

3.2、ref属性与props属性

3.2.1、ref属性

  1. 被用来给元素或子组件注册引用信息(id的替代者)
  2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
  3. 使用方式:
  4. 打标识:

    .....

  5. 获取:this.$refs.xxx

3.2.2、props属性

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

  2. 传递数据:

  3. 接收数据:

    1. 第一种方式(只接收):props:['name']
    2. 第二种方式(限制类型):props:{name:String}
    3. 第三种方式(限制类型、限制必要性、指定默认值):
    props:{
    	name:{
    	type:String, //类型
    	required:true, //必要性
    	default:'老王' //默认值
    	}
    }
    

备注:

props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

data() {
    return {
        myName:this.name
    };
},

3.3、mixin(混入)

  1. 功能:可以把多个组件共用的配置提取成一个混入对象

  2. 使用方式:

    第一步定义混合:mixin.js**(main.js同级目录)**

    export const mixin = {//分别暴露
        data(){....},
        methods:{....}
        ....
    }
    

    第二步使用混入:import {mixin} from '../mixin'

    1. 全局混入:Vue.mixin(xxx)
    2. 局部混入:mixins:['xxx']

3.4、插件

  1. 功能:用于增强Vue

  2. 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。

  3. 定义插件:plugins .js**(main.js同级目录)**

    export default {
        install(Vue){
            //全局过滤器
            Vue.filter('mySlice',function(value){
                return value.slice(0,4)
            })
    
            //定义全局指令
            Vue.directive('fbind',{
                //指令与元素成功绑定时(一上来)
                bind(element,binding){
                    element.value = binding.value
                },
                //指令所在元素被插入页面时
                inserted(element,binding){
                    element.focus()
                },
                //指令所在的模板被重新解析时
                update(element,binding){
                    element.value = binding.value
                }
            })
    
            //定义混入
            Vue.mixin({
                data() {
                    return {
                        x:100,
                        y:200
                    }
                },
            })
    
            //给Vue原型上添加一个方法(vm和vc就都能用了)
            Vue.prototype.hello = ()=>{alert('你好啊')}
        }
    }
    
  4. 引入并使用插件:

    //引入插件

    import plugins from './plugins'

    使用插件

    Vue.use()

    //引入Vue
    import Vue from "vue";
    //引入App
    import App from './App'
    //引入插件
    import plugins from './plugins'
    //关闭Vue的生产提示
    Vue.config.productionTip = false
    //创建vm
    //应用(使用)插件
    Vue.use(plugins)
    new Vue({
        el: '#app',
        render: h => h(App)
    });
    

3.5、scoped样式

  1. 作用:让样式在局部生效,防止冲突。
  2. 写法:

    3.6、TodoList

    1. 组件化编码流程:

    ​ (1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。

    ​ (2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:

    ​ 1).一个组件在用:放在组件自身即可。

    ​ 2). 一些组件在用:放在他们共同的父组件上(状态提升)。

    ​ (3).实现交互:从绑定事件开始。

    1. props适用于:

    ​ (1).父组件 ==> 子组件 通信

    ​ (2).子组件 ==> 父组件 通信(要求父先给子一个函数

    1. 使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!

    2. props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。

    案例:后面会持续改良,请向下继续阅读

    子组件 ==> 父组件 通信方式:父先给子一个函数
    【Vue全家桶】--- 第三章:Vue脚手架(Vue CLI)_第1张图片

    main.js

    //引入Vue
    import Vue from "vue";
    //引入App
    import App from './App'
    //关闭Vue的生产提示
    Vue.config.productionTip = false
    //创建vm
    //应用(使用)插件
    new Vue({
        el: '#app',
        render: h => h(App)
    });
    

    App.js

    
    
    
    
    

    MyHeader.vue

    
    
    
    
    
    

    List.vue

    
    
    
    
    
    

    Item.vue

    
    
    
    
    
    

    MyFooter.vue

    
    
    
    
    
    

    3.7、webStorage

    1. 存储内容大小一般支持5MB左右(不同浏览器可能还不一样)

    2. 浏览器端通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制。

    3. 相关API:

    4. xxxxxStorage.setItem('key', 'value');
      该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。

    5. xxxxxStorage.getItem('person');

      ​ 该方法接受一个键名作为参数,返回键名对应的值。

    6. xxxxxStorage.removeItem('key');

      ​ 该方法接受一个键名作为参数,并把该键名从存储中删除。

    7. xxxxxStorage.clear()

      ​ 该方法会清空存储中的所有数据。

    8. 备注:

    9. SessionStorage存储的内容会随着浏览器窗口关闭而消失。

    10. LocalStorage存储的内容,需要手动清除才会消失。

    11. xxxxxStorage.getItem(xxx)如果xxx对应的value获取不到,那么getItem的返回值是null。

    12. JSON.parse(null)的结果依然是null。

    案例:以localStorage为例,sessionStorage类似

    DOCTYPE html>
    <html>
      <head>
        <meta charset='UTF-8'>
        <title>localStoragetitle>
      head>
      <body>
        <h2>localStorageh2>
        <button onclick="saveData()">点我保存一个数据button>
        <button onclick="readData()">点我读取一个数据button>
        <button onclick="deleteData()">点我删除一个数据button>
        <button onclick="deleteAllData()">点我清空全部数据button>
    
        <script type="text/javascript">
            let person = {name:'张三',age:15 }
            function saveData(){
                //key 和 value 都必须是字符串,自动转换为字符串
                localStorage.setItem('msg','hello')
                localStorage.setItem('person',JSON.stringify(person))
            }
            function readData(){
                console.log(localStorage.getItem('msg'))
               const result = localStorage.getItem('person')
                console.log(JSON.parse(result))
    
            }
            function deleteData(){
               localStorage.removeItem('msg')
               localStorage.removeItem('person')
            }
            function deleteAllData(){
               localStorage.clear()   
            }
        script>
      body>
    html> 
    

    3.8、组件的自定义事件

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

    在3.6、TodoList章节中采用的方式是:通过父组件给子组件传递函数类型propos实现

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

    2. 绑定自定义事件:

    3. 第一种方式,在父组件中:

    父组件中

    //两个写法xiaowang和m1
    <Student v-on:xiaowang="getStudentName" @demo="m1"/>
    
        methods:{
            getStudentName(name,...params){
                console.log('App收到了学生名:',name,params)
                this.studentName = name
            }, 
                m1(){
                    console.log('demo事件被触发了')
                }
        },
    

    子组件中

    //可以写一个事件触发
     <button @click="sendStudentName">把学生名字传给App</button>
    
     <button @click="sendStudentName">把学生名字传给App</button>
         <button @click="unbind">解绑xiaowang事件</button>
         <button @click="death">销毁当前Student组件的实例(vc)</button>
     methods:{
         sendStudentName(){
           //触发Student组件实例身上的xiaowang事件
          //this.$emit('xiaowang',this.name,222,3333)
          //this.$emit('demo')
          //this.$emit('click')
         },
         unbind(){
           this.$off('xiaowang')//解绑一个自定义事件
           //this.$off(['xiaowang','demo'])//解绑多个自定义事件
           //this.$off()//解绑所有的自定义事件
         },
         death(){
           this.$destroy()//销毁了当前的Student组件的实例,销毁后所有的Student实例的自定义事件全部不奏效
         }
       },
    

    第二种方式:使用ref,在父组件中

    <Student ref="student" @click.native="show"/><hr>
    
        methods:{
            getStudentName(name,...params){
                console.log('App收到了学生名:',name,params)
                this.studentName = name
            },
        },
            mounted(){
                this.$refs.student.$on('xiaowang',this.getStudentName)//绑定自定义事件
                /* this.$refs.student.$on('xiaowang',(name,...params)=>{
                     console.log('App收到了学生名:',name,params)
                     this.studentName = name
                 }) */
                //this.$refs.student.$once('xiaowang',this.getStudentName)//绑定自定义事件:一次性
            }
    
    
    1. 若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。
    2. 触发自定义事件:this.$emit('atguigu',数据)
    3. 解绑自定义事件this.$off('atguigu')
    4. 组件上也可以绑定原生DOM事件,需要使用native修饰符。
    5. 注意:通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!

    **案例:**还是3.6的TODOList案例,结合3.6、3.7、3.8整合改良

    App.vue

    
    
    
    

    MyHeader.vue

    
    
    
    

    MyFooter.vue

    
    
    
    

    Item.vue、List.vue暂未做修改

    3.9、全局事件总线(GlobalEventBus)

    1. 一种组件间通信的方式,适用于任意组件间通信。
    2. 安装全局事件总线:main.js中
    new Vue({
    	el: '#app',
        render: h => h(App),
        //生命周期钩子,最先调用
    	beforeCreate() {
            /此时的this就是vm
    		Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
    	},
        ......
    }) 
    
    1. 使用事件总线:

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

         mounted(){
            this.$bus.$on('xxx',(data)=>{
             .....
            })
          }
        
      2. 提供数据this.$bus.$emit('xxxx',数据)

    2. 最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。(提供数据的组件中)

      beforeDestroy(){
           this.$bus.$off('xxx')//进行销毁
        },
      

    3.10、消息订阅与发布(pubsub)

    建议使用全局事件总线

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

    2. 使用步骤:安装pubsub:

      1. npm i pubsub-js

      2. 引入: import pubsub from 'pubsub-js'接收发送都需要)

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

      回调方法必须有两个参数

      • 第一个参数:代表订阅名(例如下面的’hello’)

      • 第二个参数:回调数据

      methods(){
        demo(_,data){......}
      }
      ......
      mounted() {
          //此处三种写法
          //第一种(不建议)
          this.pubId =  pubsub.subscribe('hello',function(msgName,data){
           console.log(this)//不使用箭头函数,此时为undefined
          })
          //第二种
          this.pubId =  pubsub.subscribe('hello',(msgName,data)=>{
           // console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data)
           console.log(this)//不使用箭头函数,此时为undefined
           
          })
          //第三种(建议):配合上面的methods
          this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
      }
      
    4. 提供数据pubsub.publish('xxx',数据)

    5. 最好在接收数据beforeDestroy钩子中,用PubSub.unsubscribe(pid)去取消订阅。

    3.11、nextTick

    1. 语法:this.$nextTick(回调函数)
    2. 作用:在下一次 DOM 更新结束后执行其指定的回调。
    3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。

    例:判断todo是否包含isEdit属性

    <button class="btn btn-edit" @click="handleEdit(todo)" v-show="!todo.isEdit" >编辑</button>
    
    //编辑
    handleEdit(todo) {
        //判断是否包含isEdit属性
        if (todo.hasOwnProperty('isEdit')) {
            //不包含则添加属性
            this.$set(todo, "isEdit", true);
        } else {
            todo.isEdit = true;
        }
        //下一轮
        this.$nextTick(function(){
            this.$refs.inputTitle.focus()
        })
    }
    //失去焦点回调(真正执行编辑逻辑)
    handleBlur(todo,e) {
        todo.isEdit = false;
        if(!e.target.value.trim()) return alert('输入不能为空!!!')
        this.$bus.$emit('updateTodo',todo.id,e.target.value)
    },
    

    3.12、Vue封装的过度与动画

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

    2. 图示:【Vue全家桶】--- 第三章:Vue脚手架(Vue CLI)_第2张图片

    3. 写法:

      第一步:准备好样式

      • 进入样式:
        1. v-enter:进入的起点
        2. v-enter-active:进入过程中
        3. v-enter-to:进入的终点
      • 离开样式:
        1. v-leave:离开的起点
        2. v-leave-active:离开过程中
        3. v-leave-to:离开的终点

    ​ 第二步:使用包裹要过度的元素,并配置name属性:

    
    	

    你好啊!

    ​ 备注:若有多个元素需要过度,则需要使用:,且每个元素都要指定key值。

    例:通过点击展示效果

    单元素

    
    
    
    
    >
    

    多元素

    
    
    
    
    >
    

    引入其他样式https://animate.style/
    【Vue全家桶】--- 第三章:Vue脚手架(Vue CLI)_第3张图片

    
    
    
    
    >
    
    

你可能感兴趣的:(前端,vue.js)