vue 基础(七)

Vue组件基础和Ref对象

组件

概念: 组件系统是 Vue 的一个重要概念,Vue允许我们将代码拆分独立成一些将小型的可复用模块。这些模块就被成为组件,使用这些组件就可以构建一个大型项目。在Vue中组件分为全局组件私有组件

组件的创建

  • 全局组件

概念: 注册在Vue构造函数中的组件,在Vue实例任何地方任何组件中都可以使用

语法: Vue.component('组件名', {组件的配置对象})

  • 私有组件

概念: 通过components配置选项注册在Vue实例对象或其他子组件内部,只能在注册的父组件内部使用。

语法: Vue配置选项和组件配置选项都支持components属性 components: {组件名: { 组件配置选项 }}

注意: template属性指定DOM模板结构中必须有且仅有一个根DOM元素!

组件的data配置选项

概念: 组件设计初衷就是将哪些独立的可复用的代码块封装起来,因为对象是引用数据类型如果直接将组件的data属性设置为对象的话。同一个组件在复用时会导致多个组件同时读写同一个对象,严重的影响了组件可复用性和独立性。为了解决这个问题Vue明确规定组件的data不可以是个对象,而是一个返回data对象的工厂模式函数。

语法:

// 普通函数
  Vue.component('gec-title', {
            template: `
            

{{name}}

`, data() { return { name: '小明', age: 18 } } }) // 箭头函数 Vue.component('gec-title', { template: `

{{name}}

