首页 > 编程语言 >Vue组件化编程

Vue组件化编程

时间:2024-07-01 19:21:00浏览次数:1  
标签:Vue name 编程 js vue 组件 data

Vue组件化编程

组件的定义:用来实现局部(特定)功能效果的代码集合(html/css/js/image)

为什么使用组件:一个界面的功能很复杂

作用:复用代码,简化项目编码,提高运行效率

组件分为非单文件组件和单文件组件,在开发中一般使用单文件组件

非单文件组件

1.组件的基本用法

组件的使用步骤有三步:定义组件、注册组件、使用组件

<body>
<div id="root">
  <school></school>
  <hr/>
  <student></student>
</div>
<script>
  //创建组件
  const school = Vue.extend({
    template:`
    <div>
    <h2>学校名:{{schoolName}}</h2>
    <h2>学校地址:{{address}}</h2>
    </div>
    `,
    data(){
      return{
        schoolName:"sdgsxy",
        address:"yantai"
      }
    }
  })
  const student = Vue.extend({
    template:`
    <div>
    <h2>学生名:{{studentName}}</h2>
    <h2>学生年龄:{{age}}</h2>
    </div>
    `,
    data(){
      return{
        studentName:"sdgsxy",
        age:18
      }
    }
  })
​
  new Vue({
    el:"#root",
    components:{
      school:school,
      student:student
    }
  })
</script>
</body>

1.定义组件

使用Vue.extend(options) 创建组件,其中 options 和 new Vue 时传入的options 几乎一样,区别点:

  • 但是不能写 el配置,因为最终所有组件都要经过一个vm的管理,由vm中的el决定服务于哪个容器

  • data 必须写成函数,为了避免组件被复用时,数据存在引用关系

  • 需要使用 template 配置组件结构

2.注册组件

在vm中配置 components 对象,用键值对的方式注册组件,值就是定义组件时的组件名,键是使用组件时用的名字

3.使用组件

通过注册组件时 定义的名字 作为标签

 

在注册组件时,还可以进行全局注册

//Vue.component('school',school)

 

注意点:

  • 关于组件名

    • 一个单词组成

      • 首字母小写 (school)

      • 首字母大写(School)

    • 多个单词组成

      • kabab-case命名(my-school)

      • CamelCase 命名 (MySchool) 需要脚手架支持

    组件名尽可能回避HTML中已有的元素名称,例如 h2、h3等

    可以使用name配置项指定组件在vue开发者工具中的名字

  • 关于组件标签

    • 第一种写法 <school></school>

    • 第二种写法 <school/>

      没有使用脚手架的话,第二种写法会导致后续组件无法渲染

  • 定义组件时可以简写

    const school = Vue.extend(options) ==> const school = options

 

2.组件的嵌套

<body>
<div id="root">
  <app></app>
  <hr/>
</div>
<script>
  //创建组件
  const student = Vue.extend({
      template:`
    <div>
    <h2>学生名:{{studentName}}</h2>
    <h2>学生年龄:{{age}}</h2>
    </div>
    `,
      data(){
          return{
              studentName:"sdgsxy",
              age:18
          }
      }
  })
  const school = Vue.extend({
    template:`
    <div>
    <h2>学校名:{{schoolName}}</h2>
    <h2>学校地址:{{address}}</h2>
      <student></student>
    </div>
    `,
    data(){
      return{
        schoolName:"sdgsxy",
        address:"yantai"
      }
    },
    components:{
        student
    }
  })
  const hello = Vue.extend({
      template:`
        <div>
            <h1>欢迎访问</h1>
        </div>
      `
  })
  const app = Vue.extend({
      template:`
        <div>
        <school></school>
        <hello></hello>
        </div>
      `,
      components:{
          school,
          hello
      }
  })
  new Vue({
    el:"#root",
    components:{
      app
    }
  })
</script>
</body>

组件嵌套就是把子组件的注册和使用 拿到父组件中

在实际开发中一般在 vm中只注册一个 app组件,其他组件都是它的子组件

 

