AngularJS初体验-02
Posted admin-NaN
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AngularJS初体验-02相关的知识,希望对你有一定的参考价值。
一、复习(数据重复报错)
数据重复,val in list 这里会报错,所有加了一个东西在后面加track by $index
<li ng-repeat="num in nums track by $index">{{num}}</li>
二、作用域
根作用域对应的是ng-app所在标签
scope是作用域的意思(相当于this)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="angular.js"></script>
</head>
<body ng-app="App" ng-init="names=\'舒见佳\'">
<div class="box" ng-controller="DemoCtrl">
<h1>{{names}}</h1>
<input type="button" value="电击" ng-click="name()">
<div class="box1" ng-controller="DemoCtrl2">
<h1>{{names}}</h1>
<input type="button" value="电击" ng-click="name()">
</div>
</div>
<script>
var App=angular.module(\'App\',[]);
App.controller(\'DemoCtrl\',[\'$scope\',function($scope){
$scope.name=function(){
alert(\'!!!∑(゚Д゚ノ)ノψ(*`ー´)ψ(•́へ•́╬)ヽ(ー_ー)ノ|ू・ω・` )\');
}
}]);
App.controller(\'DemoCtrl2\',[\'$scope\',function($scope){
// $scope.name=function(){
// alert(\'!!!∑(゚Д゚ノ)ノ\');
// }
}]);
</script>
</body>
</html>
三、过滤器
在AngularJS中使用过滤器格式化展示数据,在“{{}}”中使用“|”来调用过滤器,使用“:”传递参数。
下面的例子中date就是过滤器
日期
<dd>{{now|date:"yyyy-MM-dd hh:mm:ss"}}</dd>
排序方式
<dd>排序:{{orderBy|orderBy:\'age\':true}}</dd>
筛选数据
<dd>筛选数据:{{obj|filter:{name:\'xiao\'} }}</dd>
注意要有空格
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="angular.js"></script>
</head>
<body ng-app="App">
<dl ng-controller="DemoCtrl">
<dt>过滤器</dt>
<dd>{{now|date:"yyyy-MM-dd EEEE/EEE hh:mm:ss"}}</dd>
<dd>商品价格:{{price|currency:"¥":4}}</dd>
<dd>介绍:{{info|limitTo:-2}}</dd>
<dd>数组:{{list|limitTo:-2}}</dd>
<dd>小写:{{lowercase|lowercase}}</dd>
<dd>大写:{{uppercase|uppercase}}</dd>
<dd>数字格式:{{number|number:2}}</dd>
<dd>排序:{{orderBy|orderBy:\'\':true}}</dd>
<dd>json:{{obj|json}}</dd>
<dd>筛选数据:{{objs|filter:\'p\'}}</dd>
<dd>连写:{{uppercase|uppercase|limitTo:2}}</dd>
</dl>
<script>
var App=angular.module(\'App\',[]);
App.controller(\'DemoCtrl\',[\'$scope\',function($scope){
$scope.now=new Date;
$scope.price=12.345;
$scope.info=\'jiajia\';
$scope.list=[\'jiajia\',\'shushu\',\'jianjian\'];
$scope.lowercase=\'jiajia\';
$scope.uppercase=\'jiJJia\';
$scope.number=12.34322;
$scope.orderBy=[12,43,1,3,12,45,31,12,3];
$scope.obj={name:\'jiajia\', json:\'shushu\',papa:\'jianjian\'};
$scope.objs=[\'jiajiap\',\'shushu\',\'jianjian\'];
}]);
</script>
</body>
</html>
各种参数
1、currency[货币] 将数值格式化为货币格式
2、date日期格式化,年(y)、月(M)、日(d)、星期(EEEE/EEE)、时(H/h)、分(m)、秒(s)、毫秒(.sss),也可以组合到一起使用。
3、filter在给定数组中选择满足条件的一个子集,并返回一个新数组,其条件可以是一个字符串、对象、函数
4、json将Javascrip对象转成JSON字符串。
5、limitTo取出字符串或数组的前(正数)几位或后(负数)几位
6、lowercase将文本转换成小写格式
7、uppercase将文本转换成大写格式
8、number数字格式化,可控制小位位数
9、orderBy对数组进行排序,第2个参数是布尔值可控制方向(正序或倒序)
四、自定义过滤器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="angular.js"></script>
</head>
<body ng-app="App">
<dl ng-controller="DemoCtrl">
<dt>自定义过滤器</dt>
<dd>{{name|demo}}</dd>
</dl>
<script>
var App=angular.module(\'App\',[]);
//定义一个控制器
App.controller(\'DemoCtrl\',[\'$scope\',function($scope){
$scope.name=\'itcast\';
}]);
// 定义一个指令directive
App.directive(\'demo\',function(){
});
// 定义一个过滤器filter
//需要两个参数,过滤器的名字,和依赖关系
App.filter(\'demo\',function(){
// console.log(1);
// 必须要返回一个函数
return function(arg){
// 再次完成数据格式化的逻辑并且Angularjs会将需要格式化处理的数据当成第一个参数传递进来
// console.log(arg);
return \'你好\' +arg;
}
});
//上诉定义了最基本的过滤器,其使用方法与内置一样
</script>
</body>
</html>
首字母大写:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="angular.js"></script>
</head>
<body ng-app="App">
<dl ng-controller="DemoCtrl">
<dt>自定义过滤器</dt>
<dd>{{name|capitalize}}</dd>
</dl>
<script>
var App=angular.module(\'App\',[]);
App.controller(\'DemoCtrl\',[\'$scope\',function($scope){
$scope.name=\'itcast\';
}]);
App.filter(\'capitalize\',function(){
return function(input){
return input[0].toUpperCase()+input.slice(1);
}
});
</script>
</body>
</html>
五、依赖注入
AngularJS将一些通用的功能进行了封装,开发者只需要根据自己的情况进行调用即可。
如果开发者想要使用AngularJS内部封装好的通用的功能,必须先把他们加载进来,由此也便产生相互的依赖关系。
也就意味着我们必须有一个方法能够很好的解决依赖关系。
define([\'jquery\'],function($){});
上诉方法能够很好的解决依赖关系
这种方法叫依赖注入
依赖+注入
通过注入的方式来解决依赖
以参数的形式传递到函数内部的过程称为注入
行内式依赖注入:
在AngularJS中封装了一个通用功能叫$scope,用来实现数据绑定
如果在现实开发当中,开发者想要将数据绑定到视图上就必须用$scope
通过数组前面几个单元来指定依赖关系,最后一个单元永远是一个回调函数
在AngularJS中封装一个通用功能 $rootScope,用来直接设置根作用域。
App.controller(\'DemoCtrl\',[\'$scope\',\'$rootScope\',function($scope,$rootScope){ }]);
注入和依赖合并了。这里的$scope即是声明依赖也是注入依赖
App.controller(\'DemoCtrl\',function($scope){ });
六、服务
服务是一个对象或函数,对外提供特定的功能
(一)、内置服务:
1、$log打印调试信息
AngularJS将调试信息封装成了一个服务,开发过程中只需要调用这个服务即可
当前开发依赖一个$log的通用功能(服务)
$log是一个对象,对外开放一些方法
App.controller(\'DemoCtrl\',function($scope,$log){
$log.log(123);
$log.info(123);
$log.error(123);
$log.warn(123);
//可以通过配置服务将此功能打开
$log.debug(123);
});
2、$timeout&$interval对原生javascript中的setTimeout和setInterval进行了封装。
延时:
App.controller(\'DemoCtrl\',function($scope,$timeout){
$timeout(function(){
$scope.name="(^_−)☆o(´^`)oo(╥﹏╥)oo(´^`)o(•́へ•́╬)ψ(*`ー´)ψ";
},3000);
});
计时:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="angular.js"></script>
</head>
<body ng-app="App">
<dl ng-controller="DemoCtrl">
<dt></dt>
<dd><h3>{{name|date:\'yyyy-MM-dd hh-mm-ss\'}}</h3></dd>
<dd><button ng-click="stop()">停止</button></dd>
</dl>
<script>
var App=angular.module(\'App\',[]);
App.controller(\'DemoCtrl\',function($scope,$interval){
$scope.name=new Date();
var timer=$interval(function(){
$scope.name=new Date();
},1000);
$scope.stop=function(){
$interval.cancel(timer);;
};
});
</script>
</body>
</html>
3、$filter在控制器中格式化数据。
$filter是一个函数,并且可以接受一些参数,根据参数的不同过滤器所能处理的数据格式也不同。
----
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="angular.js"></script>
</head>
<body ng-app="App">
<dl ng-controller="DemoCtrl">
<dt></dt>
<dd><h3>{{now}}</h3></dd>
<dd><h3>{{price}}</h3></dd>
</dl>
<script>
var App=angular.module(\'App\',[]);
App.controller(\'DemoCtrl\',function($scope,$filter){
var date=$filter(\'date\');
var currency=$filter(\'currency\');
$scope.now=date(new Date(),\'yyyy-MM-dd hh-mm-ss\');
$scope.price=currency(12.3434);
});
</script>
</body>
</html>
4、$http用于向服务端发起异步请求。
$http是一个函数
用法:
$http([
url:\'\',//请求地址
method:\'\',//请求方式
data:\'\',//post方式数据
params:\'\',//get方式数据
//向服务器发送一些数据,根据请求方式不同,所使用的方法也不一样
headers :{
//请求头信息
\'Content-Type\':\'\';
}
]).then(function (data) {
//成功后的回调
},function( ) {
//失败后的回调
});
小例子:无数据
html文件:
App.controller(\'DemoCtrl\', [\'$scope\', \'$http\', function ($scope, $http) {
$http({
url: \'./example.php\',
method: \'get\'
}).then(function (res) {
$scope.users = res.data;
});
}]);
php文件:
<?php
$users = array(
array(\'name\'=>\'小明\', \'age\'=>18),
array(\'name\'=>\'小米\', \'age\'=>16),
array(\'name\'=>\'小红\', \'age\'=>17)
);
echo json_encode($users);
?>
为什么当post形式发送数据需要设置请求头,是因为post的数据是以请求主体的方式传递的
当请求方式为get时是没有请求主体的,所以请求头部不是必须设置的
结论:我们是否需要设置我们的请求头,其实参考的标准为数据是不是以请求主体的方式传递的。
Content-Type:"text/html"的含义:告诉服务器我现在使用哪个语言在跟你交流。
发送请求时,服务算对应接口有两种类型:
(1)soap类型
在jQuery中默认支持是soap类型。
(2)restfull类型
AngularJs默认支持的是restfull类型
服务器会根据我们的Content-Type值的不同,对数据的处理也不一样。如果客户端(浏览器)以Content-Type:\'application/x-www-form-urlencoded\'类型传递数据,在PHP中使用$_POST接受,
如果客户端(浏览器)以Content-Type:\'application/json\'类型传递数据,在PHP中不能使用$_POST接受,
七、跨域
url同域的 XMLHttpRequest是可以使用的
url跨域的XMLHttpRequest是不可用的
JSONP反向代理
JSONP器本质是浏览器发送一个前端事先定义好的函数的名字,服务端获取这个函数的名字,然后拼凑"()"将其返回。
在HTML之中有一些属性,天然就支持跨域访问,例如link下的href,还有img下的src,iframe的src
总之src和href属性可以跨域
发起请求,请求地址只代表资源的位置与后缀无关。
如果发起请求,其实是在向服务器索要内容,服务器根据请求资源的后缀做出不同的结果。
如果请求的资源是纯静态的,服务器直接返回,如果请求资源是动态的(.php),服务器会调用php的解析器,对php程序进行解析。服务器在将php解析器解析的结果返回给浏览器。
八、自定义服务
1、factory方法
需要两个参数:1、服务的名称2、依赖
App.factory(\'timer\',[\'$scope\',function($scope){
}]);
//上诉代码定义了基本的服务,要使用自定义服务与内置服务一致,要想是服务更有意义,返回值因为函数或对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AngularJS 自定义服务</title>
<script src="./libs/angular.min.js"></script>
</head>
<body ng-app="App">
<div ng-controller="DemoCtrl">
<h1>{{now}}{{time}}</h1>
</div>
<script>
var App = angular.module(\'App\', []); r
App.controller(\'DemoCtrl\', [\'$scope\', \'timer\', \'showTime\', function($scope, timer, showTime) {
$scope.now = showTime.now;
$scope.time = showTime.format(\'hh:mm:ss\');
}])
App.factory(\'timer\', [function () {
return function () {
console.log(\'返回值为函数\');
}
}]);
App.factory(\'showTime\', [\'$filter\', function ($filter) {
return {
now: $filter(\'date\')(new Date(), \'yyyy-MM-dd\'),
format: function (arg) {
return $filter(\'date\')(new Date(), arg);
}
}
}])
</script>
</body>
</html>
2、service方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AngularJS 自定义服务</title>
<script src="./libs/angular.min.js"></script>
</head>
<body ng-app="App">
<div ng-controller="DemoCtrl">
<h1>{{name}}</h1>
<h1>{{now}}</h1>
<h1>{{time}}</h1>
</div>
<script>
var App = angular.module(\'App\', []);
App.controller(\'DemoCtrl\', [\'$scope\', \'timer\', \'showTime\', function ($scope, timer, showTime) {
$scope.name = timer.name;
$scope.now = showTime.now;
$scope.time = showTime.format(\'hh:mm:ss\');
}])
App.service(\'timer\', [function () {
}]);
App.service(\'showTime\', [\'$filter\', function ($filter) {
this.now = $filter(\'date\')(new Date(), \'yyyy-MM-dd\');
this.format = function (arg) {
return $filter(\'date\')(new Date(), arg);
}
}]);
</script>
</body>
</html>
一、复习(数据重复报错)
数据重复,val in list 这里会报错,所有加了一个东西在后面加track by $index
<li ng-repeat="num in nums track by $index">{{num}}</li>
二、作用域
根作用域对应的是ng-app所在标签
scope是作用域的意思(相当于this)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="angular.js"></script>
</head>
<body ng-app="App" ng-init="names=\'舒见佳\'">
<div class="box" ng-controller="DemoCtrl">
<h1>{{names}}</h1>
<input type="button" value="电击" ng-click="name()">
<div class="box1" ng-controller="DemoCtrl2">
<h1>{{names}}</h1>
<input type="button" value="电击" ng-click="name()">
</div>
</div>
<script>
var App=angular.module(\'App\',[]);
App.controller(\'DemoCtrl\',[\'$scope\',function($scope){
$scope.name=function(){
alert(\'!!!∑(゚Д゚ノ)ノψ(*`ー´)ψ(•́へ•́╬)ヽ(ー_ー)ノ|ू・ω・` )\');
}
}]);
App.controller(\'DemoCtrl2\',[\'$scope\',function($scope){
// $scope.name=function(){
// alert(\'!!!∑(゚Д゚ノ)ノ\');
// }
}]);
</script>
</body>
</html>
三、过滤器
在AngularJS中使用过滤器格式化展示数据,在“{{}}”中使用“|”来调用过滤器,使用“:”传递参数。
下面的例子中date就是过滤器
日期
<dd>{{now|date:"yyyy-MM-dd hh:mm:ss"}}</dd>
排序方式
<dd>排序:{{orderBy|orderBy:\'age\':true}}</dd>
筛选数据
<dd>筛选数据:{{obj|filter:{name:\'xiao\'} }}</dd>
注意要有空格
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="angular.js"></script>
</head>
<body ng-app="App">
<dl ng-controller="DemoCtrl">
<dt>过滤器</dt>
<dd>{{now|date:"yyyy-MM-dd EEEE/EEE hh:mm:ss"}}</dd>
<dd>商品价格:{{price|currency:"¥":4}}</dd>
<dd>介绍:{{info|limitTo:-2}}</dd>
<dd>数组:{{list|limitTo:-2}}</dd>
<dd>小写:{{lowercase|lowercase}}</dd>
<dd>大写:{{uppercase|uppercase}}</dd>
<dd>数字格式:{{number|number:2}}</dd>
<dd>排序:{{orderBy|orderBy:\'\':true}}</dd>
<dd>json:{{obj|json}}</dd>
<dd>筛选数据:{{objs|filter:\'p\'}}</dd>
<dd>连写:{{uppercase|uppercase|limitTo:2}}</dd>
</dl>
<script>
var App=angular.module(\'App\',[]);
App.controller(\'DemoCtrl\',[\'$scope\',function($scope){
$scope.now=new Date;
$scope.price=12.345;
$scope.info=\'jiajia\';
$scope.list=[\'jiajia\',\'shushu\',\'jianjian\'];
$scope.lowercase=\'jiajia\';
$scope.uppercase=\'jiJJia\';
$scope.number=12.34322;
$scope.orderBy=[12,43,1,3,12,45,31,12,3];
$scope.obj={name:\'jiajia\', json:\'shushu\',papa:\'jianjian\'};
$scope.objs=[\'jiajiap\',\'shushu\',\'jianjian\'];
}]);
</script>
</body>
</html>
各种参数
1、currency[货币] 将数值格式化为货币格式
2、date日期格式化,年(y)、月(M)、日(d)、星期(EEEE/EEE)、时(H/h)、分(m)、秒(s)、毫秒(.sss),也可以组合到一起使用。
3、filter在给定数组中选择满足条件的一个子集,并返回一个新数组,其条件可以是一个字符串、对象、函数
4、json将Javascrip对象转成JSON字符串。
5、limitTo取出字符串或数组的前(正数)几位或后(负数)几位
6、lowercase将文本转换成小写格式
7、uppercase将文本转换成大写格式
8、number数字格式化,可控制小位位数
9、orderBy对数组进行排序,第2个参数是布尔值可控制方向(正序或倒序)
四、自定义过滤器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="angular.js"></script>
</head>
<body ng-app="App">
<dl ng-controller="DemoCtrl">
<dt>自定义过滤器</dt>
<dd>{{name|demo}}</dd>
</dl>
<script>
var App=angular.module(\'App\',[]);
//定义一个控制器
App.controller(\'DemoCtrl\',[\'$scope\',function($scope){
$scope.name=\'itcast\';
}]);
// 定义一个指令directive
App.directive(\'demo\',function(){
});
// 定义一个过滤器filter
//需要两个参数,过滤器的名字,和依赖关系
App.filter(\'demo\',function(){
// console.log(1);
// 必须要返回一个函数
return function(arg){
// 再次完成数据格式化的逻辑并且Angularjs会将需要格式化处理的数据当成第一个参数传递进来
// console.log(arg);
return \'你好\' +arg;
}
});
//上诉定义了最基本的过滤器,其使用方法与内置一样
</script>
</body>
</html>
首字母大写:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="angular.js"></script>
</head>
<body ng-app="App">
<dl ng-controller="DemoCtrl">
<dt>自定义过滤器</dt>
<dd>{{name|capitalize}}</dd>
</dl>
<script>
var App=angular.module(\'App\',[]);
App.controller(\'DemoCtrl\',[\'$scope\',function($scope){
$scope.name=\'itcast\';
}]);
App.filter(\'capitalize\',function(){
return function(input){
return input[0].toUpperCase()+input.slice(1);
}
});
</script>
</body>
</html>
五、依赖注入
AngularJS将一些通用的功能进行了封装,开发者只需要根据自己的情况进行调用即可。
如果开发者想要使用AngularJS内部封装好的通用的功能,必须先把他们加载进来,由此也便产生相互的依赖关系。
也就意味着我们必须有一个方法能够很好的解决依赖关系。
define([\'jquery\'],function($){});
上诉方法能够很好的解决依赖关系
这种方法叫依赖注入
依赖+注入
通过注入的方式来解决依赖
以参数的形式传递到函数内部的过程称为注入
行内式依赖注入:
在AngularJS中封装了一个通用功能叫$scope,用来实现数据绑定
如果在现实开发当中,开发者想要将数据绑定到视图上就必须用$scope
通过数组前面几个单元来指定依赖关系,最后一个单元永远是一个回调函数
在AngularJS中封装一个通用功能 $rootScope,用来直接设置根作用域。
App.controller(\'DemoCtrl\',[\'$scope\',\'$rootScope\',function($scope,$rootScope){ }]);
注入和依赖合并了。这里的$scope即是声明依赖也是注入依赖
App.controller(\'DemoCtrl\',function($scope){ });
六、服务
服务是一个对象或函数,对外提供特定的功能
(一)、内置服务:
1、$log打印调试信息
AngularJS将调试信息封装成了一个服务,开发过程中只需要调用这个服务即可
当前开发依赖一个$log的通用功能(服务)
$log是一个对象,对外开放一些方法
App.controller(\'DemoCtrl\',function($scope,$log){
$log.log(123);
$log.info(123);
$log.error(123);
$log.warn(123);
//可以通过配置服务将此功能打开
$log.debug(123);
});
2、$timeout&$interval对原生Javascript中的setTimeout和setInterval进行了封装。
延时:
App.controller(\'DemoCtrl\',function($scope,$timeout){
$timeout(function(){
$scope.name="(^_−)☆o(´^`)oo(╥﹏╥)oo(´^`)o(•́へ•́╬)ψ(*`ー´)ψ";
},3000);
});
计时:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="angular.js"></script>
</head>
<body ng-app="App">
<dl ng-controller="DemoCtrl">
<dt></dt>
<dd><h3>{{name|date:\'yyyy-MM-dd hh-mm-ss\'}}</h3></dd>
<dd><button ng-click="stop()">停止</button></dd>
</dl>
<script>
var App=angular.module(\'App\',[]);
App.controller(\'DemoCtrl\',function($scope,$interval){
$scope.name=new Date();
var timer=$interval(function(){
$scope.name=new Date();
},1000);
$scope.stop=function(){
$interval.cancel(timer);;
};
});
</script>
</body>
</html>
3、$filter在控制器中格式化数据。
$filter是一个函数,并且可以接受一些参数,根据参数的不同过滤器所能处理的数据格式也不同。
----
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="angular.js"></script>
</head>
<body ng-app="App">
<dl ng-controller="DemoCtrl">
<dt></dt>
<dd><h3>{{now}}</h3></dd>
<dd><h3>{{price}}</h3></dd>
</dl>
<script>
var App=angular.module(\'App\',[]);
App.controller(\'DemoCtrl\',function($scope,$filter){
var date=$filter(\'date\');
var currency=$filter(\'currency\');
$scope.now=date(new Date(),\'yyyy-MM-dd hh-mm-ss\');
$scope.price=currency(12.3434);
});
</script>
</body>
</html>
4、$http用于向服务端发起异步请求。
$http是一个函数
用法:
$http([
url:\'\',//请求地址
method:\'\',//请求方式
data:\'\',//post方式数据
params:\'\',//get方式数据
//向服务器发送一些数据,根据请求方式不同,所使用的方法也不一样
headers :{
//请求头信息
\'Content-Type\':\'\';
}
]).then(function (data) {
//成功后的回调
},function( ) {
//失败后的回调
});
小例子:无数据
html文件:
App.controller(\'DemoCtrl\', [\'$scope\', \'$http\', function ($scope, $http) {
$http({
url: \'./example.php\',
method: \'get\'
以上是关于AngularJS初体验-02的主要内容,如果未能解决你的问题,请参考以下文章
angularJs初体验,实现双向数据绑定!使用体会:比较爽
基于 Webpack & Vue & Vue-Router 的 SPA 初体验