Vue.js电影网站项目 github 链接(如果觉得有用记得start哦~): 项目源代码链接
目录
前言
开发模式对比
- MVC模式(JavaEE中的SSH框架,ASP.NET中的ASP.NET MVC框架)
- MVP模式(ASP.NET中的Web Forms)
- MVVM模式(Vue.js,WPF,AngularJS)
安装
1.vue.js
- 下载js文件,<script>标签引入,开发环境使用.js版本而不是.min.js
- 不下载直接用CDN,小型系统常用。BootCDN:https://www.bootcdn.cn
- 不下载直接用npm,构建大型应用时推荐使用
2.vue-devtools
- 下载地址:GitHub – vuejs/devtools: ⚙️ Browser devtools extension for debugging Vue.js applications.,readme->Get the Chrome Extension / (beta channel)
注:由于使用了ES5,故vue.js不支持IE8及其以下版本
说明:vus.js提供了一个数据的双向绑定功能,当动态更新message中的值时,并不需要刷新网页或更新节点,此节点的值会随着JavaScript代码的变动而改变
Vue.js
1.Vue.js主要特性
1)组件
- 组件是HTML元素的扩展,可自定义其数据与行为。例如通过一个bind操作将JS中的内容绑定在div标签内部:
<body>
<div id="app">
<p> {
{ message }} </p>
</div>
<script>
var app = new Vue({
el: '#app',
data:{
message: 'Hello Vue.js!'
}
})
</script>
</body>
</html>
- 注册全局组件:
<div id="app">
<my-component></my-component>
</div>
<script>
Vue.component('my-component',{
template: '<div>Hello Vue!</div>'
})
new Vue({
el: '#app'
})
</script>
2)模板
vue.js使用基于HTML的模板语法,允许开发者将DOM元素与底层vue.js实例中的数据相绑定。
3)响应式设计
响应式网络设计是为了给移动设备提供更好的体验,整合从桌面到手机的各种屏幕尺寸和分辨率,使网页适应不同分辨率的屏幕。响应式界面的四个层次:
- 同一页面在不同大小和比例上看起来都应该是舒适的;
- 同一页面在不同分辨率上看起来都应该是合理的;
- 同一页面在不同操作方式(如鼠标和触屏)下,体验应该是统一的;
- 同一页面在不同类型的设备(手机、平板、电脑)上,交互方式应该是符合习惯的。
4)过渡效果
vue.js的过渡效果可以让我们的页面元素在出现和消失时实现过渡。vue.js在插入、更新或移除DOM时,提供了多种方式的应用过渡效果,包括:
- 在CSS过渡和动画中自动应用CSS
- 配合使用第三方CSS动画库,如Animate.css
- 在过渡钩子函数中使用JavaScript之间操作DOM
- 配合使用第三方JavaScript动画库,如Velocity.js
vue.js提供了transition的封装组件,在下列情形中可以给任何元素和组件添加entering/leaving过渡:
- 条件渲染(使用v-if)
- 条件展示(使用v-show)
- 动态组件
- 组件根节点
简单而言就是,你可以使用vue的<transition></transition>组件,结合css的动画(animation),过渡(transition),或者javascript操作DOM来让你的元素或者组件动起来。而在引用css和javascript中,你可以自己写,也可以利用现成的css或者javascript的第三方库。
页面交互举例,当单击按钮后,hello Vue会渐变地消失,再次单击后又会渐变地显示:
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity .5s
}
.fade-enter, .fade-leave-to /* .fade-leave-active in below version 2.1.8 */ {
opacity: 0
}
</style>
<div id="app">
<button v-on:click="show = !show">
click
</button>
<transition name="fade">
<p v-if="show">hello Vue</p>
</transition>
</div>
<script>
// 创建根实例
new Vue({
el: '#app',
data: {
show: true
}
})
</script>
5)单文件组件
为了更好适应复杂的项目,vue.js支持以.vue为扩展名的文件来定义一个完整组件,用以替代使用Vue.component注册组件的方式。
2.Vue.js实例
1)构造器
对于Vue.js项目来说,每个应用的起步都需要使用Vue.js的构造函数创建一个根实例,如下:
// 建立Vue实例
var vm = new Vue({
// 选项
})
2)实例的属性和方法
每个Vue.js实例在被创建之前都要经过一系列的初始化过程,在初始化过程中加入一些data属性,即表示此实例的一些响应事件或数据属性等,如:
var data = { a:1 }
var vm = new Vue({
el: "#example",
data: data
})
vm.$data === data; // true
vm.$watch('a', function(newValue, oldValue){
// 这个回调将在 vm.a 改变后调用
})
3)生命周期、钩子函数
钩子函数主要对于某个实例事件发生后需要响应已经预设好的代码。钩子的this指向调用它的Vue.js实例
3.Vue.js路由
通过对不同路由路径的定义,可以将Vue.js中可供访问的路径标明。一般采用一个路径对应一个功能的形式来定义页面
1)安装vue-router(提供了Vue.js的路由控制和管理)
- 直接引入CDN
<script src=”https://cdn.bootcss.com/vue-router/3.0.6/vue-router.common.js”></script>
- npm安装
npm install vue-router
2)动态路由匹配
动态路由匹配经常需要把某种模式匹配到的所有路由全都映射到同一个组件上。例如,所有ID不同的用户都要使用User组件来渲染:
export default new Router({
routes:[
{
path: '/user/:id',
component: User
}
]
})
一个路径的定义参数使用冒号进行连接,当匹配到一个路由时,参数值会被设置到 this.$route.params,可以在每个组件中使用
3)嵌套路由
export default new Router({
routes:[
{
path: '/user/:id',
component: User,
children: [
{
path: 'vip',
component: VIP
}
]
}
]
})
- 访问 /user/xxx/ 时,页面不会渲染任何东西,因为没有匹配到合适的子路由
- 访问 /user/xx/vip 时,则会正常渲染
4)编程式导航
- <router-link to=”…”>
支持用户在具有路由功能的应用中(单击)导航,通过to属性指定目标地址,默认渲染成<a>标签
- router.push(location, onComplete?, onAbort?)
这个方法会向history栈添加一个新的记录,当点击“后退”按钮时,则回到之前的URL
router.push('home') // 参数:字符串路径
router.push({ path: 'home' }) // 参数:对象
router.push({ name: 'user', params: { userId: 123 }}) // 参数:命名的路由
router.push({ path: 'register', query: { plan: 'private'}}) // 带查询参数:/register?plan=private
router.push({ path: 'user', params: { userId } }) // 如果提供了path参数,params传递的参数会被忽略:/user
- router.replace(location, onComplete?, onAbort?)
此方法和router.push()很像,唯一不同的是,它不会向history添加新纪录,而是替换掉当前的history记录
<router-link to="..." replace>
- router.go(n)
n是一个整数,表示在history记录中向前或后退多少步,类似window.history.go(n)
router.go(1) // 在浏览器记录中前进一步,等同于 history.forward()
router.go(-1) // 在浏览器记录中后退一步,等同于 history.back()
router.go(100) // 如果记录不够用,则自动失效
5)命名视图
一个工程可能需要同时(同级)展示多个视图,页面不复杂时,可以用视图的别名
<router-view class="view one"></router-view> // 未指定名称,为默认组件
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
6)重定向和别名
- 重定向
const router = new VueRouter({
routes: [
{ path: "/a", redirect: "/b" }
]
})
const router = new VueRouter({
routes: [
{ path: "/a", redirect: { name: 'foo' } }
]
})
// 动态返回重定向目标
const router = new VueRouter({
routes: [
{ path: "/a", redirect: to => {
// return 重定向的字符串路径/路径对象
}}
]
})
- 别名
例如, /a的别名是/b,意味着用户访问/b时,URL会保持会/b,但路由匹配则为/a:
const router = new VueRouter({
routes: [
{ path: "/a", component: A, alias: "/b" }
]
})
7)路由组件传递参数
// UserProps.vue
<template>
<div> Hello, {
{ id }} </div>
</template>
<script>
export default {
// props传递数据
props: ['id']
}
</script>
//index.js
{
path: '/UserProps/:id',
component: UserProps,
props: true
}
8)history模式
const router = new VueRouter({
mode: history,
routes: [...]
})
4.Vue.js模板
1)文本
// 无论何时,绑定的数据对象上 msg 属性发生了改变,插值处的内容都会更新。
<span>Message: {
{ msg }}</span>
// 一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定
<span v-once>这个将不会改变: {
{ msg }}</span>
2)HTML
// 为了输出真正的 HTML,你需要使用 v-html 指令:
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
你的站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。
{
{ number + 1 }}
{
{ ok ? 'YES' : 'NO' }}
{
{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>
// 这些表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效。
<!-- 这是语句,不是表达式 -->
{
{ var a = 1 }}
<!-- 流控制也不会生效,请使用三元表达式 -->
{
{ if (ok) { return message } }}
模板表达式都被放在沙盒中,只能访问全局变量的一个白名单,如
Math
和Date
。你不应该在模板表达式中试图访问用户定义的全局变量。
4)指令
指令 (Directives) 是带有 v-
前缀的特殊特性。
<p v-if="seen">现在你看到我了</p>
// 这里,v-if 指令将根据表达式 seen 的值的真假来插入/移除 <p> 元素。
5)参数
一些指令能够接收一个“参数”,在指令名称之后以冒号表示。
<a v-bind:href="url">...</a>
// 在这里 href 是参数,告知 v-bind 指令将该元素的 href 特性与表达式 url 的值绑定。
<a v-on:click="doSomething">...</a>
// 在这里参数是监听的事件名。
5.条件渲染
1)v-if, v-else-if, v-else
<div v-if="type === 'A'"> A </div>
<div v-else-if="type === 'B'"> B </div>
<div v-else-if="type === 'C'"> C </div>
<div v-else> Not A/B/C </div>
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
2) v-show
<h1 v-show="ok">Hello!</h1>
不同的是带有 v-show
的元素始终会被渲染并保留在 DOM 中。v-show
只是简单地切换元素的 CSS 属性 display
。
注意:v-show
不支持 <template>
元素,也不支持 v-else
。
3)v-if vs v-show
v-if | v-show |
“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。 | 只是简单地切换元素的 CSS 属性 display |
惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。 | 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。 |
更高的切换开销,如果在运行时条件很少改变,则使用 v-if 较好。 |
更高的初始渲染开销,如果需要非常频繁地切换,则使用 v-show 较好; |
6.列表渲染
<ul id="example-1">
<li v-for="item in items">
{
{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
// 在 v-for 块中,我们可以访问所有父作用域的属性。v-for 还支持一个可选的第二个参数,即当前项的索引。
<ul id="example-2">
<li v-for="(item, index) in items">
{
{ parentMessage }} - {
{ index }} - {
{ item.message }}
</li>
</ul>
var example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
- 可以用
of
替代in
作为分隔符,因为它更接近 JavaScript 迭代器的语法:
<div v-for="item of items"></div>
2) 用 v-for
来遍历一个对象的属性
<div v-for="(value, name, index) in object">
{
{ index }}. {
{ name }}: {
{ value }}
</div>
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
<div>
<span v-for="n in 10">{
{ n }} </span>
</div>
当 v-for
与 v-if
一起使用时,v-for
具有比 v-if
更高的优先级。
注意:不推荐在同一元素上使用 v-if
和 v-for
<li v-for="todo in todos" v-if="!todo.isComplete">
{
{ todo }}
</li>
如果你的目的是有条件地跳过循环的执行,那么可以将 v-if
置于外层元素 (或 “><template>)上。如:
<ul v-if="todos.length">
<li v-for="todo in todos">
{
{ todo }}
</li>
</ul>
<p v-else>No todos left!</p>
2.2.0+ 的版本里,当在组件上使用 v-for
时,key
现在是必须的。
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>
7.事件处理
1)监听事件
<div id="example-1">
<button v-on:click="counter += 1">Add 1</button>
<p>The button above has been clicked {
{ counter }} times.</p>
</div>
var example1 = new Vue({
el: '#example-1',
data: {
counter: 0
}
})
2)事件处理方法
<div id="example-2">
<!-- `greet` 是在下面定义的方法名 -->
<button v-on:click="greet">Greet</button>
</div>
var example2 = new Vue({
el: '#example-2',
data: {
name: 'Vue.js'
},
// 在 `methods` 对象中定义方法
methods: {
greet: function (event) {
// `this` 在方法里指向当前 Vue 实例
alert('Hello ' + this.name + '!')
// `event` 是原生 DOM 事件
if (event) {
alert(event.target.tagName)
}
}
}
})
<div id="example-3">
<button v-on:click="say('hi')">Say hi</button>
<button v-on:click="say('what')">Say what</button>
</div>
new Vue({
el: '#example-3',
methods: {
say: function (message) {
alert(message)
}
}
})
有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event
把它传入方法:
<button v-on:click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
// ...
methods: {
warn: function (message, event) {
// 现在我们可以访问原生事件对象
if (event) event.preventDefault()
alert(message)
}
}
4)事件修饰符
在事件处理程序中调用 event.preventDefault()
或 event.stopPropagation()
是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题,Vue.js 为 v-on
提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
.stop
.prevent
.capture
.self
.once
.passive
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即元素自身触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
5)按键修饰符
在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on
在监听键盘事件时添加按键修饰符:
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
全部按键别名:
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
6)系统修饰键
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
.ctrl
.alt
.shift
.meta
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
7)鼠标按钮修饰符
.left
.right
.middle
这些修饰符会限制处理函数仅响应特定的鼠标按钮。
ES6常用语法
1.默认参数
可以把默认值放在函数声明里,如:
var link = function(height = 50, color = 'red'){ }
2.模板文本
在字符串中可以用 ${ NAME } 代表变量,并将其放在反引号里,如:
var name = `Your name is ${first} ${last} .`;
3.多行字符串
可以用反引号表示多行字符串,如:
var text = `aaaaaa
bbbbbb
cccccc
`
4.解构赋值,如:
var {house, mouse} = $('body').data();
var [line1, line2, line3, , line5] = file.split('n'); // 数组也同样适用
5.增强的对象文本
6.箭头函数(还没有得到广泛支持)
有了箭头函数,this将可以按照你的预期使用了。不必用that = this, self = this那么麻烦了。如:
// ES5
var _this = this;
$('.btn').click(function(event){
_this.sendData();
})
// ES6
$('.btn').click((event) =>{
_this.sendData();
})
7.Promise实现
回调函数层数过多时,可以使逻辑更清晰
8.块作用域构造let
ES6中,用let限制块级作用域,用var限制函数作用域
9.类的创建。
- 方法名不需要加function关键字
- 冒号也不需要
- 不需要分配属性this,只需在构造函数中分配即可
如:
// 创建一个类baseModel,并在类里定义constructor()方法和getName()方法
class baseModel{
constructor(options, data) {
this.name = 'Base';
this.url = 'http://baidu.com/api';
this.data = data;
this.options = options;
}
getName() {
console.log(`Class name: ${this.name}`);
}
}
10.Module(模块)
ES6中可以用模块import和export操作了,ES5和ES6使用模块的代码对比如下:
// ES5,module.js定义如下
module.exprots = {
prot: 3000,
getAccounts: function(){
...
}
}
// ES5,main.js导入module.js如下
var service = require('module.js');
console.log(service.port);
// ES6,modul.js定义如下
export var port = 3000;
exprot function getAccounts(url){
...
}
// ES6,main.js导入module.js如下
// 导入变量
import {port, getAccounts}from 'module';
console.log(service.port);
// 或导入整个模块
import * as service from 'module';
console.log(service.port);
使用Babel进行ES6的转化
Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有浏览器环境下执行。
1.安装Babel,此处使用了-g参数进行全局安装
npm install -g babel-cli
2.配置Babel的配置文件.babelrc,该文件用来设置转码规则和插件,其基本格式如下:
{
"presets": [
"es2015",
],
"plugins": []
}
此处用的是ES2015作为转码规则,则需要使用如下命令安装需要的包:
npm install –save-dev babel-preset-es2015
3.建立文件,执行转换。输入是符合ES6的index.js,目标输出是符合ES5的compiled.js
babel index.js –out-file compiled.js
WebPack
WebPack是一个开源的模块加载器兼打包工具,它能把各种资源如JS(含JSX)、Coffee、样式(Less/Sass)、图片都作为模块使用和处理。使用它之前要安装Node.js。
安装
npm install –save-dev webpack
npm install –save-dev webpack@<version>
构建第一个Vue.js项目
首先我们用vue-cli新建项目。
- 全局安装vue-cli
npm install -g vue-cli
- 创建一个名字为demo的项目。
vue init webpack demo
- 进入demo目录下,安装项目需要的插件
cd demo
npm install
- 运行项目
npm run dev
- 浏览器显示效果
- 项目下的文件夹说明
build:打包相关
config:配置,测试,生产环境的启动端口
node_modules:命令npm install 安装的node插件所在地
src:为开发者编写的代码
src/assets:放置静态页面中的图片或其他静态资源
src/components:编写的组件代码
src/router:放置项目中的路由
src/App.vue:作为入口页面
Vue.js电影网站项目
此项目是边学边做的,github链接(如果觉得有用记得start哦~): 项目源代码链接
项目截图
1.技术选择
2.开发环境
- IDE:WebStorm
- MongoDB可视化界面软件:Studio 3T
- 服务器测试:Postman客户端
3.主要功能
- 电影显示下载地址
- 电影的增、删、改等后台管理
- 主页的推荐及更新排行榜
- 用户对资源的评论、点赞、下载
- 用户的注册、登录
- 用户资料显示,基本权限控制,密码找回
- 后台对评论的审核,对用户的管理(封停、重置密码等),对用户权限的控制
- 后台编辑主页的大图,更新主页的推荐
- 用户可发送站内信给管理员
- 主页的文章功能
4.安装Express(安装之前要先安装Node.js)
- Express是一个基于Node.js平台的极简、灵活的web应用开发平台
Express核心特性:
1.可以设置中间件响应HTTP请求
2.定义了路由表用于执行不同的HTTP请求动作
3.可以通过向模板传递参数来动态渲染HTML页面
- 初始化一个npm项目,生成一个package.json文件
npm init
- 安装Express.js,并将其存入package.json
npm install express –save
- 编写程序测试Express是否安装成功,项目目录下新建index.js并写入下面的代码:
// 定义Express实例
var express = require('express');
var app = express();
// 定义路由
app.get('/', function(req, res){
res.send('Hello World!');
});
// 设置启动的地址端口信息
var server = app.listen(3000, function(){
var host = server.address().address;
var port = server.address().port;
// 打印相关提示
console.log('Example app listening at http://%s:%s', host , port);
});
- 在命令行中使用如下命令运行程序:
node index.js
- 在浏览器中访问 http://localhost:3000/ 可以打开测试页面
- 新建Express工程,先安装Express应用生成器
npm install express-generator -g
- 创建项目
express [projec_name]
- 进入该项目,使用npm安装
cd [projec_name]
npm install
- 命令行中启动应用
set DEBUG = [projec_name] & npm start
5.安装Postman(用于测试HTTP请求)
- 下载地址:链接
- 打开程序,在URL地址栏输入 http://localhost:3000 单击Send按钮,测试效果如下图
6.安装Mongoose(连接MongoDB的中间件)
- 在命令行中安装中间件
npm install mongoose –save
- 新建一个测试路由,创建名为Cat的数据集,连接名为pets的库,并在Cat中插入一个新数据Tom。index.js代码如下:
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
// 定义路由
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
// 定义路由
router.get('/mongooseTest', function (req, res, next) {
mongoose.connect('mongodb://localhost/pets', {useMongoClient: true});
mongoose.Promise = global.Promise;
var schema = new mongoose.Schema({name: String});
var Cat = mongoose.model('Cat', schema);
var tom = new Cat({ name: 'Tom'});
tom.save(function (err) {
if(err)
console.log(err);
else
console.log('success insert');
});
res.send('数据库连接测试');
});
module.exports = router;
- 在命令行中重启服务器,浏览器中访问 http://localhost:3000/mongooseTest ,效果如下:
7.安装Supervisor(监控代码的修改,工程中的代码修改后,会自动重新载入代码)
- 在命令行中安装
npm install -g supervisor
- 使用命令行启动程序
supervisor bin/www
- 执行效果
8.安装Crtpto(一个用于加密的中间件)
npm install crypto -save
- 根据用户id和一个固定字符串生成MD5值,示例代码:
var crypto = require('crypto');
const init_token = 'TKL02o';
// 获取MD5值
function getMD5Password(id){
var md5 = crypto.createHash('md5');
var token_before = id + init_token;
return md5.update(token_before).digest('hex');
}
9.安装iView(一套基于 Vue.js 的高质量UI 组件库)
- 方法1.NPM 安装
npm install iview –save
- 方法2.CDN 引入
<link rel=”stylesheet” href=”//unpkg.com/iview/dist/styles/iview.css”>
<script src=”//unpkg.com/iview/dist/iview.min.js”></script>
希望本文对您有帮助,您的打赏是对我最大的鼓励~
今天的文章Vue.js快速入门+项目实战(源码)分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/29139.html