3.VueComponent

  • school组件本质是一个名为 VueComponent的构造函数,且不是程序员定义的,时Vue.extend生成的

  • 我们只需要写<school></school> ,vue 解析时会帮我们创建school组件的实例对象

    即Vue帮我们执行的 new VueComponent(options)

  • 需要注意的是每次调用 Vue.extend 返回的都是一个全新的VueComponent

  • 关于this的指向

    • 组件中

      • data、method、watch、computed中的函数,他们的this均是VueCompontent实例对象

    • new Vue(options) 中

      • data、method、watch、computed中的函数,他们的this均是Vue实例对象

  • VueComponent 的实例对象,以后简称vc,vue实例对象简称vm

 

Vue和VueComponent的关系

VueComponent和Vue的关系:

VueComponent 的原型对象 的 原型对象 就是 Vue的原型对象

为什么要有这个关系?

为了让组件实例对象可以访问到Vue原型上的方法和属性

 

单文件组件

单文件组件是一个个的 vue文件,浏览器不能直接处理 vue文件,需要借助 webpack或脚手架

在vue文件中,主要写三个标签

  • template 里面写组件的结构

  • script 里面写组件交互相关代码

  • style 组件的样式

需要注意 template 不参与渲染,所以在 该标签中需要有一个根标签

<template>
    <div class="demo">
        <h2>学校名称:{{schoolName}}</h2>
        <h2>地址:{{address}}</h2>
    </div>
</template>
​
<script>
    const school = Vue.extend({
        data(){
            return{
                schoolName:"sdgsxy",
                address:"yantai"
            }
        }
    })
</script>
​
<style>
  .demo{
    background-color: orange;
  }
</style>

三个标签写完后,需要对 script 标签的内容进行 暴露,然后别的文件才能引入该文件使用

使用 默认暴露,并且可以 省略 Vue.extend

<script>
    export default{
        name:'School',
        data(){
            return{
                schoolName:"sdgsxy",
                address:"yantai"
            }
        }
    }
</script>

定义好自己的组件后 一定要写一个 App.vue 来引入自己的组件

<template>
    <div>
        <!-- 使用组件 -->
        <School/>
        <Student/>
    </div>
​
</template>
​
<script>
    //引入组件
    import School from './School.vue'
    import Student from './Student.vue'
   
    export default {
        name:'App',
        //注册引入的组件
        components:{
            School,
            Student
        }
    }
</script>

 

有了三个组件 App.vue、School.vue、Student.vue,需要用vm去使用他们,所以还需要一个 js文件去创建vm

import App from './App.vue'
​
new Vue({
    el:'#root',
    template:`<App/>`,
    components:{
        App
    }
})

有了 vm 还缺一个 容器 root,所以还需要创建一个 html文件作为容器

<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <title>测试单文件组件</title>
    
</head>
<body>
    <div id="#root"></div>
    <!-- 引入vue -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
    <!-- 引入 main.js -->
    <script type="text/javascript" src="./main.js"></script>
</body>
</html>

 

关于vue脚手架

需要安装node.js

执行 npm install -g @vue/cli 安装最新的脚手架

创建一个vue项目

  • vue create xxxx(xxxx是项目名)

  • npm run serve 启动项目,脚手架版本为2.9.6的话命令是 npm run dev

 

分析 vue项目

  • babel.config.js ES6转 ES5 的配置文件

  • package.json 配置包名、版本、依赖等,常用命令也写在该文件中

  • package-lock.json 包版本控制文件

  • src

    • main.js 网页的入口,执行完 npm run serve 后直接执行main.js

    • App.vue 所有组件的父组件

    • assets 该目录存放网页的静态资源

    • components 该目录存放所有子组件

  • public

    • favicon.ico 网页页签图标

    • index.html 网页的界面

render函数

通过vue-cli构建的项目中的main.js 和 自己写的main.js 的区别

import Vue from 'vue'      
import App from './App.vue'          

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
import App from './App.vue'

new Vue({
    el:'#root',
    template:`<App/>`,
    components:{
        App
    }
})

