美文网首页
Vue组件化编程

Vue组件化编程

作者: 渚清与沙白 | 来源:发表于2023-11-01 10:02 被阅读0次

    组件:实现应用中局部功能代码和资源的集合
    模块:对外提供特定功能的js程序,一般是一个js文件
    模块化:应用中JS都是以模块来编写,这就一个模块化应用
    组件化:应用中的功能都是多组件的方式编写,这就是一个组件化应用

    组件命名规范

    1. 单个单词的名字
      (1). 纯小写,注册和使用时都用小写
      (2). 注册和使用时首字母大写,vue渲染时本身就是大写开头,可以与之呼应。

    2. 多个单词组成的名字
      (1). 全部小写,单词之间短横线连接
      (2). 脚手架环境下,注册和使用时每个单词首字母大写

    3. 创建组件时配置的组件名字name仅仅在开发工具中呈现。

    非单文件组件

    • 创建组件 Vue.extend({})
    // 创建组件
    const student = Vue.extend({
      name: 'student'
      template:` <div> <h1> {{ name }} </h1> </div>`,
      data(){
         return {
             name:'',
         }
       },
       methods: {
          copyName(){},
       },
    });
    
    # 简写形式  不需要写Vue.extend   内部源码进行了判断
    const student = {
       name: 'student'
       template:` <div> <h1> {{ name }} </h1> </div>`,
       data(){
           return {
              name:'',
           }
       },
       methods: {
           copyName(){},
       },
    };
    
    • 注册组件
      全局注册于局部注册
    // 全局注册
    Vue.component('student',student);  # 第一个参数是组件名,第二个参数是组件
    
    // 局部注册
    new Vue({
        data() {
           return {
              time: 1
           };
        },
       // 局部注册组件
       components:{ student }
    });
    
    • 使用组件
      使用组件时,采用自闭合写法需要再脚手架环境下使用。<student/>
    <div id="root"> 
       <student> </student>  
    </div>
    
    // cli环境下
    <template>
      <div>
        <student />
      </div>
    </template>
    

    单文件组件

    VueComponent

    VueComponent是一个构造函数

    1. 组件的本质是一个名为VueComponent的构造函数,是Vue.extend()生成的。

    2. 在使用组件时,Vue解析时会去创建组件的实例对象,Vue执行了new VueComponent(option)

    3. 每次执行Vue.extend时都会返回一个全新的VueComponent

    4. 在注册组件并使用组件标签后,才会创建VueComponent实例对象

    // 模拟 Vue.extend 生成VueComponent
    Vue.extend = function(extendOptions) {
      /*..........*/
      var sub = function VueComponent(options){
        this._init(options);
      }
      return sub;
      /*..........*/
    }
    
    1. this指向问题。
      (1)在组件配置中,data函数,methods中的函数、watch中的函数、computed中的函数,他们的this指向均是【VueComponent实例对象】
      (2)在new Vue(options)配置中,data函数,methods中的函数、watch中的函数、computed中的函数,他们的this指向均是【Vue实例对象】
    2. VueComponent实例对象称之为vc组件实例对象;Vue实例对象称之为vm。vm和vc都有数据代理和数据监视。vc配置项不可传eldata必须是一个函数vm配置项可以传el,data可以是函数,也可以是对象。
    3. VueComponent.prototype.__proto__Vue.prototype指向相同。存在 VueComponent.prototype.__proto__ === Vue.prototype 的关系。组件实例对象vc可以访问到Vue原型上的属性和方法
      image.png
    单文件配置

    对外暴露的是Vue.extend配置对象,这里没有写Vue.extend,Vue会帮助我们使用Vue.extend来创建VueComponenet实例对象

    export default {
      data(){
        return {};
      },
      methods:{
      }
    }
    

    Vue CLI

    CLI: command line interface
    全局安装@vue/cli:npm install -g @vue/cli
    创建项目:vue create xxx
    启动项目:vue run serve

    // index.html
    <!DOCTYPE html>
    <html lang="">
      <head>
        <meta charset="utf-8">
        <!-- 让IE浏览器以最高的渲染 级别渲染页面 -->
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <!-- 开启移动端的理想视口 -->
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        <!-- 配置页签图标 BASE_URL代表public目录 -->
        <link rel="icon" href="<%= BASE_URL %>favicon.ico">
        <!-- 配置网页标题 值是获取package.json中的name -->
        <title><%= htmlWebpackPlugin.options.title %></title>
      </head>
      <body>
        <!-- 当浏览器不支持js时,该标签的内容就会渲染 -->
        <noscript>
          <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly...</strong>
        </noscript>
        <!-- 容器 -->
        <div id="app"></div>
        <!-- built files will be auto injected -->
      </body>
    </html>
    
    render函数

    完整版vue是由vue核心模板解析器组成。模板解析器所占体积占用vue三分之一。如果使用完整版vue,webpack在打包时也会将模板解析器打包,由于webpack打包时会做翻译.vue解析模板的工作,所以模板解析器就没有存在的必要,于是就产生了没有模板解析器的精简版Vue。

    image.png
    new Vue({
        router,
        store,
        render: (h) => h(App),
    }).$mount('#app');
    
    1. render的本质是一个函数,render函数的参数是createElement,createElement也是一个函数。
      import Vue from 'vue'引入的是ES6模块化版本dist/vue.runtime.esm.js,这个版本的没有模板解析器,带有runtime的版本都没有模板解析器。在new Vue(options)时,配置对象template选项,就无法解析。

    2. render的作用是为了弥补不完整版本vue.js的功能:模板解析。
      引入了运行时版Vue,在new Vue(options)时,需要使用render函数

    3. vue-template-compiler插件 用于解析组件中的template

    4. vue.js与vue.runtime.xx.js的区别
      (1). vue.js是完整版的Vue,包含Vue核心和模板解析器
      (2). vue.runtime.xx.js是运行版的Vue,只包含Vue核心,不包含模板解析器

    5. 为什么要使用render函数?
      因为vue.runtime.esm.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容。

    配置文件

    vue.config.js是可选配置文件,使用了commonJS暴露。Vue会将该文件输送给webpack,与webpack中的配置进行合并。webpack是基于node的,nodeJS采用的模块化是commonJS。

    ref属性
    • 作用:用于给DOM元素或者子组件注册引用信息(id选择器的替代者)
    • 使用
      1. 用在HTML元素上,获取到的是真实的DOM元素
        <h1 ref="title">{{ msg }}</h1>
        获取真实DOM元素
        const dom = this.$refs.title
      2. 用在组件标签上,获取到的是组件实例对象
        <School ref="sch"></School>
        获取组件实例对象
        const dom = this.$refs.sch
    props配置项
    • 作用:让组件介绍外部传来的参数
    • 三种配置方式
    // 1. 简单接收  数组形式,无法指定数据类型
    props: ['name','age'],
    
    // 2. 仅限制数据类型
    props: {
        name:String,
        age:Number,
    },
    
    // 3. 指定多种类型
    props: {
         type: [String, Number],
    }
    
    // 4. 完整配置 require与default不必同时配置
    props: {
        name: {
          type:String,
          require:true,
        },
        age: {
          type:Number,
          default:60,
        }
    },
    

    props可以接收函数参数

    • 传参
      <Student name="zs" :age="18"/>
    • props中配置的参数是只读的,不能修改
      data中声明的数据名不可与props中的参数名相同。
      要修改props传过来的值,需要借助data。
    data(){
      return {
        myName:this.name, // props的数据优先于data,所以可以这样使用
      }
    },
    props:[ 'name' ]
    

    修改myName即可,但是不会影响name的值。

    mixins配置项
    • 作用:可多个组件共用的配置提取成一个混入对象
    • 使用方式:
      1. 定义混合
      // mixin.js
      export const mixin = {
        data(){...},
        methods:{...},
        mounted(){},
      }
      
      1. 使用混合
        全局混合:Vue.mixin(mixin);
        局部混合:mixins:[mixin]
    插件

    插件是一个必须含义install函数的对象

    • 功能:用于增强Vue
    • 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后得参数就是插件使用者传递的数据。
    • 定义插件
      // plugins.js
      export default {
        install(Vue){
            Vue.filter();// 添加过滤器
            Vue.directive();// 添加全局指令
            Vue.mixin();// 配置全局混入
            Vue.prototype.hello = ()=>{} // 添加实例方法
         }
      }
    
    • 使用插件
      import plugins from './plugins'
      Vue.use(plugins);
    组件的自定义事件
    • 子给父传递数据
      通过父给子传递函数类型的props实现
      通过父给子绑定自定义事件实现

    • 绑定自定义事件

      1. v-bind或@ 方式
        <Student @name="getName"/>
        <Student @name.once="getName"/> 触发一次事件
      2. ref 方式
        <Student ref="student"/>
        this.$refs.student.$on('name',getName)
        this.$refs.student.$once('name',getName) 触发一次事件
    • 触发事件
      this.$emit('name',this.name) 可以传递多个参数

    • 解绑事件
      this.$off('name') 解绑一个事件
      this.$off(['name','test']) 解绑多个事件 参数是数组类型
      this.$off() 解绑所有的自定义事件

    • 总结

      1. 组件的自定义事件是用于子组件给父组件传递数据
      2. 给谁绑定事件,就找谁触发事件
      3. 组件上也可以绑定DOM原生事件,需要使用native修饰符
      4. this.$refs.student.$on('name',callback),这种方式绑定事件时,callback要么配置在methods中,要么使用箭头函数,否则callback中使用了this,指向会出问题。
    全局事件总线
    • 作用:实现任意组件之间通信
    • 原理:给Vue的原型对象增加一个对象,一个具有$on、$off、$emit方法的对象,VueComponent和Vue的实例对象都可以访问到Vue的原型对象,这样在组件就可以使用自定义事件进行跨组件通信。
    • 实现:Vue.prototype.$bus = this;
    new Vue({
      render: h => h(App),
      beforeCreate() {
        Vue.prototype.$bus = this;
      },
    }).$mount('#app')
    
    • 使用:this.$bus.$on('xxx')this.$bus.$off('xxx')this.$bus.$emit('xxx')
      在组件的beforeDestory钩子函数中解绑当前组件注册的总线事件
    消息订阅与发布

    消息订阅与发布库:pubsub-js

    • 作用:实现任意组件之间通信
    • 订阅消息:pubsub.subscribe('xxx',(msgName,params)=>{})
    • 发布消息:pubsub.publish('xxx',params)
    • 取消订阅:pubsub.unsubscribe(pubId)
    this.$nextTick()

    this.$nextTick()中的回调在下一次DOM更新完毕之后再执行

    Vue控制动画和过渡

    <translation name="hello" :appear="true"></translation>
    <translation/>标签不是真实的DOM元素,只能控制单个DOM元素
    <translation-group/> 可以控制多个DOM元素,但是必须给元素设置key属性

    • 动画
      定义css动画,vue通过v-enter-active等和translate标签来实现
    <template>
      <div>
        <button @click="show = !show">显示/隐藏</button>
        <!-- name 决定class的名称前缀; appear 决定第一次显示是否执行动画 -->
        <transition name="move" :appear="true">
          <h1 v-show="show">渚清与沙白</h1>
        </transition>
      </div>
    </template>
    
    <script>
    export default {
        name: "Test",
        data() {
          return {
            show: true,
          };
        },
    };
    </script>
    
    <style scoped>
      h1 {
        background-color: coral;
      }
    
      /** 进入时激活的动画 */
      /** 不设置name="move",这里使用 v-enter-active */
      .move-enter-active {
        animation: move 1s linear;
      }
      /** 离开时激活的动画 */
      .move-leave-active {
        animation: move 1s linear reverse;
      }
      @keyframes move {
        from {
          transform: translateX(-100%);
        }
        to {
          transform: translateX(0);
        }
      }
    </style>
    
    • 过渡
      不需要配置动画(@keyframes)
      v-enter
      v-enter-to
      v-leave
      v-leave-to
    <template>
      <div>
        <button @click="show = !show">显示/隐藏</button>
        <!-- name 决定class的名称前缀 appear 决定第一次显示是否执行动画 -->
        <transition name="move" :appear="true">
          <h1 v-show="show">渚清与沙白</h1>
        </transition>
      </div>
    </template>
    
    <script>
    export default {
      name: "Test",
      data() {
        return {
          show: true,
        };
      },
    };
    </script>
    
    <style scoped>
      h1 {
        background-color: cornflowerblue;
      }
      /** 进入的起点、离开的终点 */
      .move-enter, .move-leave-to {
        opacity: 0;
        transform: translateX(-100%);
      }
    
      .move-enter-active, .move-leave-active {
        transition: all 0.5s linear;
      }
    
      /** 进入的终点、离开的起点 */
      .move-enter-to, .move-leave{
        opacity: 1;
        transform: translateX(0);
      }
    </style>
    
    • animation.css动画库
    • 引入
      import 'animation.css'
    • 配置库
      <transition
          name="animate__animated animate_bounce"
          :appear="true"
          enter-active-class="animate__fadeInUp"
          leave-active-class="animate__fadeOutDown"
        >
          <h1 v-show="show">渚清与沙白</h1>
        </transition>
    
    配置代理

    发送Ajax请求有哪些方式?

    1. XMLHttpRequest
    2. jQuery
    3. axios
    4. fetch
      jQuery和axios是对XMLHttpRequest的封装。XMLHttpRequest是js内置的对象。fetch和XMLHttpRequest平级,浏览器window对象上就有XMLHttpRequestfetch
      fetch:双层Promise、不支持IE
      **** CORS **** Access-Control-Allow-Origin ****跨域,违背同源策略。同源策略规定协议名主机名端口号必须一致。
      跨域是客户端请求发送成功,服务器也收到数据,并且还返回了数据,浏览器发现跨域,将数据留下来了。
    • 解决跨域
      1. 后端解决。服务器响应头配置特定参数,但是不安全。
      2. jsonp 只能解决get请求的跨域问题,其他请求解决不了
      3. 前端配置代理服务器
        代理服务器端口跟前端服务器所处位置一样,端口一样。在发起请求时,先找代理服务器,代理服务器转发给服务器,服务器将响应数据发送给代理服务器,代理服务器再转发给前端服务器。当请求资源前端服务器本身就有,不会走代理服务器。
        服务器与服务器之间通信不用Ajax,ajax是前端与服务器的通信工具。

    开启代理服务器

    1. nginx
    2. 借助Vue CLI 脚手架
    • 脚手架配置代理
    1. 方式一
      vue.config.js脚本中配置
      devServer: {
        proxy: 'http://localhost:5000',// 接口服务器的地址
      },
    

    优点:配置简单,请求资源时直接发送给前端(8080)即可
    缺点:不能配置多个代理,不能灵活控制是否走代理
    工作方式:当请求了前端不存在的资源时,该请求会转发给服务器。(优先匹配前端资源)

    1. 方式二
      在vue.config.js脚本中配置
      // /api: 请求前缀 方式二
      // 收到请求时发现有前缀才会转发到接口服务器  否则不做转发
      devServer:{
        proxy: {
           https: false,
          '/api': {//控制是否走代理
            target: 'http://localhost:5000',
            changeOrigin: true,// 用于控制请求头的host值
            ws: true,// 用于支持websocket
            pathRewrite: {// 重写地址
              '^/api': ''// 正则匹配,匹配所有以/api开头的请求路径
            }
          },
          '/demo':{// 配置多个代理
            target: 'http://localhost:5001',
            changeOrigin: true,// 用于控制请求头的host值
            pathRewrite: {// 重写地址
              '^/demo': ''// 正则匹配,匹配所有以/demo开头的请求路径
            }
          }
        }
      }
      // 请求 http://localhost:5000/api/user/login  无需配置pathRewrite
      // 请求 http://localhost:5000/user/login  需配置pathRewrite
    

    changeOrigin: true:服务器收到的请求中请求头的host是http://localhost:5000/,与服务器端口一致
    changeOrigin: false:服务器收到的请求中请求头的host是http://localhost:8080/,与前端端口一致
    优点:可以配置多个代理,可以灵活控制请求是否走代理
    缺点:配置繁琐,请求接口时必须加前缀

    • vue-resource
      vue1.0阶段使用的请求库
      vue中的插件库,vue-resource也是对XmlHttpRequest的封装,与axios的用法一致。
      this.$http.get()
    插槽
    • 默认插槽
      <slot></slot>
      <slot> 这是一个默认插槽 </slot>
    • 具名插槽
      <slot name="top"></slot> 设置名字
      <ul slot="top"></li> 使用,将ul放入top插槽
      <template #footer> </template>
    // 定义插槽 插槽名是title,默认值是title变量值
    <slot name="title">{{title}}</slot>  
    
    // 使用组件 传递title
    <el-collapse-item title="一致性 Consistency" name="1">
        <div>与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;</div>
    </el-collapse-item>
    
    // 使用插槽 替换title
    <template slot="title">
         <div>与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;</div>
    </template>
    

    2.6.0 新增
    跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符#。例如 v-slot:header 可以被重写为 #header

    定义具名插槽

    <template>
      <div>
        <p> 我是子组件 </p>
        <solt></solt>
        <solt name='top'></solt>
      </div>
    </template>
    

    引用插槽v-solt:

    // v-slot:top写法只能在template标签中使用
    <template v-slot:top>
       <h1>1</h1>
       <h1>2</h1>
       <h1>3</h1>
    </template>
    

    引用插槽v-solt:header的简写形式#header

    // 简写
    <template>
      <h1>1</h1>
      <template #top>
          <h1>2</h1>
      </template>
    </template>
    
    • 作用域插槽
      数据在定义插槽的组件(子组件)中,根据数据生成不同的DOM结果需要组件的使用者来决定(父组件),
    // 父组件
    <category>
      <template slot-scope="scopeData">// slot-scope=""和scope=“”均可,目前已过时!
        <h1>{{scopeData}}</h1>
      </template>
    </category>
    // v-slot
    <category>
      <template  v-slot="scopeData">
        <h1>{{scopeData}}</h1>
      </template>
    </category>
    
    // 子组件
     <template>
      <div>
        <slot :datas="list"></slot>
      </div>
     </template>
    

    在 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即v-slot指令)。它取代了 slot 和 slot-scope。

    • 动态插槽名
    <base-layout>
      <template v-slot:[dynamicSlotName]>
        ...
      </template>
    </base-layout>
    

    组件间通信

    1. props
    2. 自定义事件
    3. 全局事件总线
    4. 消息订阅与发布
    5. 插槽
    6. vuex

    相关文章

      网友评论

          本文标题:Vue组件化编程

          本文链接:https://www.haomeiwen.com/subject/opdvidtx.html