前端基础-05VUE基础02

01 组件化思维

生产环境一般不会直接导入一个js文件,通过组件

网页中实现一个功能,需要使用html定义功能的内容结构,使用css声明功能的外观样式,还要使用js来定义功能的特效

把一个功能相关的[HTMLcssjavascript]代码封装在一起组成一个整体的代码块封装模式,我们称之为“组件”

 

默认组件-示例

组件名 button-counter 可以随意

Data 数据

Template 模板 存放html内容的属性

不支持css

不支持 CSS (No CSS support) 意味着当 HTML JavaScript 组件化时,CSS 明显被遗漏

 

数据隔离

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
  <script src="vue3.js"></script>
</head>
<body>
<div id="components-demo">
  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter/>
</div>
<script>
  // 创建一个Vue应用
  const app=Vue.createApp({});
  // 定义一个名为button-counter的新全局组件
  app.component('button-counter',{
    data(){
      return{
        count:0
      }
    },
    template:`
      <button @click="count++">
      You clicked me {{count}} times.
      </button>`,
      style:{
        color:"red",
      }
  });
  app.mount('#components-demo')
</script>
</body>
</html>

 

 

单文件组件

Vue 单文件组件(又名 *.vue 文件,缩写为 SFC)是一种特殊的文件格式,它允许将 Vue 组件的模板、逻辑 与 样式封装在单个文件中。

<template>
  <p class="greeting">{{ greeting }}</p>
</template>

<script>
export default {
  data() {
    return {
      greeting: 'Hello World!'
    }
  }
}
</script>

<style scoped>
.greeting {
  color: red;
  font-weight: bold;
}
</style>

 

Script存放数据

Template存放html代码

Style存放css代码

 

 

虽然 SFC 需要一个构建步骤,但益处颇多:

使用熟悉的 HTMLCSS JavaScript 语法编写模块化组件

预编译模板

组件作用域 CSS

通过交叉分析模板与脚本进行更多编译时优化

IDE 支持 模板表达式的自动补全与类型检查

开箱即用的热模块更换(HMR)支持

02脚手架 vue/cli

Vue/cli

Vite

安装vue/cli

 

关于旧版本: Vue CLI 的包名称由 vue-cli 改成了 @vue/cli。 如果你已经全局安装了旧版本的 vue-cli (1.x 2.x),你需要先通过 npm uninstall vue-cli -g yarn global remove vue-cli 卸载它。

 

Vue CLI 4.x 需要 Node.js v8.9 或更高版本 (推荐 v10 以上)

 

Js作为前端语言使用。不仅能做前端

 

Node.js 相当于python的解释器 python.exe

Pip包 安装第三方依赖包,nodejs中有npm相当于pip

 

后端可选择

Javascript

Java

Go

Python

Vue-cli支持后端

Express相当于nodejs  javascript框架

 

1 下载node vue一定要在4.5以上

 

1 下载nodejs

http://nodejs.cn/download/

2 安装vue/cli

C:\Users\zhu>npm install -g @vue/cli

 

3 更新

C:\Users\zhu>npm update -g @vue/cli

03 使用

创建项目hello-world

1 创建vue create hello-world

D:\GoWork\src\gitee.com\zhutao2014\s9\day13>vue create hello-world

 

 

2选择安装组件

Babel勾选上

Router勾选上

Linter会严格检查语法,取消掉

回车

 

 

 

3选择3.x版本

 

 

4 选择历史模式路由

 

5 选择配置方式package.json

 

6 保存预处理记录

可以取名字为 basePro,相当于保存了一个配置模板。

想要删除,可以找到window用户家目录下.vuerc,删除"presets": {} {}内的内容。

 

2 创建成功后,启动

 

3执行完成后

 

 

 

 

4 访问最终页面

 

 

 

 

这个是给配置起名字

 

 

 

04

npmnodejs配套命令

 

单页面开发 spa:  single page application

 

 

 

 

 

代码都写好后,不用vue-cli

通过webpack打包

生成静态文件。

把静态文件放到nginx

 

 

 

 

 

目录结构

文件说明

src

package-lock 锁相关的

package.json

 

安装包,依赖于哪个环境

package.json 记录信息

package.jsonnode_model的关系