`, data: () => ({ name: '小明', age: 18 }) })

单项数据流

概念: 在Vue中组件之间是单项数据流的。单项数据流规定子组件不可以直接访问父组件的数据,只能通过props属性让父组件把数据传递给子组件。并且子组件不可以直接修改父组件传递给子组件的数据

props的使用

概念: 组件可以通过特殊的配置选项props给自身设置自定义属性,父组件就可通过props属性传值将父组件的数据传递给子组件,因为Vue是单项数据流子组件不可以修改props(props是只读的)

注意:组件的data属性与props属性不能同名



    

{{age}}

反向传值

因为Vue是单项数据流的,规定只允许父组件向子组件传递状态,而不允许子组件直接修改父组件传递过来的状态。Vue提供了自定义事件API,通过父组件监听子组件自定义事件, 当子组件想要修改父组件的状态时会通过 $emit 方法触发自定义事件。父组件对应监听子组件自定义事件的回调函数就会被触发,这样父组件自身的方法就会相应的去修改自身的状态。子组件的props就会更新

语法: $emit('自定义事件名', 向父组件回调函数传递参数)

注意: $emit只接受两个参数,参数一触发父组件监听的指定事件名,参数二(可选)向父组件监听事件回调函数传递的数据

案例: $emit的使用

 

Vue脚手架安装使用

  • Step1 在系统变量中安装Vue脚手架工具vue-cli
#全局安装vue-cli环境配置
npm install -g @vue/cli

[图片上传失败...(image-f5a03d-1623249421811)]

  • Step2访问到指定目录,使用vue指令创建新项目
#全局安装完毕后,以后 vue create 项目名称 搭建项目
vue create project_name   

[图片上传失败...(image-3c5470-1623249421811)]

  • Step3执行创建vue项目指令时会返回一个vue项目配置询问,先直接使用默认vue 2.0 模板
? Please pick a preset: (Use arrow keys)
> Default ([Vue 2] babel, eslint) #使用默认vue 2.0 模板
  Default (Vue 3 Preview) ([Vue 3] babel, eslint) #使用默认vue 3.0 模板
  Manually select features      #自定义模板

[图片上传失败...(image-58dc1f-1623249421811)]

  • Step4 安装完毕后
# 访问新创建的项目目录
cd project_name
#启动测试用服务开发指令
npm run serve
#项目开发完毕打包指令
npm run build

Vue-cli项目结构


webpack-demo
|- /public // 公共目录,这个目录中的文件不会被webpack打包而是作为一个静态目录
// 放置在 public 目录下或通过绝对路径被引用。这类资源将会直接被拷贝,而不会经过 webpack 的处理。
|- index.html // vue中 html模板文件
|- /src // 整个项目代码开发目录
|- main.js // 项目的入口文件
|- babel.config.js // webpack babel-loader配置文件
|- package.json // 项目的配置描述文件
|- README.md // 项目的readme文件
+|- vue.config.js // 可自定义Vue webpack相关配置的文件

局部关闭 ESlint 校检

ESlint 是一个js代码检测工具,约束开发人员的代码风格,如果想具体了解,请查阅其文档

相关文档: https://blog.csdn.net/qq_39557024/article/details/107519531

public 文件夹

概念: 任何放置在 public 文件夹的静态资源都会被简单的复制,而不经过 webpack。你需要通过绝对路径来引用它们。

注意: 我们推荐将资源作为你的模块依赖图的一部分导入,这样它们会通过 webpack 的处理并获得如下好处:

  • 脚本和样式表会被压缩且打包在一起,从而避免额外的网络请求。

  • 文件丢失会直接在编译时报错,而不是到了用户端才产生 404 错误。

  • 最终生成的文件名包含了内容哈希,因此你不必担心浏览器会缓存它们的老版本。

public 目录提供的是一个应急手段,当你通过绝对路径引用它时,留意应用将会部署到哪里。如果你的应用没有部署在域名的根部,那么你需要为你的 URL 配置 publicPath 前缀,在 public/index.html 或其它通过 html-webpack-plugin 用作模板的 HTML 文件中,你需要通过 <%= BASE_URL %> 设置链接前缀:



在js文件中 使用process.env.BASE_URL作为pubulic文件的前缀




publicPath配置实在项目的根目录下vue.config.js中设置publicPath选项就好了

module.exports = {
    publicPath: process.env.NODE_ENV === 'production'
      ? '/production-sub-path/' //真实开发的话,如果你的项目存放在公司域名二级路径下 只需要将 /production-sub-path/改为 /公司二级路径/就可以了
      : '/'
  }

webpack 相关(了解)

介绍: 在vue-cli中简单的配置webpack方式就是在Vue项目的根目录下创建vue.config.js文件。这个通过配置这个文件中 module.exports 公开的对象实现对Vue Webpack进行修改。

  1. 指定项目静态资源模块的相对路径
  2. 指定打包后文件的目录(默认dist文件)
  3. assets文件的目录
  4. 多页面应用开发
  5. css模块化 loader等
  6. 给项目添加Webpack plugin
  7. 配置当前项目的开发测试服务器
// vue.config.js
module.exports = {
    publicPath: process.env.NODE_ENV === 'production'
        ? '/production-sub-path/' //真实开发的话,如果你的项目存放在公司域名二级路径下 只需要将 /production-sub-path/改为 /公司二级路径/就可以了
        : '/',
    devServer: { // 服务器代理,当请求了代理设置的路径时 会自动跳转到指定服务器上,解决跨域问题
        proxy: {
            "/search": {
                target: 'http://musicapi.leanapp.cn/',
                changeOrigin: true
                // 当你请求 /search?123123 时 会代理到 'http://musicapi.leanapp.cn/search?123123'
            }
        }
    }
}

了解Vue-cli src目录结构

介绍: 在src文件中main.js是整个项目的入口文件,也是实例化Vue对象的地方

因为vue-cli是模块化开发,所以整个项目不适用< script >标签引入Vue支持而是使用模块化依赖模式通过import引入Vue对象

import Vue from 'vue'
import App from './App.vue' // 引入单文件App组件

Vue.config.productionTip = false
// 实例化Vue
new Vue({
  render: h => h(App)  
  // render是template字符串模板的替代方案,render是一个函数函数接收一个参数(createElement)
  // 这个参数可以将组件生成为一个Vue DOM节点渲染在页面上
  // 所以上面这句化等价于 template: '' 
}).$mount('#app')

// 如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素。
// 这时可以使用 vm.$mount() 手动地挂载一个未挂载的实例。

认识单文件组件

我们观察下面的代码,在Vue实例中添加了局部组件App,如果说除了Vue实例以外其他组件可能也需要注册App局部组件的话。我们推荐将App抽离出来提供给其他组件复用

new Vue({
    el: '#app',
    components: {
        App: {
            props: ['name','age'],
            data() {
                return {
                    address: 'bj'
                }
            },
            template: `
            