可以很明显地看到 这两个文件对于 App组件的注册以及模板的构建采取了两种不同的方式

如果把我们写main.js 的方式 放到该项目中去运行,会报如下错误

image-20240624184328604

错误:你正在使用一个 运行版本 的 vue,没有模板解析器。也就是说引入的vue 是一个残缺的vue

两条解决方案:

  • 使用rander 函数

  • 引入完整版vue

项目中 引入vue使用的语句是 import Vue from 'vue' ,它引入的是 node_modules 目录下的vue

image-20240624185301974

因为没有指定具体的文件,所以会去package.json 文件中去找到底引入哪个文件

image-20240624185430193

因为使用的是vue 模块化引入 所以到底引入哪个文件是由 module 来控制的,由此可见 引入的是 dist/vue.runtime.esm.js 它就是 残缺版的vue

完整版 vue 是在 dist下的 vue.js,这是第二种解决方案

第一种解决方案是使用rander函数,他的完整版写法如下

new Vue({
  //render: h => h(App),
  // template:`<App/>`,
  // components:{
  //   App
  // }
  render(createElement){
      return createElement('h1',"你好啊")
  },
  //template:'<h1>你好啊</h1>'
}).$mount('#app')

render接收一个参数,这个参数是 函数,这个函数接收的参数是 界面元素,这里是 标签名和内容

把render 简写之后

render:q => q('h1',"你好啊")

由于 h1是html 的内置元素,所以需要传两个参数,如果参数是组件那么直接传入就行

 

那么为什么要设计和引入 残缺版的vue呢?

Vue 中包含 Vue的核心 + 模板解析器,如果Vue不创造精简版Vue,那么webpack打包后生成的文件里就包含模板解析器。这时它出现在这就不太合适了

 

使用vue.config.js 可以对脚手架进行个性化配置

 

ref属性

  • 作用:被用来给元素或子组件注册引用信息

  • 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象

  • 使用方式:

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

    • 获取:this.$refs.xxx

<template>
  <div>
    <h1 v-text="msg" ref="title"></h1>
    <button ref="btn" @click="showDOM">点击输出</button>
    <School ref="sch"></School>
  </div>
</template>

<script>
import School from "./components/School.vue";
export default {
  name:'App',
  // eslint-disable-next-line vue/no-unused-components
  components:{School},
  data(){
    return{
      msg:"你好欢迎"
    }
  },
  methods:{
    showDOM(){
      console.log(this.$refs.title)
      console.log(this.$refs.btn)
      console.log(this.$refs.sch)
    }
  }
}
</script>

image-20240624201645877

输出的三个分别是DOM、DOM、组件实例对象

 

props 配置项

之前向页面展示数据都是把数据写到 data函数中如果想要更改数据,就要修改data里面的数据。但我们知道 组件的一大特点就是能够复用,如果别人想要复用你的组件,但是想展示的数据不同。那么该如何解决呢?

这时就可以用props配置项来接收参数,传递参数的地方就是 使用该组件的地方

<template>
  <div>
    <h1>{{msg}}</h1>
    <Student name="李四" age="80"></Student>
  </div>
</template>

传递方在组件使用时 通过属性传递参数 ,这些属性也可以用v-bind 绑定

<template>
  <div>
    <h2>学生姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <button @click="addAge">点击增加年龄</button>
  </div>
</template>
<script>
export default {
    /* eslint-disable */
    name:"Student",
    data(){
        return{
            //name:'张三',
            //age:18,
        }  
    },
    methods:{
        addAge(){
            this.age++
        }
    },
    props:['name','age']
}
</script>

接收方 通过 props 接收参数,需要注意的是 在data中不能再把数据写死

props是一个数组,里面的值就是 传入的参数名,顺序无所谓

props:['name','age'] 这种方式 是 简单接收,还可以对传入的参数进行限制

props:{
	name:String,
	age:Number
}

写成对象的形式,限制传入参数的类型

还可以限制的更详细一些

props:{
    name:{
        type:String,
        required:true
    },
    age:{
        type:Number,
        default:18
    }
}