hello-world\package.json

内部提供的脚本环境

"scripts": {
  "serve": "vue-cli-service serve",
  "build": "vue-cli-service build"
},

依赖

"dependencies": {
  "core-js": "^3.8.3",
  "vue": "^3.2.13",
  "vue-router": "^4.0.3"
},
"devDependencies": {
  "@vue/cli-plugin-babel": "~5.0.0",
  "@vue/cli-plugin-router": "~5.0.0",
  "@vue/cli-service": "~5.0.0"
},

包存放的位置 node_modules

安装axios

hello-world项目安装axios

 

 

 

 

node_modules中引入axios

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-test\hello-world>npm install axios

1 hello-world\public\index.html

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\hello-world\public\index.html

 

<div id="app"></div>

2 hello-world\src\main.js

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\hello-world\src\main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')

mount加载#app的区域

 

3 hello-world\src\App.vue

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\hello-world\src\App.vue

 

router-link 带触发事件的标签,类似于a标签

router-view用于展示的标签

 

<template>
  <nav>
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
  </nav>
  <router-view/>
</template>

单文件组件模式流程

 

 

Main.jsindex.html填充

 

App.vue 单文件组件

 

App.vue

修改后保存,自动重启

<template>
<!--  <nav>-->
<!--    <router-link to="/">Home</router-link> |-->
<!--    <router-link to="/about">About</router-link>-->
<!--  </nav>-->
<!--  <router-view/>-->
  <h1>Welcome to VUE</h1>
</template>

 

单文件组件-导入组件三部曲

修改App.vue

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\hello-world\src\App.vue

1 导入子组件 import

@ 符号相当于src路径

2 暴露组件export components

注意 export default 对应的name: 'App',为文件名App.vue

3 使用子组件<HelloWorld>

<template>
<!--  <nav>-->
<!--    <router-link to="/">Home</router-link> |-->
<!--    <router-link to="/about">About</router-link>-->
<!--  </nav>-->
<!--  <router-view/>-->
  <h1>Welcome to VUE</h1>
  <HelloWorld></HelloWorld>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>

打印结果

 

示例

App.vue嵌套Home.vue

<template>
  <h1>Welcome to VUE</h1>
  <Home></Home>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import Home from '@/views/Home.vue'

export default {
  name: 'App',
  components: {
    HelloWorld,
    Home
  }
}
</script>

Home.vue嵌套 HelloWorld.vue

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld/>
  </div>
</template>

<script>
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: "Home",
  components:{
    HelloWorld
  }
}
</script>

<style scoped>

</style>

查看HomeWorld.vue组件

<template>
  <h3>hello world</h3>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

<style scoped>
h3 {
  color: red;
}
</style>

App嵌套Home, home嵌套 HelloWorld

 

 

 

 

vue单文件组件模式本质

1个index.html vue在里面用了不同的js 让页面产生变化

下午05

大组件放views

小组件放在components

 

创建vue-pro项目

D:\GoWork\src\gitee.com\zhutao2014\s9\day13>vue create vue-pro

 

 

 

router-link具有具体事件的a标签

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\App.vue

<template>
  <nav>
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
  </nav>
  <router-view/>
</template>

 

 

router目录里的js文件

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\router\index.js

 

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  }
]

无论访问哪个路径,都是访问的index.html页面

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\App.vue

<template>
  <h1>hello user</h1>
</template>

 

 

router-view 标签

router-view根据不同的路由关系,找到组件

插入到app.vuerouter-view的位置

 

 

route-link组件

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\App.vue

<template>
  <nav>
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
  </nav>
  <router-view/>
</template>

 

 

点击route-link 切换到route-view对应的组件

 

 

 

dom替换

 

 

 

 

 

 

route-linka标签区别

router-linkjsdom的替换

a标签是一次httpget请求

 

练习加路由

App.vue添加

<router-link to="/test1">test1</router-link>

 

修改路由 添加

hello-world\src\router\index.js

import Test1 from '../views/Test1.vue'

 

 

{

  path: '/test1',

  name: 'test1',

  component: Test1

}

下午06

构建Nav组件