用户:{{name}} 年龄:{{age}}

地址:{{address}}

` } } })

抽离后

const App = {
    props: ['name','age'],
    data() {
        return {
            address: 'bj'
        }
    },
    template: `
    

用户:{{name}} 年龄:{{age}}

地址:{{address}}

` } new Vue({ el: '#app', components: { App } })

我们在开发中推荐使用模块化开发,建议将每个可复用的组件单独封装成一个js模块,通过import引入其他文件中复用。这样的好处是便于维护更新让项目的结构更明确。

// 将App组件封装成一个js模块
// App.js
export default {
    props: ['name','age'],
    data() {
        return {
            address: 'bj'
        }
    },
    template: `
    

用户:{{name}} 年龄:{{age}}

地址:{{address}}

` } // 其他组件或实例注册App组件 import App from './App' new Vue({ el: '#app', components: { App } })

Vue为了简化template字符串模板的开发(使用字符串写HTML语法js无法格式化代码,编译器无法对模板进行补全和检查),Vue提供了一个.vue文件简化了js文件创建单文件组件时template字符串模板开发不便。.vue文件单独的将template选项抽离出来以HTML的形式进行开发。

上面的App.js就可以转化为:

// App.vue
// template 被抽离出来变成了一个独立的标签,内部本来使用字符串模板代码变成HTML语法



注意

  1. .vue文件不仅支持template标签指定组件的模板样式和script 公开当前模板配置选项,还支持style标签内置的设置当前组件的样式,而且style标签支持使用sass\less\stylus预编译语言





  1. 建议使用.vue创建组件时,组件名与文件名一致并且使用每个单词首字母大写的命名方法。例: HelloWorld.vue、DemoComponent.vue

Props验证

概念:在开发中我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这一模式会在开发中帮开发人员捕获大量的异常。

语法: props可以是一个数组,数组中的每一项都是当前组件的props属性名。props属性还是是一个对象为每个指定的props属性指定其验证规则以及默认值

props: {
        // 当前组件的propsA属性必须是Number数据类型或者为空(可忽略)
        propA: Number, 
        // propB与propA等价
        // prop为指定数据类型只需要设置该属性type值为对应数据类型的构造函数
        propB: {
            type: Number
        },
        // prop属性可以设置为必要属性,渲染该组件时必须给该属性传值并且不可为空
        propC: {
            type: Number,
            required: true 
        },
        // prop属性支持默认值,当没有给该prop传递属性是,该属性则会使用默认值
        // 注意: 默认值优先级小于required
        propD: {
            type:Number,
            default: 15
        },
        propE: {
          type: Object,
          // 对象或数组默认值必须从一个工厂函数获取
          default: function () {
            return { message: 'hello' }
          }
        }
    }

Props验证规则

 props: {
        // 通过构造函数指定prop数据类型
        propA: Number,
        propB: Boolean,
        propC: String,
        propD: Array,
        propE: Object,
        propF: Symbol,
        propG: RegExp,
        propH: Date,
        propI: Cat, // 可以指定任何构造函数作为prop的type,当前prop接收到的值必须是当前指定构造函数的实例对象
        propJ: Function
        // prop验证支持 多个可能的类型
        propK: [String, Number], 
        // 自定义验证规则,不满足验证条件是return false
        propL: {
          validator(val) {// val 传入到 propL属性的值
            if (typeof val === "string") {
              if (/fuck/gi.test(val)) {
                console.error("组件ComponentA中 属性 PropL包含敏感词汇!");
              } else {
                return true;
              }
            } else {
              console.error("数据必须是字符串");
            }
            return false;
          }
        }
    }

动态组件

概念: VUe 提供了一个标签component,该标签可以使用 is attribute 来切换不同的组件:

在动态组件上使用 keep-alive

概念: 当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题。

 

注意: 在上面的案例中如果没有使用keep-alive缓存失活的组件,那么失活的组件将被丢弃(卸载),组件切换时每次都是挂载一个全新的组件

异步组件(了解)

介绍: 在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。例如:

Vue.component('async-example', function (resolve, reject) {
 setTimeout(function () {
   // 向 `resolve` 回调传递组件定义
   resolve({
     template: '
I am async!
' }) }, 1000) })

如你所见,这个工厂函数会收到一个 resolve 回调,这个回调函数会在你从服务器得到组件定义的时候被调用。你也可以调用 reject(reason) 来表示加载失败。这里的 setTimeout 是为了演示用的,如何获取组件取决于你自己。一个推荐的做法是将异步组件和 webpack 的 code-splitting 功能一起配合使用:

Vue.component('async-webpack-example', function (resolve) {
 // 这个特殊的 `require` 语法将会告诉 webpack
 // 自动将你的构建代码切割成多个包,这些包
 // 会通过 Ajax 请求加载
 require(['./my-async-component'], resolve)
})

你也可以在工厂函数中返回一个 Promise,所以把 webpack 2 和 ES2015 语法加在一起,我们可以这样使用动态导入:

Vue.component(
   'async-webpack-example',
  // 这个动态导入会返回一个 `Promise` 对象。
  () => import('./my-async-component')
)

当使用局部注册的时候,你也可以直接提供一个返回 Promise 的函数:

new Vue({
 // ...
 components: {
   'my-component': () => import('./my-async-component')
 }
})

如果你是一个 Browserify 用户同时喜欢使用异步组件,很不幸这个工具的作者明确表示异步加载“并不会被 Browserify 支持”,至少官方不会。Browserify 社区已经找到了一些变通方案,这些方案可能会对已存在的复杂应用有帮助。对于其它的场景,我们推荐直接使用 webpack,以拥有内置的头等异步支持。

懒加载状态 (2.3.0+ 新增)

这里的异步组件工厂函数也可以返回一个如下格式的对象:

const AsyncComponent = () => ({
 // 需要加载的组件 (应该是一个 `Promise` 对象)
 component: import('./MyComponent.vue'),
 // 异步组件加载时使用的组件
 loading: LoadingComponent,
 // 加载失败时使用的组件
 error: ErrorComponent,
 // 展示加载时组件的延时时间。默认值是 200 (毫秒)
 delay: 200,
 // 如果提供了超时时间且组件加载也超时了,
 // 则使用加载失败时使用的组件。默认值是:`Infinity`
 timeout: 3000
})

Ref

概念: Vue给组件元素提供了一个ref属性,绑定了ref属性的组件元素可以在当前vue实例对象中通过$refs访问其真实DOM节点(标签元素)或实例对象(组件)。

在原生html标签中使用ref

语法:

当前组件内部 this.$refs.变量名 访问其真实DOM节点

 

在组件中中使用ref

语法 当前组件内部 this.$refs.变量名 访问这个子组件的实例对象,可以获取这个组件实例的属性和方法(尽量避免使用该模式,因为他会增加组件间的耦合性)





注意:

  1. vue实例中每个标签或组件都可以设置ref属性,绑定了ref属性的元素可以有任意个

text

// 这时可以在组件中通过 this.$refs不同的变量名访问对应的DOM元素
  1. ref配合列表渲染(v-for)使用时,$refs返回值为包含列表渲染出来的所有元素的一个数组
    
// 与v-for同级的ref 返回值都是列表渲染出来当前元素数组集合

//v-for 内部的ref 返回值也是列表渲染出来当前元素数组集合 {{num}}-span 没用的a {{num}}

你可能感兴趣的:(vue 基础(七))