其中 type 是对类型的限制,required限制必须传入,default设置默认值

 

注意点: 接收到的props 是不能修改的,如果业务需求要改,可以在data里设置一个属性,并把接收到的参数赋值给他,然后修改data中的值就可以了

data中的属性和 props 中的属性 如果相同,props的优先级更高

data(){
    return{
        //name:'张三',
        //age:18,
        myAge: this.age
    }  
},
methods:{
    addAge(){
    	this.myAge++
    }
},

 

mixin 混入

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

在js文件中定义 混入,里面可以包含 组件的配置项 如data、methods等

export const hunhe = {
    data(){
        return{
            x:100,
            y:200
        }
    },
    methods:{
        showName(){
            alert(this.name)
        }
    }
}

在组件中使用时,先引入js文件,再通过配置项mixins 引用定义的混入

<script>
import { hunhe } from '../mixin'

export default {
    /* eslint-disable */
    name:"Student",
    data(){
        return{
            name:'张三',
            age: 18
        }  
    },
    mixins:[hunhe]
}
</script>

mixins配置项是一个 数组 可以引入多个混入

如果混入中的配置项和组件中的配置项冲突了,比如都在data定义了一个x,那么x的值是组件中定义的值

如果是钩子函数冲突,那么这两个钩子函数都会执行

上面那种引入是局部引入,还有全局引入的方式

在main.js 中 先引入 混入,在调用Vue的mixin方法,传入混入即可

这时所有的组件中都有混入的元素了

 

插件

功能:增强vue

本质:包含install方法的一个对象,install的第一个参数是Vue,后面的参数是使用者传递的数据

定义:在 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原型添加一个方法
        Vue.prototype.hello = ()=>{
            alert(11111)
        }
    }
}

使用:在main.js 中 引入该文件

调用Vue.use() 使用该插件

 

scoped 样式

作用:让样式在局部生效,防止冲突

写法:<style scoped>

 

组件化编码流程

1.实现静态组件:按功能点拆分,命名不要和html冲突

2.实现动态组件:考虑好数据的存放位置

  • 一个组件在用:放在自身组件即可

  • 一些组件在用:放在他们共同的父组件

3.实现交互

 

props适用于:

  • 父组件向子组件传递,通过在子组件的标签中传递

  • 子组件向父组件传递,需要父组件先传给子组件一个函数,子组件调用这个函数,传入父组件需要的值

v-model 绑定的值不能是 props传过来的值,因为props中的值不可以修改

 

webStorage

1.存储内容大小一般支持5MB左右,视浏览器而定

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