<template>
  <div>
    <ul>
      <li v-for="menu in menu_list"><a :href="menu.link">{{ menu.name }}</a></li>
      <li>
            <span>所在地:</span><select v-model="city" name="" id="">
        <option value="北京">北京</option>
        <option value="上海">上海</option>
        <option value="深圳">深圳</option>
      </select>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "Nav",
  data() {
    return {
      menu_list: [
        {name: "百度", "link": "http://www.baidu.com"},
        {name: "腾讯", "link": "http://www.qq.com"},
        {name: "小米", "link": "http://www.xiaomi.com"},
      ],
      city: "北京",
    }
  },
}
</script>

<style scoped>
ul, li {
  list-style: none;
  padding: 0;
  margin: 0;
}

ul::after {
  overflow: hidden;
  clear: both;
  display: block;
  content: "";
}

li {
  float: left;
  margin: 0 20px;
}

a {
  text-decoration: none;
  color: #666;
}
</style>

 

下拉菜单

<li>
      <span>所在地:</span><select v-model="city" name="" id="">
  <option value="北京">北京</option>
  <option value="上海">上海</option>
  <option value="深圳">深圳</option>
</select>
</li>

 

构建home.vue组件

三部曲:在home.vue中添加Nva组件

①引入Import ②暴露组件export ③使用Nav标签

<template>
  <div class="home">
    <Nav/>
  </div>
</template>

<script>
// @ is an alias to /src
import Nav from '@/components/Nav.vue'

export default {
  name: 'Home',
  components: {
    Nav
  }
}
</script>

 

浏览器访问

 

构建Forecast.vue组件

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\components\Forecast.vue

<template>
  <h1>天气预报</h1>
</template>

<script>
export default {
  name: "Forecast"
}
</script>

<style scoped>

</style>

在再home中引入天气预报组件

<template>
  <div class="home">
    <Nav/>
    <Forecast/>
  </div>
</template>

<script>
// @ is an alias to /src
import Nav from '@/components/Nav.vue'
import Forecast from "@/components/Forecast";

export default {
  name: 'Home',
  components: {
    Forecast,
    Nav
  }
}
</script>

 

 

修改Forecast.vue组件

找到内容,放到页面

<template>
  <h1>天气预报</h1>
  <p><input type="text" placeholder="请输入查询城市" v-model="city">
    <button @click="sendAjax">查询</button>
  </p>
  <table border="1" v-if="forecasts.length>1">
    <tr>
      <td>日期</td>
      <td>天气</td>
      <td>最高气温</td>
      <td>最低气温</td>
      <td>风向</td>
    </tr>
    <tr v-for="day_forecast in forecasts">
      <td>{{day_forecast.date}}</td>
      <td>{{day_forecast.type}}</td>
      <td>{{day_forecast.high}}</td>
      <td>{{day_forecast.low}}</td>
      <td>{{day_forecast.fengxiang}}</td>
    </tr>
  </table>
</template>

 

js代码

<script>
export default {
  name: "Forecast",
  data() {
    return {
      forecasts:[],
      city:"北京"
    }
  },
  methods: {
    sendAjax() {
      var that=this
      // alert(123)
      axios.get("http://wthrcdn.etouch.cn/weather_mini",{
        params:{
          // city:"北京"
          city:this.city
        }
      }).then(function (response){
        console.log("response",response)
        that.forecasts=response.data.data.forecast
      })
    },
  },
  created(){
    this.sendAjax()
  }
}
</script>

样式拿过来

<style scoped>
tr td{
  padding: 10px;
  width:80px;
}
</style>

 

此时没有axios

 

 

安装

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro>npm install axios

 

1 记录模块名 版本号

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\package.json

"dependencies": {
  "axios": "^0.26.1",
  "core-js": "^3.8.3",
  "vue": "^3.2.13",
  "vue-router": "^4.0.3"
},

 

2 node_models中下载下来

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\node_modules\axios

 

导入包

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\components\Forecast.vue

