Vue.js 3.0快速入门(附电影购票APP开发实战源码)

前言

文档笔记来源:kuangshenstudy,清华大学出版社,结合视频资源食用更佳,相关资源源码在文末,有需要自取。

一、概述

Vue是什么?

Vue.js是基于JavaScript的一套MVVC的前端框架。集合了众多优秀的主流框架设计思想,轻量、数据驱动(默认单向数据绑定,但也支持双向数据绑定)、学习成本低。 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

MVVM是什么?

MVVM层实现了前后端更好的分离(前端需要的数据只需要请求后端的接口即可)。
MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。vm指定的是ViewModel,是视图模型。

ViewModel是MVVM模式的核心,是连接View和Model的桥梁。它有两个方向:

  1. 将模型转化成试图,将后端传递的数据转化成用户看到的界面。
  2. 将试图转化成模型,即将所看到的页面转化成后端的数据。
    在Vue.js框架中这两个方向都实现了,就是Vue.js中数据的双向绑定。
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第1张图片
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第2张图片

MVVM模式的实现者

Model:模型层, 在这里表示JavaScript对象
View:视图层, 在这里表示DOM(HTML操作的元素)
ViewModel:连接视图和数据的中间件, Vue.js就是MVVM中的View Model层的实现者

为什么要使用MVVM

MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处

低耦合:视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
可复用:可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑。
独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewMode),设计人员可以专注于页面设计。
可测试:界面素来是比较难以测试的,而现在测试可以针对ViewModel来写。
Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第3张图片

二、Here we go!

1、第一个Vue程序(基于idea安装vus插件开发)

1.1引用vue.js 使用cdn导入

<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

或者

<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>

不推荐新手直接使用 vue-cli

1.2创建一个空项目,创建一个文件夹,new一个HTML文件

Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:

(模板块,后期可直接复制模板)

<div id="app">
  {{ message }}
</div>
var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})

万物始于hello word 创建第一个 vue.js

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>

<body>

<!--view层,模板-->
<div id="app">
    <!--    数据绑定-->
    {{message}}
</div>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script type="text/javascript">
    // 创建一个Vue实例
    var vm = new Vue({
    el:"#app",
        /*Model:数据*/
        data:{
        message:"hello vue~"
        }
    });
</script>

</body>
</html>

说明:

  • el:“#app” -----> 绑定元素的ID
  • data:{message:“hello vue~”} ----> 数据对象中有一个名为message的属性,并设置了初始值 hello,vue ~
  • {{message}} -----> 实现数据绑定功能
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第4张图片
    测试:

为了能够更直观的体验Vue带来的数据绑定功能, 我们需要在浏览器测试一番, 操作流程如下:
  1、在浏览器上运行第一个Vue应用程序, 进入开发者工具
  2、在控制台输入vm.message=‘HelloWorld’, 然后回车, 你会发现浏览器中显示的内容会直接变成HelloWorld,不需要刷新页面
  此时就可以在控制台直接输入vm.message来修改值, 中间是可以省略data的, 在这个操作中, 我并没有主动操作DOM, 就让页面的内容发生了变化, 这就是借助了Vue的数据绑定功能实现的; MV VM模式中要求View Model层就是使用观察者模式来实现数据的监听与绑定, 以做到数据与视图的快速响应。
  Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第5张图片

2、熟悉ES 6的语法

2.1为什么要使用ES 6

ES6是一次重大的版本升级,与此同时,由于ES6秉承着最大化兼容已有代码的设计理念,过去编写的 JS 代码还能正常运行。事实上,许多浏览器已经支持部分ES6特性,并继续努力实现其余特性。这意味着,在一些已经实现部分特性的浏览器中,开发者符合标准的 JavaScript 代码已经可以正常运行,可以更加方便地实现很多复杂的操作,提高开发人员的工作效率。
以下是ES6排名前十位的最佳特性列表(排名不分先后)

  • Default Parameters (默认参数)
  • Template Literals (模板文本)
  • Multi - line Strings (多行字符串)
  • Destructuring Assignment (解构赋值)
  • Enhanced Object Literals (增强的对象文本)
  • Arrow Functions (箭头函数)
  • Promises
  • Block - Scoped Constructs Let and Const (块作用域构造 Let and Const )
  • Classes(类)
  • Modules(模块)

2.2块作用域构造let和const