3.相关API

  • xxxxStorage.setItem('key','value) 设置键值对进行存储

  • xxxxStorage.getItem('key') 传入键名,返回键名对应的值

  • xxxxStorage.deleteItem('key') 传入键名,删除该项

  • xxxxStorage.clear() 清楚所有数据

 

4.sessionStorage 存储的内容会随着浏览器窗口关闭而消失

localStorage 需要手动清楚才会消失

 

 

自定义事件

之前从子组件向父组件传递数据时是通过 props,父组件先向子组件传递一个函数,子组件调用这个函数,并传递数据

利用自定义事件也可以实现子组件向父组件传递数据

父组件在 子组件标签处绑定一个自定义事件,用 v-on,值可以是一个函数,当子组件触发这个事件时,就会调用这个函数

在子组件中触发这个自定义事件使用 this.$emit,第一个参数是自定义事件的名字,后面的参数是要传的值

<template>
  <div>
    <h1>{{msg}}</h1>
    <School @getSomething="getSchoolName"></School>
    <hr/>
    <Student></Student>
  </div>
</template>

<script>
import Student from './components/Student.vue'
import School from './components/School.vue'
export default {
    name:'App',
    components:{Student,School},
    data(){
        return{
            msg:"欢迎!!!"    
        } 
    },
    methods:{
      getSchoolName(name){
        console.log('学校名:' + name)
      }
    }
}
</script>

这里的自定义事件是 getSomething,触发该事件后执行 getSchoolName 函数

<template>
  <div>
    <h2>学校姓名:{{name}}</h2>
    <h2>地址:{{address}}</h2>
    <button @click="senSchoolName">点击发送学校名称</button>
  </div>
</template>

<script>

export default {
    /* eslint-disable */
    name:"School",
    data(){
        return{
            name:'sdgsyx',
            address:"yantai"
        }  
    },
    methods:{
      senSchoolName(){
        this.$emit('getSomething',this.name)
      }
    }
}
</script>

 

这是自定义事件的第一种写法,除此之外还有第二种

给子组件 绑定 ref属性,然后在钩子函数mounted中,定义自定义事件

<template>
	...
    <Student ref="student"></Student>
  	...
</template>

<script>
...
export default {
   	...
    methods:{
     	...
      getStudentName(name){
        console.log('学生名:' + name)
      },
    },
    mounted(){
      this.$refs.student.$on('getStudent',this.getStudentName)
    }
}
</script>

在mounted函数中。先用 this.$refs.student 获取到子组件的组件实例对象,然后调用 $on,第一个参数是自定义事件的名字,第二个是回调函数

子组件中还是用 this.$emit('getStudent',this.name) 去触发自定义事件

 

第二种方式比第一种方式更加灵活,可以进行延时绑定

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

 

自定义事件解绑

调用 this.$off() 参数是 自定义事件名

传入一个自定义事件名是解绑一个自定义事件

传入一个数组是解绑多个自定义事件

什么都不传就是把所有自定义事件都解绑

当组件实例对象被销毁后,组件绑定的自定义事件也就被销毁了

 

全局事件总线

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

2.安装全局事件总线

在main.js中给 vue的原型对象上绑定一个属性,这个属性能够被所有的组件看到,并且它有绑定和解绑的函数($on、$off、$emit),那么这个属性的值就是vue的实例对象。

绑定这个属性的时机就是在创建vue实例中,调用 beforeCreate 函数,确保该属性能够在模板被渲染之前被绑定

new Vue({
    el:"#app",
    render:h => h(App),
    beforeCreate() {
        Vue.prototype.$bus = this
    },
})

在要接收的组件中,绑定一个自定义事件,调用 $on,在beforeDestroy中解绑

mounted() {
  this.$bus.$on('sendEvent',(data)=>{
    console.log("我是School,我收到了:" + data)
  })
},
beforeDestroy() {
	this.$bus.$off('sendEvent')
}

在要发送的组件中触发该自定义事件,调用 $emit

methods:{
  sendStudentName(){
    this.$bus.$emit('sendEvent',this.name)
  }
}

 

 

消息订阅与发布(pubsub)

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

2.使用步骤

  • 安装pubsub,它是一个js库 npm i pubsub-js

  • 引入 import pubsub from 'pubsub-js'

  • 在接收消息方,订阅消息

    methods(){
    	demo(msgName,data){...}
    },
    mounted(){
    	this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
    },
    beforeDestroy(){
        pubsub.unsubscribe(this.pid)
    }

    注意:在回调函数中,第一个参数是消息名,第二个是接收的数据,最好在beforeDestroy去取消订阅

  • 在发送消息方,发布消息

    methods(){
    	send(){
            pubsub.publish("xxx",data)
        }
    },

     

nextTick

作用:在下一次DOM 结束后执行指定的回调

handleUpdate(){
    this.showInput = true
    this.$nextTick(function(){
      this.$refs.input.focus()
    })     
},

在handleUpdate 函数中,当数据改变后,vue并不会立即去重新解析模板,而是会继续执行函数,等到函数执行完后才去重新解析模板,如果不加 $nextTick, 让input获取焦点的时候,input输入框还没有被渲染到模板上,所以会没有效果

使用 $nextTick,vue解析完模板后,再执行里面的回调函数

 

Vue 封装的过渡与动画

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

2.

3.写法:

  • 准备好样式

    • 元素进入时的样式:

      • v-enter:进入的起点

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

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

    • 元素离开时的样式:

      • v-leave:离开的起点

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

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

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

    <transition name="hello">
    	<h1 v-show="isShow">
            你好!
        </h1>
    </transition>
  • 备注:如果有多个元素需要过渡,则需要使用 <transition-group> 且每个元素都要指定key值

标签:Vue,name,编程,js,vue,组件,data
From: https://www.cnblogs.com/wztblogs/p/18278670

相关文章

  • Vue 中的Ajax
    Vue中的Ajax配置代理发送ajax请求的方式:1.xhrnewXMLHttpRequest()xhr.open()配置请求信息xhr.send()发送请求虽是鼻祖,但很麻烦,一般对其进行二次封装2.jQuery$.get$.postjQuery的核心是DOM操作,在vue等框架中不常使用3.axios与jQuery相比的优......
  • 用C++解决编程题目:角谷猜想
    学习目标:用C++编写简单的题目学习内容:#include<iostream>usingnamespacestd;intmain(){longlongn;cin>>n;while(n!=1){if(n%2==1){cout<<n<<"*3+1="<<n*3+1<<endl;n=3*n+1;......
  • Mojo — 适用于所有人工智能开发人员的编程语言
    Mojo语言是一个由人工智能公司Modular推出的全新编程语言,专为AI开发者设计。Mojo的语法与Python相似,但结合了Python的易用性和C语言的高性能,旨在解锁AI硬件的可编程性和AI模型的可扩展性。Modular这个公司则是一个非常年轻的新生AI创业公司,于2022年由ChrisLattner和TimDavi......
  • JavaScript 编程语言【 数据类型】过滤|排序|映射|迭代
    文章目录将border-left-width转换成borderLeftWidth过滤范围原位(inplace)过滤范围降序排列复制和排序数组创建一个可扩展的calculator映射到names映射到对象按年龄对用户排序随机排列数组获取平均年龄数组去重从数组创建键(值)对象Iterableobject(可迭代对象)Symbol.......
  • Vue Ant Design中a-tree组件支持点击父节点名称(title\label)所有子节点选中
    核心代码<a-treeref="treeRef"class="draggable-tree"v-if="treeData.length":tree-data="treeData"......
  • 记一次vue脚手架打包生成的js里面变量逻辑错误的解决
    问题背景开发环境调用threejs,实现3d功能组件,开发环境测试正常,打包部署到现场后异常。浏览器控制台,报变量i和r,没有定义下图是点击报错地方打开的控制台截图。可以看到有ir变量。解决思路开发调试没有问题,那肯定是打包之后命名的变量存在不正确的逻辑了。肯定不能修改dis......
  • 自定义vue3 hooks
    文章目录hooks目录结构demohooks当页面内有很多的功能,js代码太多,不好维护,可以每个功能都有写一个js或者ts,这样的话,代码易读,并且容易维护,组合式setup写法与此结合......
  • 一个项目学习Vue3---Vue模板方法
     内容资源下载:关注公众号(资小库),下载相关资源分析下面一段代码,学习模板方法的可能的知识<template><div><div>将下面的msg属性放到上面来:{{msg}}</div><divv-html="htmlMsg"></div><divv-bind="id">这个地方绑定了一个ID{{id}}</div>......
  • (记得关注哦)国产商用密码:编程实现分组密码体制中的国密算法SM4。
    一、研究SM4算法(一)SM4算法的分组长度、密钥长度、S盒、轮函数①分组长度和密钥长度:分组长度:SM4算法的分组长度为128位(即16字节),这意味着它每次加密或解密的数据块大小为128位。密钥长度:SM4算法的密钥长度为128位(即16字节),与分组长度相同。......
  • 利用阿里云API获取实时天气信息|C语言Linux网络编程练手小项目
    文章目录目录文章目录前言一、HTTP数据请求1.HTTP概述2.数据请求方式3.JSON格式二、阿里云API获取,使用1.购买(白嫖)API接口步骤2.API使用代码编写3.编译程序 4.运行结果总结前言在项目开发时常常需要显示各种信息,如时间、天气、温度、空气质量指数等等。在......