<script>
import axios from "axios"; //要导入的包直接写包名即可,不需要使用路径
export default {
  name: "Forecast",
  data() {
    return {
      forecasts:[],
      city:"北京"
    }
  },

 

 

打印结果

 

调整表格居中

添加margin: 0 auto;

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\components\Forecast.vue

<style scoped>
table {
  margin: 0 auto;
}
tr td{
  padding: 10px;
  width:100px;
}
</style>

 

 

文本居中

App.vue中默认有文本居中

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\App.vue

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

 

打印结果

 

export default js的导出格式

created 点击按钮前加载

<script>
import axios from "axios"; //要导入的包直接写包名即可,不需要使用路径
export default {
  name: "Forecast",
  data() {
    return {
      forecasts:[],
      city:"北京"
    }
  },
  methods: {
    sendAjax() {
      var that=this
      // alert(123)
      axios.get("http://wthrcdn.etouch.cn/weather_mini",{
        params:{
          // city:"北京"
          city:this.city
        }
      }).then(function (response){
        console.log("response",response)
        that.forecasts=response.data.data.forecast
      })
    },
  },
  created(){
    this.sendAjax()
  }
}
</script>

 

 

 

 

综合练习

完整代码

Nav.vue

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\components\Nav.vue

<template>
  <div>
    <ul>
      <li v-for="menu in menu_list"><a :href="menu.link">{{ menu.name }}</a></li>
      <li>
            <span>所在地:</span><select v-model="city" name="" id="">
        <option value="北京">北京</option>
        <option value="上海">上海</option>
        <option value="深圳">深圳</option>
      </select>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "Nav",
  data() {
    return {
      menu_list: [
        {name: "百度", "link": "http://www.baidu.com"},
        {name: "腾讯", "link": "http://www.qq.com"},
        {name: "小米", "link": "http://www.xiaomi.com"},
      ],
      city: "北京",
    }
  },
}
</script>

<style scoped>
ul, li {
  list-style: none;
  padding: 0;
  margin: 0;
}

ul::after {
  overflow: hidden;
  clear: both;
  display: block;
  content: "";
}

li {
  float: left;
  margin: 0 20px;
}

a {
  text-decoration: none;
  color: #666;
}
</style>

 

Forecast.vue

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\components\Forecast.vue

<template>
  <h1>天气预报</h1>
  <p><input type="text" placeholder="请输入查询城市" v-model="city">
    <button @click="sendAjax">查询</button>
  </p>
  <table border="1" v-if="forecasts.length>1">
    <tr>
      <td>日期</td>
      <td>天气</td>
      <td>最高气温</td>
      <td>最低气温</td>
      <td>风向</td>
    </tr>
    <tr v-for="day_forecast in forecasts">
      <td>{{day_forecast.date}}</td>
      <td>{{day_forecast.type}}</td>
      <td>{{day_forecast.high}}</td>
      <td>{{day_forecast.low}}</td>
      <td>{{day_forecast.fengxiang}}</td>
    </tr>
  </table>
</template>

<script>
import axios from "axios"; //要导入的包直接写包名即可,不需要使用路径
export default {
  name: "Forecast",
  data() {
    return {
      forecasts:[],
      city:"北京"
    }
  },
  methods: {
    sendAjax() {
      var that=this
      // alert(123)
      axios.get("http://wthrcdn.etouch.cn/weather_mini",{
        params:{
          // city:"北京"
          city:this.city
        }
      }).then(function (response){
        console.log("response",response)
        that.forecasts=response.data.data.forecast
      })
    },
  },
  created(){
    this.sendAjax()
  }
}
</script>

<style scoped>
table {
  margin: 0 auto;
}
tr td{
  padding: 10px;
  width:100px;

}
</style>

 

 

Home.vue

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\views\Home.vue

<template>
  <div class="home">
    <Nav/>
    <Forecast/>
  </div>
</template>

<script>
// @ is an alias to /src
import Nav from '@/components/Nav.vue'
import Forecast from "@/components/Forecast";

export default {
  name: 'Home',
  components: {
    Forecast,
    Nav
  }
}
</script>

 

 

Index.js

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\router\index.js

import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  }
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

 

 

App.vue

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\App.vue

<template>
<!--  <nav>-->
<!--    <router-link to="/">Home</router-link> |-->
<!--    <router-link to="/about">About</router-link> -->
<!--  </nav> -->
  <router-view/>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

nav {
  padding: 30px;
}

nav a {
  font-weight: bold;
  color: #2c3e50;
}

nav a.router-link-exact-active {
  color: #42b983;
}
</style>

 

下午07 子给父