块级声明用于声明在指定块的作用域之外无法访问的变量。这里的块级作用域是指函数内部或
者字符{}内的区域。
在ES6中, let 是一种新的变量声明方式。在函数作用域或全局作用域中,通过关键字 var 声明
的变量,无论在哪里声明,都会被当成在当前作用域顶部声明的变量。

 function calculateTotalAmount ( vip )(
//只能使用 var 方式定义变量
 var amount =0;
 if ( vip ){
 //在此定义会被覆盖
 var amount=1;
  //在此定义会被覆盖
 var amount=100;
  //在此定义会被覆盖
  var amount=1000;
  return amount;
 } //打印内容
 console.log(calculateTotal/^mount (true));

以上结果将返回1000,这是一个bug,在ES 6中,用let限制块级作用域,而var限制函数作用域。

funetion calculateTotalAmount(vip){
//使用 var 方式定义变量 var amount =0;
 if(vip){
//使用1et定义的局部变量
 let amount =1;//第1个 let 
 let amount =100;//第2个 let 
 let amount =1000;//第3个 let 
 }
 return amount ;
 }
 console.log(calculateTotalAmount(true));

程序结果将会是0,因为块作用域中有了 let ,如果 amount=1 ,那么这个表达式将返回1。本例是一个演示,这里有一堆常量,它们互不影响,因为它们属于不同的块级作用域。
JavaScript 中的 var 只能声明一个变量,这个变量可以保存任何数据类型的值。ES6之前并没有定义声明常量的方式,ES6标准中引入了新的关键字 const 来定义常量。
使用 const 定义常量后,常量将无法改变, const 常量的用法说明如下。

1、const常量,只能一次赋值

const PI=3.14159;
PI=3.14;//报错 Assignment to constant variable.

2、对象常量

对象的属性可以修改,对象的引用不能修改

const obj={name:"kerr"};
obj.name="tom";

3、冻结对象

防止修改对象的属性

const obj=Object.freeze({name:"kerr"});
obj.name="tom";//报错,提示冻结对象不能再重新定义赋值

2.3模板字面量

2.3.1 Multi - line Strings (多行字符串)

ES 6的多行字符串是一个实用的功能,在ES 5中我们只能使用以下方法来表示多行字符串:

var roadPoem =, 江南好,风景旧曾谙。'
+,日出江花红胜火,1
+,春来江水绿如蓝。,
+,能不忆江南?'
+'忆江南-江南好1;

然而在ES 6中,仅仅用反引号就可以解决

var roadPoem = `江南好,风景旧曾谙。
日出江花红胜火,
春来江水绿如蓝。
能不忆江南?

2.3.2字符串占位符

使用模板和插入值是在字符串里输出变量的方式,在ES 5中开发者可以组合一个字符串

//在ES 6之前只能使用组合字符串的方式
var name = * your name is * + first + * ' +last + *.*;
var url=* http://localhost:3000/api/messages/* +id;

在ES 6 中,占位符是使用语法${NAME}的,将包含的NAME变量或者表达式放在反引号中

var name=`your name is ${first} ${last}. `;
var url=`http://localhost:3000/api/messages/${id}`;

2.4默认参数和rest参数

JavaScript定义默认参数的方式如下:

//JavaScript原先定义方式
var link=function (height,color,url){
var height =height || 50;
var color=color  | | * red*;
var url=url || 'http://baidu.com';
}

在ES 6中,可以直接把默认值放在函数申明中:

var link = function (height=50,color=* red*,url=`http://baidu.com *)

ES 6引入rest参数,用于获取函数的实参,不过rest参数不适合参数个数不确定的函数

ES 5中获取函数的实参:

function data(){
console.log(arguments);
}
data('pg','xj','jz');

在ES 6中,使用rest参数获取函数的实参:

function data(...args){
console.log(args);
}
data('苹果','香蕉','橘子');

rest参数必须放在参数最后的位置

function fn(a,b,...args){
console.log(a);
console.log(b);
console.log(args);
}
fn(100,200,300,400,500,600);

2.5解构赋值

house和mouse是key,同时也是hi变量

var data=$('body') . data();//data拥有两个属性house和mouse
house=data.house;
mouse=data.mouse;
//在Note.js中使用ES 5代码
var j sonMiddleware=require('bady-parser').j sonMiddleware;
var body=req.body;//body的两个属性,username和password
username = body.username;
password=body.password;

在ES 6中可以使用以下代码替换ES 5的代码

var { house,mouse)=$(1 body').data;
var (jsonMiddleware}=require('body-pareser');
var (username,password)=req.body;
//这个也同样适合数组
var [col1,col2]=$(' .cplumn*),[line1z line2,line3z,line5]=file.split(ln');

2.6展开运算符

第一个用途:组装数组

let color = ['red', 'yellow'];
let colorful = [...color, 'green', 'blue'];
console.log(colorful); // ["red", "yellow", "green", "blue"]

第二个用途:获取数组除了某几项的其他项

let num = [1, 3, 5, 7, 9];
let [first, second, ...rest] = num;
console.log(rest); // [5, 7, 9]

2.7增强的对象文本

2.7.1通过变量进行对象初始化

const
a=100,b=200,c=300;
obj={
	a
	b
	c
};

2.7.2简化定义对象方法

const lib={
	sum(a,b) { return a+b;},
	mult(a,b) {return a*b;}
};
console.log(lib.sum(100,200));//300
console.log(lib.mult(100,200));//20000

这里不能使用ES 6箭头函数(=>),因为该方法需要一个名称。如果直接命名每个方法,则可以使用=>箭头函数。例如:

const lib={
	sum:(a,b)=>a+b,
	mult:(a,b)=>a*b
};
console.log(lib.sum(100,200));//300
console.log(lib.mult(100,200));//20000

2.7.3动态属性键

通过在方括号[]内置表达式,可以在ES 6中到那个太分配对象键

const 
key1='one',
obj={
	[key1]:100,
	two:200,
	three:300
};
//表示obj.one=100,obj.two=200,obj.three=300

2.7.4解构属性中的变量

在ES 6中,通过解构可以创建于等效对象属性同名的变量。

const myObjecct={
	one:'洗衣机',
	two:'冰箱',
	three:'空调'
};
const{one,two,three}=myObject;
//表示	one='洗衣机',	two='冰箱',	three='空调'

2.8箭头函数

CoffecScript 就是因为有丰富的箭头函数,所以让很多开发者所喜爱。在ES6中,也有丰富的箭头出数。比如,以前我们使用闭包, this 总是预期之外地产生改变,而箭头函数的好处在于,现在 this 可以按照你的预期使用了,身处箭头函数里面, this 还是原来的 this 。
有了箭头函数,我们就不必像使用 that = this 或 self = this 、_ this = this 、 bind ( this )那么麻烦了。例如,下面的代码使用ES5就不是很优雅:

 var _this=this ;
$(*.btn *).click ( function (event){
this.ssenData();
})_

在ES6中则不需要使用_ this = this :

$ (*.btn*).click((event)=>{
this.sendData();
})

但并不是完全否定之前的方案,ES6委员会决定,以前的 function 的传递方式也是一个很好的方案,所以它们仍然保留了以前的功能。
下面是另一个例子,通过 call 传递文本给 logUpperCase ()函数,在ES5中:

 var logUpperCase = function (){
 var this = this ;
 this.string = this.string.toUpperCase ();
 return function (){
 return console.log (_this.string );
 }
 }
 logUpperCase .call({ string:*ES 6 rocks *});
 //而在Es6中并不需要用 this 浪费时间
 var logUpperCase = function (){
 this.string=this.string.toUpperCase ();
return()=>console.log(this.string);
}logUpperCase .call({string: * ES 6 rocks *})();

2.8Promise实现

在ES 6中有标准的Promise实现
下面是使用setTimeout()函数实现异步延迟加载函数;

setTimeout(function){
console.log('yay!*);
},1000);
var wait1000 = new Promise((resolve,reject)=>(
setTimeout(resolve,1000);
}).then(()=>(
console.log(* yay!*);
});

3、熟悉Vue.js的语法

3.1 v-bind

<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
  <span v-bind:title="message">
    鼠标悬停几秒钟查看此处动态绑定的提示信息!
  </span>

    <!--1.导入Vue.js-->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
    <script type="text/javascript">
        // 创建一个Vue实例
        var vm = new Vue({
            el:"#app",
            /*Model:数据*/
            data:{
                message:"mest Stduying vue "
            }
        });
    </script>
</div>
</body>
</html>

Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第6张图片
说明:

  • 看到的 v-bind attribute 被称为指令。指令带有前缀 v-,以表示它们是 Vue 提供的特殊 attribute
  • 它们会在渲染的 DOM 上应用特殊的响应式行为

3.2 v-if、v-else

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<!--Vue基本语法-->
<body>

<!--view层,模板-->
<div id="app">
<span v-bind:title="message">鼠标悬停几秒钟查看此处动态绑定的提示信息!</span>
    <br>

    <!--v-if else-->
    <h1 v-if="type">yes</h1>
    <h2 v-else>No</h2>
    <h1 v-if="type==='A'">A</h1>
    <h1 v-else-if="type==='B'">B</h1>
    <h1 v-else="type==='C'">C</h1>

</div>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script type="text/javascript">
    // 创建一个Vue实例
    var vm = new Vue({
    el:"#app",
        data:{
        message:"你好 vue~",
            // type:true
            type:'A',
        counter :0,
        message:"mest Stduying vue "
        },
            methods: {//方法必须定义在Vue的method对象中
                sayHi:function (event) {
                    alert(this.message);
                }
    },

});
</script>

</body>
</html>

Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第7张图片
说明:

  • 在浏览器上运行,打开控制台
  • 在控制台输入vm.type=false然后回车,你会发现浏览器中显示的内容会直接变成NO
    注:使用v-*属性绑定数据是不需要双花括号包裹的

3.3 v-for

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<!--Vue基本语法-->
<body>

<!--view层,模板-->
<div id="app">
<!--v-for-->
    <li v-for="item in items">
        {{item.message}}
    </li>


</div>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script type="text/javascript">
    // 创建一个Vue实例
    var vm = new Vue({
    el:"#app",
        data:{
        message:"你好 vue~",
            // type:true
            type:'A',
            items: [
                {message:'java-vue'},
                {message:'前端+后端'},
                {message:'java+mysql'}
            ],
        counter :0,
        message:"mest Stduying vue "
        },
            methods: {//方法必须定义在Vue的method对象中
                sayHi:function (event) {
                    alert(this.message);
                }
    },

});
</script>

</body>
</html>

Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第8张图片

3.4 v-on

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<!--Vue基本语法-->
<body>

<!--view层,模板-->
<div id="app">
<span v-bind:title="message">鼠标悬停几秒钟查看此处动态绑定的提示信息!</span>
    <br>
<!--v-on    -->
<button v-on:click="sayHi">click me</button>
    <button v-on:click="counter +=1">add</button>
    <p>The button above has been clicked {{ counter }} times.</p>

</div>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script type="text/javascript">
    // 创建一个Vue实例
    var vm = new Vue({
    el:"#app",
        data:{
            // type:true
            type:'A',
        counter :0,
        message:"mest Stduying vue "
        },
            methods: {//方法必须定义在Vue的method对象中
                sayHi:function (event) {
                    alert(this.message);
                }
    },

});
</script>

</body>
</html>

Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第9张图片

3.5 v-html

该指令用于更新元素的innerHtml。内容按普通html插入。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>

<body>

<!--view层,模板-->
<div id="app">
    <!--    数据绑定-->
    <p v-html="message">古诗欣赏:</p>
</div>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script type="text/javascript">
    // 创建一个Vue实例
    var vm = new Vue({
    el:"#app",
        /*Model:数据*/
        data:{
            message:'

老去惜花心已懒,爱梅犹绕江村。

'
} }); </script> </body> </html>

Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第10张图片

4、Vue 表单双向绑定

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件;
  • checkbox 和 radio 使用 checked property 和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<!--双向绑定 v-model-->
<body>

<!--view层,模板-->
<div id="app">
输入的是:<input type="text" v-model="message">{{message}}
    <br>
输入的是:<textarea type="text" v-model="message"></textarea>{{message}}

</div>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script type="text/javascript">
    // 创建一个Vue实例
    var vm = new Vue({
    el:"#app",
        data:
            {
                message:"123"
            }
    });
</script>

</body>
</html>

Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第11张图片
说明:
在文本区域插值 ({{text}}) 并不会生效,应用 v-model 来代替

复选框、多选框、下拉框

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>

<body>

<!--view层,模板-->
<div id="app">

<!--Gender:-->
    <input type="radio" name="sex" value="Men" v-model="mest" >Men
    <input type="radio" name="sex" value="Female"  v-model="mest">Female
    <p>choose which:{{mest}}</p>
<br>
<!--    下拉框:-->
<select v-model="selected" >
    <option value="" disabled name="one">--请选择--
    <option>A</option>
<!--    -->
    <option >B</option>
    <option>C</option>
</select>
 <p>choose which:{{selected}}</p>
    <br>
<!--    复选框:-->

    <input type="checkbox" value="足球" v-model="check">
    <label>足球</label>
    <input type="checkbox" value="汽车" v-model="check">
    <label>汽车</label>
    <input type="checkbox" value="音乐" v-model="check">
    <label>音乐</label>
    <input type="checkbox" value="游戏" v-model="check">
    <label>游戏</label>
<p>choose which:{{check}}</p>



</div>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script type="text/javascript">
    // 创建一个Vue实例
    var vm = new Vue({
    el:"#app",
        // data:{
        //     mest:''
        // }
        // data:{
        //     selected:''
        // }
        data:{
            mest:'',
            selected:'',
            check:['足球']
        }
    });
</script>

</body>
</html>

Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第12张图片

组件:
组件是可复用的Vue实例, 说白了就是一组可以重复使用的模板, 跟JSTL的自定义标签、Thymeleal的th:fragment等框架有着异曲同工之妙,通常一个应用会以一棵嵌套的组件树的形式来组织

  • Vue.component():注册组件
  • cvzhanshi:自定义组件的名字
  • template:组件的模板

5、Axios异步通信

  • 从浏览器中创建XMLHttpRequests
  • 从node.js创建http请求
  • 支持Promise API[JS中链式编程]
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换JSON数据
  • 客户端支持防御XSRF(跨站请求伪造)

测试Axios

准备data数据

{
  "name": "qingjiang",
  "url": "https://www.baidu.com/",
  "page": 1,
  "isNonProfit": true,
  "address": {
    "street": "含光门",
    "city": "陕西西安",
    "country": "中国"
  },
  "links": [
    {
      "name": "bilibili",
      "url": "https://bilibili.com"
    },
    {
      "name": "mest",
      "url": "https://www.baidu.com/"
    },
    {
      "name": "百度",
      "url": "https://www.baidu.com/"
    }
  ]
}

测试:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style>
        [v-cloak]{
            display: none;
        }
    </style>
</head>
<!--解决闪烁问题v-cloak-->
<div id="vue" v-cloak>
    <div>{{info.name}}</div>

    <div>{{info.address}}</div>

    <a v-bind:href="info.url">click me</a>

</div>
<body>
<!--引入js文件-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el:"#vue",
        //data()方法 data: 属性
        data(){
            return{
                //请求的返回参数合适,必须和json字符串一致
                info:{
                    name:null,
                    address:{
                        street:null,
                        city:null,
                        country:null
                    },
                    url:null
                }
            }
        },
        mounted(){//钩子函数
            axios.get('../data.json').then(response=>(this.info=response.data));
        }
    });
</script>
</body>
</html>

说明:

  • 在这里使用了v-bind将a:href的属性值与Vue实例中的数据进行绑定
  • 使用axios框架的get方法请求AJAX并自动将数据封装进了Vue实例的数据对象中
  • 我们在data中的数据结构必须和Ajax响应回来的数据格式匹配

Vue生命周期图
Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第13张图片

6、Vue 计算属性、内容分发、自定义事件

6.1 计算属性

计算属性的重点突出在属性两个字上(属性是名词),首先它是个属性其次这个属性有计算的能力(计算是动词),这里的计算就是个函数:简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>

<body>

<!--view层,模板-->
<div id="app">
<p>NowTime:{{currentTime1()}}</p>
<p>ComTime:{{currentTime2}}</p>


</div>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script type="text/javascript">
    // 创建一个Vue实例
    var vm = new Vue({
    el:"#app",
        data:{
        message:"hello mest"
        },
        methods:{
        currentTime1:function () {
        return Date.now();//返回一个时间戳
        }
        },
        // 计算属性:methods和computed方法不能重名
        computed:{
        currentTime2:function () {
            this.message;
        return Date.now();
        }
        }
    });
</script>

</body>
</html>

注意:methods和computed里的东西不能重名,重名之后,只会调用methods的方法

说明:

  • methods:定义方法, 调用方法使用currentTime1(), 需要带括号
  • computed:定义计算属性, 调用属性使用currentTime2,
    不需要带括号:this.message是为了能够让currentTime2观察到数据变化而变化
  • 如何在方法中的值发生了变化,则缓存就会刷新!可以在控制台使用vm.message=”你好呀",
    改变下数据的值,再次测试观察效果!

6.2 内容分发(插槽)

在Vue.js中我们使用元素作为承载分发内容的出口,可以称其为插槽,可以应用在组合组件的场景中。

需求:需要把下面的内容,让标题和内容通过插槽插入内容

<p>标题</p>
<ul>
    <li>abcd</li>
    <li>abcd</li>
    <li>abcd</li>
</ul>

定义一个代办事情的组件

 Vue.component('todo',{
        template:'
\
代办事项
\
    \
  • cvzhanshi study Java
  • \
\
'
});

将上面的代码留出一个插槽,即slot

 Vue.component('todo',{
        template:'
\ \
    \ \
\
'
});

定义一个名为todo-title的待办标题组件 和 todo-items的待办内容组件

Vue.component('todo-title',{
        props:['title'],
        template:'
{{title}}
'
}); //这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来! Vue.component("todo-items",{ props:["item","index"], template:"
  • {{index+1}},{{item}}
  • "
    });

    slot通过name和组件绑定

     Vue.component('todo',{ var vm = new Vue({
            el:"#vue",
            data:{`在这里插入代码片`
                todoItems:['test1','test2','test3']
            }
        });
    
            template:'
    \ \
      \ \
    \
    '
    });

    实例化Vue并初始化数据

     var vm = new Vue({
            el:"#vue",
            data:{
                todoItems:['test1','test2','test3']
            }
        });
    
    

    将数据通过插槽插入预留出来的位置

    <todo>
            <todo-title slot="todo-title" v-bind:title="title"></todo-title>
            <todo-items slot="todo-items" v-for="item in todoItems" :item="item" ></todo-items>
        </todo>
    
    

    说明:

    • ​ slot:是绑定组件用的
    • ​ :title --> 是v-bind:title的缩写

    完整代码:

    <!DOCTYPE html>
    <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
        </head>
        <body>
            <!--view层,模板-->
            <div id="vue">
                <todo>
                    <todo-title slot="todo-title" v-bind:title="title"></todo-title>
                    <!---->
                    <!--如下为简写-->
                    <todo-items slot="todo-items" v-for="item in todoItems" :item="item" ></todo-items>
                </todo>
            </div>
            <!--1.导入Vue.js-->
            <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
            <script type="text/javascript">
                Vue.component('todo',{
                    template:'
    \ \
      \ \
    \
    '
    }); Vue.component('todo-title',{ props:['title'], template:'
    {{title}}
    '
    }); //这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来! Vue.component("todo-items",{ props:["item"], template:"
  • {{item}}
  • "
    }); var vm = new Vue({ el:"#vue", data:{ title:"mest study vue", todoItems:['test1','test2','test3'] } }); </script> </body> </html>

    7、小结

    核心:数据驱动,组件化

    优点:借鉴了AngularJS的模块化开发和React的虚拟Dom,虚拟Dom就是把Demo操作放到内存中执行;

    常用的属性:
    v-if
    v-else-if
    v-else
    v-for
    v-on绑定事件,简写@
    v-model数据双向绑定
    v-bind给组件绑定参数,简写:

    组件化:
    组合组件slot插槽
    组件内部绑定事件需要使用到this.$emit(“事件名”,参数);
    计算属性的特色,缓存计算数据


    三、第一个vue-cli项目

    3.1 Vue-cli简介

    vue-cli官方提供的一个脚手架,用于快速生成一个vue的项目模板
    预先定义好的目录结构及基础代码,就好比咱们在创建Maven项目时可以选择创建一个骨架项目,这个估计项目就是脚手架,我们的开发更加的快速

    3.2 环境配置

    Node.js

    下载地址: http://nodejs.cn/download/ 安装的时候一直下一步直到结束

    确认是否安装成功: 在cmd中运行node -v命令,查看是否能够输出版本号 在cmd中运行npm -v命令,查看是否能够输出版本号
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第14张图片

    安装node.js淘宝镜像加速器(cnpm)

    -g 就是全局安装
    npm install cnpm -g

    或使用如下语句解决npm速度慢的问题,但是每次install都需要 npm install
    –registry=https://registry.npm.taobao.org

    安装vue-cli

    cnpm install vue-cli-g
    #测试是否安装成功#查看可以基于哪些模板创建vue应用程序,通常我们选择webpack
    vue list

    3.3 第一个vue-cli应用程序

    创建一个基于webpack模板的vue应用程序

    1. 打开DOS系统窗口,进入到D盘

    D:\Work\IdeaProjects-Vue\

    1. 创建一个名为myvue项目。

    输入vue create mydemo 按下回车,
    提示选择配置方式,包括Vue2.x默认配置、Vue3.0默认配置和手动配置,使用方向键选择Vue3.0(第二个),然后只需等待几秒加载。
    提示:项目名称不能为大写,否则无法成功创建

    1. 项目创建成功后,在对应盘符可以看见项目文件夹,就可以启动项目。

    使用"cd myvue"进入项目文件夹,然后使用脚手架提供的“npm run serve”命令启动。

    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第15张图片

    1. 如图,出现对应端口号后,可以去本地浏览器访问端口,localhost:8080即可。
      Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第16张图片
      提示:创建或加载过程中可能出现加载失败需要fix的情况,当出现问题时,它会给出提示,我们按照提示来就行。通过 npm audit fix来修复就行。极端情况:重新install,再重复以上操作。

    四、webpack使用

    WebPack是一款模块加载器兼打包工具, 它能把各种资源, 如JS、JSX、ES 6、SASS、LESS、图片等都作为模块来处理和使用

    4.1 使用webpack

    安装:

    npm install webpack -g
    npm install webpack-cli -g

    测试安装成功:

    webpack -v
    webpack-cli -v

    配置:

    entry:入口文件, 指定Web Pack用哪个文件作为项目的入口
    output:输出, 指定WebPack把处理完成的文件放置到指定路径
    module:模块, 用于处理各种类型的文件
    plugins:插件, 如:热更新、代码重用等
    resolve:设置路径指向
    watch:监听, 用于设置文件改动后直接打包

    4.2 使用webpack

    创建项目:
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第17张图片

    创建一个webpack文件夹,使用idea打开

    1. 创建一个名为modules的目录,用于放置JS模块等资源文件
    2. 在modules下创建模块文件hello.js
    //暴露一个方法:sayHi
    exports.sayHi = function(){
        document.write("
    Hello Webpack
    "
    ); }
    1. 在modules下创建一个名为main.js的入口文件main.js,用于打包时设置entry属性
    //require 导入一个模块,就可以调用这个模块中的方法了
    var hello = require("./hello");
    hello.sayHi();
    
    
    1. 在项目目录下创建webpack.config.js配置文件,使用webpack命令打包
    module.exports = {
        entry:"./modules/main.js",
        output:{
            filename:"./js/bundle.js"
        }
    }
    
    1. 打包:
      说明:打包如果失败,就用管理员权限运行webpack

    在项目目录下创建HTML页面,如index.html,导入webpack打包后的JS文件

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>狂神说Java</title>
    </head>
    <body>
    <script src="dist/js/bundle.js"></script>
    </body>
    </html>
    
    

    直接运行index.html
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第18张图片
    提示:

    参数–watch 用于监听变化,如果要打包的东西有变化,就重新打包
    webpack --watch

    五、vue-router路由

    5.1 安装

    基于第一个vue-cli进行测试学习; 先查看node modules中是否存在vue-router, vue-router是一个插件包, 所以我们还是需要用n pm/cn pm来进行安装的

    npm install vue-router --save-dev
    

    如果在一个模块化工程中使用它,必须要通过Vue.use()明确地安装路由功能

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    Vue.use(VueRouter);
    
    

    5.2 测试路由

    • 删除第一个vue-cli项目中的没用的东西
    • components 目录下存放我们自己编写的组件
    • 定义几个自己的组件 Content.vue 、Main.vue、mest.vue

    Content.vue

    <template>
        <div>
            <h1>内容页</h1>
        </div>
    </template>
    
    <script>
        export default {
            name:"Content"
        }
    </script>
    
    

    Main.vue

    <template>
        <div>
            <h1>首页</h1>
        </div>
    </template>
    
    <script>
        export default {
            name:"Main"
        }
    </script>
    
    

    Mest.vue

    <template>
        <div>
            <h1>Mest</h1>
        </div>
    </template>
    
    <script>
        export default {
            name:"Mest"
        }
    </script>
    
    
    • 安装路由,在src目录下,新建一个文件夹:router,专门存放路由,配置路由index.js
    import Vue from'vue';
    //导入路由插件
    import Router from 'vue-router';
    //导入上面定义的组件
    import Content from '../components/Content';
    import Main from '../components/Main';
    import Mest from "../components/Mest";
    //安装路由
    // Vue.use(Router) ;
    createApp(App).use(router).mount('#app')
    //配置路由
    export default new Router({
        routes:[
            {
                //路由路径
                path:'/content',
                //路由名称
                name:'content',
                //跳转到组件
                component:Content
            },{
                //路由路径
                path:'/main',
                //路由名称
                name:'main',
                //跳转到组件
                component:Main
            }
            ,{
                //路由路径
                path:'/mest',
                //路由名称
                name:'main',
                //跳转到组件
                component:Mest
            }
        ]
    });
    
    
    • 在main.js中配置路由
    import Vue from 'vue';
    import App from './App';
    
    import router from './router';//自动扫描里面的路由配置
    Vue.config.productionTip = false;
    
    /* eslint-disable no-new */
    new Vue({
        el: '#app',
        router,
        components: { App },
        template: ''
    })
    
    
    • 在App.vue中使用路由
    <template>
      <div id="app">
        <!--
              router-link:默认会被渲染成一个<a>标签,to属性为指定链接
              router-view:用于渲染路由匹配到的组件
            -->
        <h1>cVzhanshi</h1>
        <router-link to="/main">首页</router-link>
        <router-link to="/content">内容</router-link>
        <router-link to="/mest">mest</router-link>
        <router-view></router-view>
      </div>
    </template>
    
    <script>
      export default {
        name: 'App',
      }
    </script>
    
    
    • 运行npm run dev,然后浏览器访问localhost:8080

    六、电影购票APP开发实战

    6.1脚手架搭建

    • 选择好项目存放的目录,使用Vue脚手架创建一个项目,项目名称为:buyfilm。

    vue create buyfilm

    按照图示选择功能,选择路由器使用history模式
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第19张图片
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第20张图片
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第21张图片

    6.2系统构架

    本项目使用的都是本地静态资源,主要是前端展示。
    其中public文件夹用来存放项目的静态文件。
    在src中,放置了所有的源码文件。components用来放置比较小的的、公用的组件。
    views用来放置三个主页面文件。
    routers用来放置路由,其中index.js文件是主路由。
    main.js是项目入口文件的JavaScript逻辑,在webpack打包之后将被注入到index.html页面中。
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第22张图片

    6.3项目运行效果:

    通过运行 :npm run serve 后会展示出本地网址,打开链接就能访问本购票系统。
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第23张图片
    App主页面展示效果:
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第24张图片
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第25张图片
    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第26张图片

    Vue.js 3.0快速入门(附电影购票APP开发实战源码)_第27张图片

    6.4设计项目组件

    6.4.1设计头部和底部导航组件

    1、头部组件(Header)

    <template>
        <header id="header">
            <h1>{{title}}</h1>
        </header>
    </template>
    
    <script>
        export default {
            name: "Header",
            // props是子组件访问父组件数据的唯一接口
            props:{
                title:{
                    type:String,
                    default:'风云电影'
                }
            }
        }
    </script>
    <!--scoped属性实现了私有化的样式-->
    <style scoped>
        #header{
            width: 100%;
            height: 50px;
            color: #ffffff;
            background: #e54847;
            border-bottom:1px solid #e54847;
            position: relative;
        }
        #header h1{
            font-size: 18px;
            text-align: center;
            line-height: 50px;
            font-weight: normal;
        }
        #header i{
            position: absolute;
            left: 5px;top: 50%;
            margin-top: -13px;
            font-size: 26px;
        }
    </style>
    

    2、底部导航组件(TabBar)

    <template>
        <div id="footer">
            <!--router-link>组件支持用户在具有路由功能的应用中单击导航。通过to属性指定目标地址,默认渲染为带有正确连接的标签,可以通过配置tag属性生成别的标签。另外,当目标路由成功激活时,链接元素自动设置一个表示激活的css类名-->
            <ul>
                <router-link tag="li" to="/movie">
                    <i class="fa fa-film"></i>
                    <p>电影</p>
                </router-link>
                <router-link tag="li" to="/cinema">
                    <i class="fa fa-youtube-square"></i>
                    <p>影院</p>
                </router-link>
                <router-link tag="li" to="/mine">
                    <i class="fa fa-user-circle"></i>
                    <p>我的</p>
                </router-link>
            </ul>
        </div>
    </template>
    
    <script>
        export default {
            name: "Tabbar"
        }
    </script>
    
    <style scoped>
        #footer{
            width: 100%;
            height: 50px;
            background: white;
            border-top: 2px solid #ebe8e3;
            position: fixed;
            left: 0;
            bottom: 0;
        }
        #footer ul{
            display: flex;
            text-align: center;
            height: 50px;
            align-items: center;
        }
        #footer ul li{
            flex: 1;
            height: 40px;
        }
        #footer li.active{color: #f03d37;}
        /* router-link-active:路由中自带的样式 选中时的颜色*/
        #footer li.router-link-active{color: #f03d37;}
        #footer ul i{font-size: 20px;}
        #footer ul p{
            font-size: 12px;
            line-height: 18px;
        }
    </style>
    

    6.4.2设计电影页面组件

    1、城市组件(City)

    <template>
        <div class="city_body">
            <div class="city_list">
                <div class="city_hot">
                    <h2>热门城市</h2>
                    <ul class="clearfix">
                        <li>北京</li>
                        <li>上海</li>
                        <li>天津</li>
                        <li>合肥</li>
                        <li>郑州</li>
                    </ul>
                </div>
                <div class="city_sort">
                    <div>
                        <h2>A</h2>
                        <ul>
                            <li>阿克苏</li>
                            <li>安康</li>
                            <li>安庆</li>
                        </ul>
                    </div>
                    <div>
                        <h2>B</h2>
                        <ul>
                            <li>白山</li>
                            <li>白城</li>
                            <li>宝鸡</li>
                        </ul>
                    </div>
                    <div>
                        <h2>C</h2>
                        <ul>
                            <li>沧州</li>
                            <li>长春</li>
                            <li>昌吉</li>
                        </ul>
                    </div>
                    <div>
                        <h2>D</h2>
                        <ul>
                            <li>大理</li>
                            <li>大连</li>
                            <li>大庆</li>
                        </ul>
                    </div>
                    <div>
                        <h2>E</h2>
                        <ul>
                            <li>鄂尔多斯</li>
                            <li>恩施</li>
                            <li>鄂州</li>
                        </ul>
                    </div>
                </div>
            </div>
            <div class="city_index">
                <ul>
                    <li>A</li>
                    <li>B</li>
                    <li>C</li>
                    <li>D</li>
                    <li>E</li>
                </ul>
            </div>
        </div>
    </template>
    <script>
        export default {
            name: "City"
        }
    </script>
    <style scoped>
        #content .city_body{
            margin-top: 45px;
            display: flex;
            width: 100%;
            position: absolute;
            top: 0;
            bottom: 0;
        }
        .city_body .city_list{
            flex: 1;
            overflow: auto;
            background: #fff5f0;
        }
        .city_body .city_list::-webkit-scrollbar{
            background-color: transparent;
            width: 0;
        }
        .city_body .city_hot{
            margin-top: 20px;
        }
        .city_body .city_hot h2{
            padding-left: 15px;
            line-height: 30px;
            font-size: 14px;
            background: #f0f0f0;
            font-weight:normal;
        }
        .city_body .city_hot ul li{
            float: left;
            background: #fff;
            width: 29%;
            height: 33px;
            margin-top: 15px;
            margin-left: 3%;
            padding:0 4px;
            border: 1px solid #e6e6e6;
            border-radius: 3px;
            line-height: 33px;
            text-align: center;
            box-sizing: border-box;
        }
        .city_body .city_sort div{
            margin-top: 20px;
        }
        .city_body .city_sort h2{
            padding-left: 15px;
            line-height: 30px;
            font-size: 14px;
            background: #f0f0f0;
            font-weight: normal;
        }
        .city_body .city_sort ul{
            padding-left: 10px;
            margin-top: 10px;
        }
        .city_body .city_sort ul li{
            line-height: 30px;
        }
        .city_body .city_index{
            width: 20px;
            display: flex;
            flex-direction: column;
            justify-content: center;
            text-align: center;
            border-left:1px solid #e6e6e6;
        }
    </style>
    

    2、正在热映(NowPlaying)

    <template>
        <div class="movie_body">
            <ul>
                <li>
                    <div class="pic_show"><img src="../../../public/images/001.png" alt=""></div>
                    <div class="info_list">
                        <h2>机械师2:复活</h2>
                        <p>观众评<span class="grade"> 8.9</span></p>
                        <p>主演: 杰森·斯坦森 杰西卡·阿尔芭 汤米·李·琼斯 杨紫琼 山姆·哈兹尔丁</p>
                        <p>今天50家影院放映800</p>
                    </div>
                    <div class="btn_mall">
                        购票
                    </div>
                </li>
                <li>
                    <div class="pic_show"><img src="../../../public/images/002.png" alt=""></div>
                    <div class="info_list">
                        <h2>敢死队</h2>
                        <p>观众评<span class="grade"> 8.7</span></p>
                        <p>主演: 西尔维斯特·史泰龙,杰森·斯坦森,梅尔·吉布森</p>
                        <p>今天50家影院放映750</p>
                    </div>
                    <div class="btn_mall">
                        购票
                    </div>
                </li>
                <li>
                    <div class="pic_show"><img src="../../../public/images/003.png" alt=""></div>
                    <div class="info_list">
                        <h2>最后的巫师猎人</h2>
                        <p>观众评<span class="grade"> 8.4</span></p>
                        <p>主演: 范·迪塞尔,萝斯·莱斯利,伊利亚·伍德,迈克尔·凯恩,丽纳·欧文</p>
                        <p>今天50家影院放映600</p>
                    </div>
                    <div class="btn_mall">
                        购票
                    </div>
                </li>
                <li>
                    <div class="pic_show"><img src="../../../public/images/004.png" alt=""></div>
                    <div class="info_list">
                        <h2>饥饿游戏3</h2>
                        <p>观众评<span class="grade"> 7.6</span></p>
                        <p>主演: 詹妮弗·劳伦斯,乔什·哈切森,利亚姆·海姆斯沃斯</p>
                        <p>今天50家影院放映550</p>
                    </div>
                    <div class="btn_mall">
                        购票
                    </div>
                </li>
                <li>
                    <div class="pic_show"><img src="../../../public/images/005.png" alt=""></div>
                    <div class="info_list">
                        <h2>钢铁骑士</h2>
                        <p>观众评<span class="grade"> 7.3</span></p>
                        <p>主演: 本·温切尔,乔什·布雷纳,玛丽亚·贝罗, 迈克·道尔, 安迪·加西亚</p>
                        <p>今天50家影院放映500</p>
                    </div>
                    <div class="btn_mall">
                        购票
                    </div>
                </li>
                <li>
                    <div class="pic_show"><img src="../../../public/images/006.png" alt=""></div>
                    <div class="info_list">
                        <h2>奔跑者
                        </h2>
                        <p>观众评<span class="grade"> 6.6</span></p>
                        <p>主演: 尼古拉斯·凯奇,康妮·尼尔森,莎拉·保罗森,彼得·方达</p>
                        <p>今天50家影院放映500</p>
                    </div>
                    <div class="btn_mall">
                        购票
                    </div>
                </li>
            </ul>
        </div>
    </template>
    <script>
        export default {
            name: "NowPlaying"
        }
    </script>
    <style scoped>
        #content .movie_body{
            flex: 1;overflow: auto;
        }
        .movie_body ul{
            margin: 0 12px;
            overflow: hidden;
        }
        .movie_body ul li{margin-top: 12px;display: flex;align-items: center;border-bottom: 1px solid #e6e6e6;padding-bottom: 10px;}
        .movie_body .pic_show{width: 64px;height: 90px;}
        .movie_body .pic_show img{width: 100%;}
        .movie_body .info_list{margin-left:10px;flex: 1;position: relative; }
        .movie_body .info_list h2{
            font-size: 17px; line-height: 24px;
            width: 150px;overflow: hidden;
            white-space: nowrap;
            text-overflow:ellipsis ;
        }
        .movie_body .info_list p{
            font-size:13px;
            color: #666;
            line-height: 22px;
            width: 200px;
            overflow: hidden;
            white-space: nowrap;
            text-overflow:ellipsis ;
        }
        .movie_body .info_list .grade{
            font-weight: 700;
            color: #faaf00;
            font-size: 15px;
        }
        .movie_body .info_list img{
            width: 50px;
            position: absolute;
            right: 10px;
            top: 5px;
        }
        .movie_body .btn_mall, .movie_body .btn_pre{
            width: 47px;
            height: 27px;
            line-height: 28px;
            text-align: center;
            background-color: #f03d37;
            color: #fff;
            border-radius: 4px;
            font-size: 12px;
            cursor: pointer;
    
        }
        .movie_body .btn_pre{
            background-color: #3c9fe6;
        }
    </style>
    

    3、即将上映(ComingSoon)

    <template>
        <div class="movie_body">
            <ul>
                <li>
                    <div class="pic_show"><img src="../../../public/images/007.png" alt=""></div>
                    <div class="info_list">
                        <h2>佐罗和麦克斯</h2>
                        <p><span class="person">46465</span>人想看</p>
                        <p>主演:格兰特·鲍尔 艾米·斯马特 博伊德·肯斯特纳</p>
                        <p>未来30天内上映</p>
                    </div>
                    <div class="btn_pre">
                        预售
                    </div>
                </li>
                <li>
                    <div class="pic_show"><img src="../../../public/images/008.png" alt=""></div>
                    <div class="info_list">
                        <h2>废材特工</h2>
                        <p><span class="person">64645</span>人想看</p>
                        <p>主演: 杰西·艾森伯格,克里斯汀·斯图尔特,约翰·雷吉扎莫</p>
                        <p>未来30天内上映</p>
                    </div>
                    <div class="btn_pre">
                        预售
                    </div>
                </li>
                <li>
                    <div class="pic_show"><img src="../../../public/images/009.png" alt=""></div>
                    <div class="info_list">
                        <h2>凤凰城遗忘录</h2>
                        <p><span class="person">42465</span>人想看</p>
                        <p>主演:Clint Jordan</p>
                        <p>未来30天内上映</p>
                    </div>
                    <div class="btn_pre">
                        预售
                    </div>
                </li>
                <li>
                    <div class="pic_show"><img src="../../../public/images/010.png" alt=""></div>
                    <div class="info_list">
                        <h2>新灰姑娘</h2>
                        <p><span class="person">46465</span>人想看</p>
                        <p>主演: Cassandra Morris,Kristen Day</p>
                        <p>未来30天内上映</p>
                    </div>
                    <div class="btn_pre">
                        预售
                    </div>
                </li>
                <li>
                    <div class="pic_show"><img src="../../../public/images/011.png" alt=""></div>
                    <div class="info_list">
                        <h2>鲨卷风4:四度觉醒</h2>
                        <p><span class="person">38465</span>人想看</p>
                        <p>主演: 塔拉·雷德,Ian Ziering,Masiela Lusha</p>
                        <p>未来30天内上映</p>
                    </div>
                    <div class="btn_pre">
                        预售
                    </div>
                </li>
                <li>
                    <div class="pic_show"><img src="../../../public/images/012.png" alt=""></div>
                    <div class="info_list">
                        <h2>全境警戒</h2>
                        <p><span class="person">46465</span>人想看</p>
                        <p>主演: 戴夫·巴蒂斯塔,布兰特妮·斯诺,Angelic Zambrana</p>
                        <p>未来30天内上映</p>
                    </div>
                    <div class="btn_pre">
                        预售
                    </div>
                </li>
            </ul>
        </div>
    </template>
    
    <script>
        export default {
            name: "ComingSoon"
        }
    </script>
    
    <style scoped>
        #content .movie_body{
            flex: 1;overflow: auto;
        }
        .movie_body ul{
            margin: 0 12px;
            overflow: hidden;
        }
        .movie_body ul li{margin-top: 12px;display: flex;align-items: center;border-bottom: 1px solid #e6e6e6;padding-bottom: 10px;}
        .movie_body .pic_show{width: 64px;height: 90px;}
        .movie_body .pic_show img{width: 100%;}
        .movie_body .info_list{margin-left:10px;flex: 1;position: relative; }
        .movie_body .info_list h2{
            font-size: 17px; line-height: 24px;
            width: 150px;overflow: hidden;
            white-space: nowrap;
            text-overflow:ellipsis ;
        }
        .movie_body .info_list p{
            font-size:13px;
            color: #666;
            line-height: 22px;
            width: 200px;
            overflow: hidden;
            white-space: nowrap;
            text-overflow:ellipsis ;
        }
        .movie_body .info_list .grade{
            font-weight: 700;
            color: #faaf00;
            font-size: 15px;
        }
        .movie_body .info_list img{
            width: 50px;
            position: absolute;
            right: 10px;
            top: 5px;
        }
        .movie_body .btn_mall, .movie_body .btn_pre{
            width: 47px;
            height: 27px;
            line-height: 28px;
            text-align: center;
            background-color: #f03d37;
            color: #fff;
            border-radius: 4px;
            font-size: 12px;
            cursor: pointer;
    
        }
        .movie_body .btn_pre{
            background-color: #3c9fe6;
        }
    </style>
    

    4、搜索组件(Search)

    <template>
        <div class="search_body">
            <div class="search_input">
                <div class="search_input_wrapper">
                    <i class="fa fa-search"></i>
                    <input type="text">
                </div>
            </div>
            <div class="search_result">
                <h3>电影/电视剧/综艺</h3>
                <ul>
                    <li>
                        <div class="img"><img src="../../../public/images/001.png" alt=""></div>
                        <div class="info">
                            <p><span>机械师2 </span><span>8.9</span></p>
                            <p>剧情,喜剧,犯罪</p>
                            <p>2020-6-30</p>
                        </div>
                    </li>
                </ul>
            </div>
        </div>
    </template>
    <script>
        export default {
            name: "Search"
        }
    </script>
    <style scoped>
        #content .search_body{
            flex: 1;
            overflow: auto;
        }
        .search_body .search_input{
            padding: 8px 10px;
            background-color: #f5f5f5;
            border-bottom: 1px solid #e5e5e5;
        }
        .search_body .search_input_wrapper{
            padding: 0 10px;
            border: 1px solid #e6e6e6;
            border-radius: 5px;
            background-color: #fff;
            display: flex;
        }
        .search_body .search_input_wrapper i{
            font-size: 16px;
            padding: 4px 0;
        }
        .search_body .search_input_wrapper input{
            border: none;
            font-size: 13px;
            color: #333;
            padding: 4px 0;
            outline: none;
        }
        .search_body .search_result h3{
            font-size: 15px;
            color: #999;
            padding: 9px 15px;
            border-bottom: 1px solid #e6e6e6;
        }
        .search_body .search_result li{
            border-bottom: 1px #c9c9c9 dashed;
            padding: 10px 15px;
            box-sizing: border-box;
            display: flex;
        }
        .search_body .search_result .img{
            width: 60px;
            float: left;
        }
        .search_body .search_result .img img{
            width: 100%;
        }
        .search_body .search_result .info{
            float: left;
            margin-left: 15px;
            flex: 1;
        }
        .search_body .search_result .info p{
            height: 22px;
            display: flex;
            line-height: 22px;
            font-size: 12px;
        }
        .search_body .search_result .info p:nth-of-type(1) span:nth-of-type(1){
            font-size: 18px;
            flex: 1;
        }
        .search_body .search_result .info p:nth-of-type(1) span:nth-of-type(2){
            font-size: 16px;
            color: #fc7103;
        }
    </style>
    

    6.4.3设计影院页面组件

    影院列表组件(CiList)

    <template>
        <div class="cinema_body">
            <ul>
                <li>
                    <div>
                        <span>大地影院延庆金锣湾店</span>
                        <span class="q"><span class="price"> 38.5</span> 元起</span>
                    </div>
                    <div class="address">
                        <span>延庆区北街39号H座首层</span>
                        <span> >100km </span>
                    </div>
                    <div class="card">
                        <div>小吃</div>
                        <div>折扣卡</div>
                    </div>
                </li>
                <li>
                    <div>
                        <span>燕山影剧院</span>
                        <span class="q"><span class="price"> 37.5</span> 元起</span>
                    </div>
                    <div class="address">
                        <span>房山区燕山岗南路3</span>
                        <span> >120km</span>
                    </div>
                    <div class="card">
                        <div>小吃</div>
                        <div>折扣卡</div>
                    </div>
                </li>
                <li>
                    <div>
                        <span>万达影城昌平保利光魔店</span>
                        <span class="q"><span class="price"> 37.9</span> 元起</span>
                    </div>
                    <div class="address">
                        <span>昌平区鼓楼南街佳莲时代广场四层</span>
                        <span> >80km </span>
                    </div>
                    <div class="card">
                        <div>小吃</div>
                        <div>折扣卡</div>
                    </div>
                </li>
                <li>
                    <div>
                        <span>门头沟影剧院</span>
                        <span class="q"><span class="price"> 30.9</span> 元起</span>
                    </div>
                    <div class="address">
                        <span>门头沟区新桥大街12</span>
                        <span>  >110km </span>
                    </div>
                    <div class="card">
                        <div>小吃</div>
                        <div>折扣卡</div>
                    </div>
                </li>
            </ul>
        </div>
    </template>
    <script>
        export default {
            name: "CiList"
        }
    </script>
    <style scoped>
        #content .cinema_body{
            flex: 1;
            overflow: auto;
        }
        .cinema_body ul{
            padding: 20px;
        }
        .cinema_body li{
            border-bottom: 1px solid #e6e6e6;
            margin-bottom: 20px;
        }
        .cinema_body div{
            margin-bottom: 10px;
        }
        .cinema_body .q{
            font-size: 11px;
            color: #f03d37;
        }
        .cinema_body .price{
            font-size: 18px;
        }
        .cinema_body .address{
            font-size: 13px;
            color:#666;
        }
        .cinema_body .address span:nth-of-type(2){
            float: right;
        }
        .cinema_body .card{
            display: flex;
        }
        .cinema_body .card div{
            padding: 0 3px;
            height: 15px;
            line-height: 15px;
            border-radius:2px;
            color: #f90;
            border:1px solid #f90;
        }
        .cinema_body .card div.or{
            color: #f90;
            border: 1px solid #f90;
        }
        .cinema_body .card div.bl{
            color: #589daf;
            border: 1px solid #589daf;
        }
    </style>
    

    6.4.4设计我的页面组件

    只有一个登录/注册组件(未实现后端交互)

    <template>
        <div class="login_body">
            <div>
                <input class="login_text" type="text" placeholder="账号/手机号/邮箱">
            </div>
            <div>
                <input class="login_text" type="password" placeholder="请输入您的密码">
            </div>
            <div class="login_btn">
                <input type="submit" value="登录">
            </div>
            <div class="login_link">
                <a href="#">立即注册</a>
                <a href="#">找回密码</a>
            </div>
        </div>
       
    </template>
    
    <script>
        export default {
            name: "Login"
        }
    </script>
    
    <style scoped>
        #content .login_body{
            width: 100%;
        }
        .login_body .login_text{
            width: 100%;
            height: 40px;
            border: none;
            border-bottom: 1px #ccc solid;
            margin:0 5px;
            outline: none;
        }
        .login_body .login_btn{
            height: 50px;
            margin: 10px;
        }
        .login_body .login_btn input{
            display: block;
            width: 100%;
            height: 100%;
            background: #e54847;
            border-radius: 3px;
            border: none;
            color: white;
        }
        .login_body .login_link{
            display: flex;
            justify-content: space-between;
        }
        .login_body .login_link a{
            text-decoration: none;
            margin: 0 5px;
            font-size: 12px;
            color:#e54847;
        }
    </style>
    

    6.5设计项目页面组件及路由配置

    6.5.1电影页面组件及路由

    <template>
        <div id="main">
            <!-- 头部组件-->
            <Header title="风云电影"></Header>
            <div id="content">
       
                <div class="movie_menu">
                    <router-link tag="div" to="/movie/city" class="city_name">
                        <span>北京 </span><i class="fa fa-caret-down"></i>
                    </router-link>
                    <div class="hot_swtich">
                        <router-link tag="div" to="/movie/nowPlaying" class="hot_item active">正在热映</router-link>
                        <router-link tag="div" to="/movie/comingSoon" class="hot_item">即将上映</router-link>
                    </div>
                    <router-link tag="div" to="/movie/search" class="search_entry">
                        <i class="fa fa-search"></i>
                    </router-link>
                </div>
                <!--二级路由渲染-->
                <keep-alive>
                    <router-view></router-view>
                </keep-alive>
    
            </div>
            <!-- 尾部组件-->
            <TabBar></TabBar>
        </div>
    </template>
    <script>
        import Header from '../../components/Header';
        import TabBar from '../../components/TabBar';
        export default {
            name:'Movie',
            components:{
                Header,
                TabBar
            }
        }
    </script>
    <style scoped>
        #content .movie_menu{
            width: 100%;
            height: 45px;
            border-bottom: 1px solid #e6e6e6;
            display: flex;
            justify-content: space-between;
        }
        .movie_menu .city_name{
            margin-left: 20px;
            height: 100%;
            line-height: 45px;
        }
        .movie_menu .city_name.router-link-active{
            color: #ef4238;
            border-bottom: 2px solid #ef4238;
            box-sizing: border-box;
        }
        .movie_menu .hot_swtich{
            display: flex;
            height: 100%;
            line-height: 45px;
        }
        .movie_menu .hot_item{
            font-size: 15px;
            color: #666;
            width: 80px;
            text-align: center;
            margin: 0 12px;
            font-weight: 700;
        }
        .movie_menu .hot_item.router-link-active{
            color: #ef4238;
            border-bottom:2px solid #ef4238;
        }
        .movie_menu .search_entry{
            margin-right: 20px;
            height: 100%;
            line-height: 45px;
        }
        .movie_menu .search_entry.router-link-active{
            color: #ef4238;
            border-bottom:2px solid #ef4238;
            box-sizing: border-box;
        }
        .movie_menu .search_entry i{
            font-size: 24px;
            color: red;
        }
    </style>
    

    配置路由:

    // movie路由
    export default {
        path:'/movie',
        //按需载入的方式
        component:()=>import('../../views/Movie'),
        // 二级路由,使用children进行配置
        children:[
            {
                path:'city',
                component:()=>import('../../components/City')
            },
            {
                path:'nowPlaying',
                component:()=>import('../../components/NowPlaying')
            },
            {
                path:'comingSoon',
                component:()=>import('../../components/ComingSoon')
            },
            {
                path:'search',
                component:()=>import('../../components/Search')
            },
            // 重定向:当路径为/movie时,重定向到/movie/nowPlaying路径
            {
                path:'/movie',
                redirect:'/movie/nowPlaying'
            }
        ]
    }
    

    6.5.2影院页面组件及路由

    <template>
        <div id="main">
            <Header title="风云影院"></Header>
            <div id="content">
                <div class="cinema_menu">
                    <div class="city_switch">
                        全城 <i class="fa fa-caret-down"></i>
                    </div>
                    <div class="city_switch">
                        品牌 <i class="fa fa-caret-down"></i>
                    </div>
                    <div class="city_switch">
                        特色 <i class="fa fa-caret-down"></i>
                    </div>
                </div>
                <CiList></CiList>
            </div>
            <TabBar></TabBar>
        </div>
    </template>
    <script>
        import Header from '../../components/Header';
        import TabBar from '../../components/TabBar';
        import CiList from '../../components/CiList';
        export default {
            name:'Cinema',
            components:{
                Header,
                TabBar,
                CiList
            }
        }
    </script>
    <style scoped>
    #content .cinema_menu{
        width: 100%;
        height: 45px;
        border-bottom: 1px solid #e6e6e6;
        display: flex;
        justify-content: space-around;
        align-items: center;
        background: white;
    }
    </style>
    

    配置路由:

    // Cinema路由
    export default {
        path:'/cinema',
        component:()=>import('../../views/Cinema')
    }
    

    6.5.3我的页面组件及路由

    <template>
        <div id="main">
            <Header title="我的影院"></Header>
            <div id="content">
                <Login></Login>
            </div>
            <TabBar></TabBar>
        </div>
    </template>
    <script>
        import Header from '../../components/Header';
        import TabBar from '../../components/TabBar';
        import Login from '../../components/Login';
        export default {
            name:'Mine',
            components:{
                Header,
                TabBar,
                Login
            }
        }
    </script>
    <style scoped></style>
    

    配置路由:

    // mine路由
    export default {
        path:'/mine',
        component:()=>import('../../views/Mine')
    }
    

    总结

    百度文库源码提取链接:https://pan.baidu.com/s/1k_65SO6rIQxDaTe-So3lpw
    提取码:点赞文章后私聊
    参考文献:《Vue.js 3.0从入门到精通》清华大学出版社
    文档参考:https://blog.csdn.net/qq_45408390/article/details/118151297
    Vue中文文档:https://cn.vuejs.org/v2/guide/

    你可能感兴趣的:(idea,vue.js,es6,前端框架,webpack)