组件和组件之间传递数据

Nav.vue的值传给Home.vue

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\views\Home.vue

<template>
  <div class="home">
    <Nav/>
    <p>选中的城市:{{city}}</p>
    <Forecast/>
  </div>
</template>

显示选中的城市

 

 

子组件传递 事件给父组件

在子组件中,通过this.$emit('自定义事件名', 参数1,参数2,...)来调用父组件中定义的事件.

 

 

 

 

Nav.vue是子组件

Home.vue父组件配置

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\views\Home.vue

1 添加data数据cityp标签

2添加methodscollBack函数

3 Nav标签中添加调用,getCity事件调用collBack函数

注意:getCity在子组件在Nav.vue中定义。

 

<template>
  <div class="home">
    <Nav @getCity="collBack"></Nav>
    <p>选中的城市:{{city}}</p>
    <Forecast/>
  </div>
</template>

<script>
// @ is an alias to /src
import Nav from '@/components/Nav.vue'
import Forecast from "@/components/Forecast";

export default {
  name: 'Home',
  data(){
    return {
      city:""
    }
  },
  components: {
    Forecast,
    Nav
  },
  methods:{
    collBack(choose_city){
      // alert(123)
      this.city=choose_city
    }
  }
}
</script>

 

Nav.vue子组件配置

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\components\Nav.vue

 

父组件的getCity 是子组件本身的this.city

 

<template>
  <div>
    <ul>
      <li v-for="menu in menu_list"><a :href="menu.link">{{ menu.name }}</a></li>
      <li>
            <span>所在地:</span><select v-model="city" name="" id="">
        <option value="北京">北京</option>
        <option value="上海">上海</option>
        <option value="深圳">深圳</option>
      </select>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "Nav",
  data() {
    return {
      menu_list: [
        {name: "百度", "link": "http://www.baidu.com"},
        {name: "腾讯", "link": "http://www.qq.com"},
        {name: "小米", "link": "http://www.xiaomi.com"},
      ],
      city: "北京",
    }
  },
  created() {
    this.$emit("getCity",this.city);
  }
}
</script>

<style scoped>
ul, li {
  list-style: none;
  padding: 0;
  margin: 0;
}

ul::after {
  overflow: hidden;
  clear: both;
  display: block;
  content: "";
}

li {
  float: left;
  margin: 0 20px;
}

a {
  text-decoration: none;
  color: #666;
}
</style>

排错测试是否调用

methods:{
  collBack(choose_city){
    // alert(123)
    this.city=choose_city
  }
}

 

添加watch

当调整不同内容,created已经不再执行了

D:\GoWork\src\gitee.com\zhutao2014\s9\day13\vue-pro\src\components\Nav.vue

<script>
export default {
  name: "Nav",
  data() {
    return {
      menu_list: [
        {name: "百度", "link": "http://www.baidu.com"},
        {name: "腾讯", "link": "http://www.qq.com"},
        {name: "小米", "link": "http://www.xiaomi.com"},
      ],
      city: "北京",
    }
  },
  created() {
    this.$emit("getCity",this.city);
  },
  watch:{
    city(newVal,oldVal){
      console.log(newVal,oldVal);
      this.$emit("getCity",this.city);
    }
  }
}
</script>

 

 

 

 

利用watch做同步

 

下午08 12 父给子传数据

 

父组件中取值

 

子组件接收 props

 

 

 

 

 

联动

 

 

 

watch或者updated

 

 

 

 

修改 不要重复声明

 

 

 

 

 

 

下午13 路由

组件嵌套

 

 

设定路由

 

 

 

 

 

 

 

 

 

 

 

 

路由传参 无视频

1 路径参数传参

2 get参数传参

 

想查询2012/12参数对应的文章

 

 

 

 

把值传给子组件

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

下午14

 

 

希望能过滤文章

 

 

正常拿到年月发送给后端ajax请求

 

 

 

data赋值

 

 

 

 

 

 

 

不写死,给数据渲染

 

 

 

 

作为get请求的参数

 

 

 

 

 

 

最后打包命令

 

 

 

 

 

作业 当前全国疫情信息

 

posted @ 2022-04-08 21:32  澐湮  阅读(36)  评论(0编辑  收藏  举报