从零开始学习vue(2)

时间:2023-01-02 18:24:39

一.vue实例

每个vue应用都是通过Vue构造函数创建的一个新的实例开始的:

var vm = new Vue({
//选项对象
})

在这其中vm(viewModel的简称)通常都表示vue实例的变量名。当创建一个vue实例,你都可以传入一个选项对象作为参数,完整的选项对象,你可能需要查看API文档

一个vue应用应该由一个通过new Vue构造的根实例和许多可嵌套可复用的组件构成,这也就是说所有的组件都是vue实例。

二.数据与方法

当一个vue实例被创建完成之后,就会向它的vue响应系统中加入了data对象中能找到的所有属性,当这些属性的值发生改变之后,视图就会发生响应,也就是更新相应的值。我们来看一个例子:

//源数据对象
var obj = { name:"eveningwater" };
//构建实例
var vm = new Vue({
data:obj
}) //这两者是等价的
vm.name === obj.name;
//这也就意味着
//修改data对象里的属性也会影响到源数据对象的属性
vm.name = "waterXi";
obj.name;//"waterXi"
//同样的,修改源数据对象的属性也会影响到data对象里的属性
obj.name = 'stranger';
vm.name;//"stranger"

可能需要注意的就是,只有data对象中存在的属性才是响应式的,换句话说,你为源数据对象添加一个属性,根本不会影响到data对象。如:

obj.sex = "男";
vm.sex;//undefined
obj.sex;//'男'
obj.sex = "哈哈哈";
vm.sex;//undefined

这也就意味着你对sex的修改并不会让视图更新,如此一来,你可能需要在data对象中初始化一些值,如下:

data:{
str:'',
bool:false,
arr:[],
obj:{},
err:null,
num:0
}

查看此处具体示例

只是还有一个例外Object.freeze(),这个方法就相当于锁定(冻结)一个对象,使得我们无法修改现有属性的特性和值,并且也无法添加新属性。因此这会让vue响应系统无法追踪变化:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>freeze</title>
</head>
<body>
<div id="app">
<span>{{ message }}</span>
<button type="button" v-on:click="reverseMessage">反转信息</button>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码如下:

      var obj = {
message: "hello,vue.js!"
}
//阻止对象
Object.freeze(obj);
var app = new Vue({
el: "#app",
data:obj,
methods: {
reverseMessage: function() {
this.message = this.message.split("").reverse().join("");
}
}
});

如此一来,无论我们怎么点击按钮,都不会将信息反转,甚至页面还会报错,如下图:

从零开始学习vue(2)
可前往此处具体示例自行查看效果。

当然除了数据属性以外,vue还暴露了一些有用的实例属性和方法,它们通常都带有$前缀,这样做的方式是以便与用户区分开来。来看一个示例:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>property</title>
</head>
<body>
<div id="app"> </div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

  var obj = {
name:'eveningwater'
}
var vm = new Vue({
data:obj,
});
//这行代码表示将vue实例挂载到id为app的DOM根节点上,相当于在实例的选项对象中的el选项,即
//el:'#app'
vm.$mount(document.querySelector('#app'))
//数据是相等的
vm.$data === obj;//true
//挂载的根节点
vm.$el === document.querySelector('#app');//true
//以上两个属性都是实例上的属性,接下来还有一个watch即监听方法是实例上的方法
vm.$watch('name',function(oldValue,newValue){
//数据原来的值
console.log(oldValue);
//数据最新的值
console.log(newValue);
})

接下来,可以尝试在浏览器控制台修改name的值,你就会发现watch()方法的作用了,如下图所示:

从零开始学习vue(2)

这个示例可前往具体示例

三.实例生命周期

每个vue实例在被创建的时候都会经历一些初始化的过程,这其中提供了一些生命周期钩子函数,这些钩子函数代表不同的生命周期阶段,这些钩子函数的this就代表调用它的那个实例。对于生命周期,有一张图:

从零开始学习vue(2)

你不需要立即这张图所代表的含义,我们来看一个示例:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>vue life cycle</title>
</head>
<body>
<div id="app">
<span>vue生命周期</span>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

  var obj = {
name:'eveningwater'
}
var app = new Vue({
data:obj,
beforeCreate:function(){
//此时this指向app这个vue实例,但并不能得到data属性,因此this.name的值是undefined
console.log('实例被创建之前,此时并不能访问实例内的任何属性' + this.name)
}
});

关于生命周期的全部理解,我们需要理解后续的组件知识,再来补充,此处跳过。这个示例可前往具体示例

四.模板语法

vue使用基于HTML的模板语法,在vue的底层是将绑定数据的模板渲染成虚拟DOM,并结合vue的响应式系统,从而减少操作DOM的次数,vue会计算出至少需要渲染多少个组件。

最简单的模板语法莫过于插值了,vue使用的是Mustache语法(也就是双大括号"{{}}")。这个只能对文本进行插值,也就是说无论是字符串还是标签都会被当作字符串渲染。如:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>Mustache</title>
</head>
<body>
<div id="app">
<span>{{ greeting }}World!</span>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

 var obj = { greeting:"Hello,"};
var vm = new Vue({
data:obj
});
vm.$mount(document.getElementById('app'));

如此以来Mustache标签就会被data对象上的数据greeting给替代,而且我们无论怎么修改greeting的值,视图都会响应,具体示例

我们还可以使用v-once指令对文本进行一次性插值,换句话说,就是这个指令让插值无法被更新:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>Mustache</title>
</head>
<body>
<div id="app">
<span v-once>{{ greeting }}World!</span>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

 var obj = { greeting:"Hello,"};
var vm = new Vue({
data:obj
});
vm.$mount(document.getElementById('app'));

在浏览器控制台中我们输入vm.greeting="stranger!"可以看到视图并没有被更新,这就是这个指令的作用,我们需要注意这个指令对数据造成的影响。具体实例

既然双大括号只能让我插入文本,那要是我们要插入HTML代码,我们应该怎么办呢?v-html这个指令就可以让我们插入真正的HTML代码。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>v-html</title>
</head>
<body>
<div id="app">
<p>{{ message }}</p>
<p v-html="message"></p>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

 var obj = { message:"<span style='color:#f00;'>hello,world!</span>"};
var vm = new Vue({
data:obj
});
vm.$mount(document.getElementById('app'));

页面效果如图所示;

从零开始学习vue(2)

可前往具体示例

关于HTML特性,也就是属性,我们需要用到v-bind指令,例如:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>v-bind</title>
</head>
<body>
<div id="app">
<div v-bind:id="propId">使用v-bind指令给该元素添加id属性</div>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

 var obj = { propId:"myDiv"};
var vm = new Vue({
data:obj
});
vm.$mount(document.getElementById('app'));

打开浏览器控制台,定位到该元素,我们就能看到div元素的id属性为"myDiv",如下图所示:

从零开始学习vue(2)

具体示例

在绑定与元素实际作用相关的属性,比如disabled,这个指令就被暗示为true,在默认值是false,null,undefined,''等转换成false的数据类型时,这个指令甚至不会表现出来。如下例:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>v-bind</title>
</head>
<body>
<div id="app">
<button type="button" v-bind:disabled="isDisabled">禁用按钮</button>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

 var obj = { isDisabled:123};
var vm = new Vue({
data:obj
});
vm.$mount(document.getElementById('app'));

这样一来,无论我们怎么点击按钮都没用,因为123被转换成了布尔值true,也就表示按钮已经被禁用了,我们可以打开控制台看到:

从零开始学习vue(2)

你可以尝试这个示例具体示例

在使用模板插值的时候,我们可以使用一些JavaScript表达式。如下例:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>expression</title>
</head>
<body>
<div id="app">
<p>{{ number + 1 }}</p>
<p>{{ ok ? "确认" : "取消" }}</p>
<p>{{message.split("").reverse().join("")}}</p>
<div v-bind:id="'my' + elementId">
元素的id为<span :style="{ 'color':color }">myDiv</span>
</div>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

 var obj = {
number: 123,
ok: true,
message: "hello,vue.js!",
elementId: "Div",
color: "red"
};
var vm = new Vue({
data: obj
});
vm.$mount(document.getElementById("app"));

这些JavaScript表达式都会被vue实例作为JavaScript代码解析,具体示例

值得注意的就是有个限制,只能绑定单个表达式,像语句是无法生效的。如下例:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>sentence</title>
</head>
<body>
<div id="app">
<p>{{ var number = 1 }}</p>
<p>{{ if(ok){ return '确认'} }}</p>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

  var obj = {
number: 123,
ok: true
};
var vm = new Vue({
data: obj
});
vm.$mount(document.getElementById("app"));

像这样直接使用语句是不行的,浏览器控制台报错,如下图:

从零开始学习vue(2)

不信可以自己试试具体示例

指令(Directives)是带有v-前缀的特殊特性,通常指令的预期值就是单个JavaScript表达式(v-for除外),例如v-ifv-show指令,前者表示DOM节点的插入和删除,后者则是元素的显隐。所以,指令的职责就是根据表达式值的改变,响应式的作用于DOM。现在我们来看两个示例:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>v-if</title>
</head>
<body>
<div id="app">
<p v-if="value === 1">{{ value }}</p>
<p v-else-if="value === 2">{{ value }}</p>
<p v-else>{{ value }}</p>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

  var obj = {
value: 1
};
var vm = new Vue({
el: "#app",
data() {
return obj;
}
});

运行在浏览器效果如图:

从零开始学习vue(2)

现在你可以尝试在浏览器控制台更改vm.value = 2vm.value = 3我们就可以看到页面的变化。你也可以狠狠点击此处具体示例查看和编辑。

我们再看v-show的示例:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>v-show</title>
</head>
<body>
<div id="app">
<p v-show="value === 1">{{ value }}</p>
<p v-show="value === 2">{{ value }}</p>
<p v-show="value === 3">{{ value }}</p>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

var obj = {
value:1
}
var vm = new Vue({
data:obj
});
vm.$mount(document.querySelector('#app'))

然后查看效果如图:

从零开始学习vue(2)
尝试在控制台修改vm.value = 2vm.value = 3我们就可以看到页面的变化。你也可以狠狠点击具体示例查看。

从上面两个示例的对比,我们就可以看出来v-showv-if指令的区别了,从切换效果来看v-if显然不如v-show,这说明v-if有很大的切换开销,因为每一次切换都要不停的执行删除和插入DOM元素操作,而从渲染效果来看v-if又比v-show要好,v-show只是单纯的改变元素的display属性,而如果我们只想页面存在一个元素之间的切换,那么v-if就比v-show要好,这也说明v-show有很大的渲染开销。

而且v-if还可以结合v-else-ifv-else指令使用,而v-show不能,需要注意的就是v-else必须紧跟v-if或者v-else-if之后。当需要切换多个元素时,我们还可以使用template元素来包含,比如:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>template</title>
</head>
<body>
<div id="app">
<template v-if="value > 1">
<p>{{ value }}</p>
<h1>{{ value }}</h1>
</template>
<template v-else>
<span>{{ value }}</span>
<h2>{{ value }}</h2>
</template>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

  var obj = {
value: 1
};
var vm = new Vue({
el: "#app",
data() {
return obj;
}
});

此时template相当于一个不可见元素,如下图所示:

从零开始学习vue(2)
尝试在控制台修改vm.value = 2就可以看到效果了,你也可以狠狠的点击此处具体示例

对于可复用的元素,我们还可以添加一个key属性,比如:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>key</title>
</head>
<body>
<div id="app">
<template v-if="loginType === 'username'">
<label>username:</label>
<input type="text" key="username" placeholder="enter your username" />
</template>
<template v-else-if="loginType === 'email'">
<label>email:</label>
<input type="text" key="email" placeholder="enter your email" />
</template>
<template v-else>
<label>mobile:</label>
<input type="text" key="mobile" placeholder="enter your mobile" />
</template>
<button type="button" @click="changeType">
toggle login type
</button>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

      var obj = {
loginType: "username",
count:1
};
var vm = new Vue({
el: "#app",
data() {
return obj;
},
methods: {
changeType() {
this.count++;
if (this.count % 3 === 0) {
this.loginType = "username";
} else if (this.count % 3 === 1) {
this.loginType = "email";
} else {
this.loginType = "mobile";
}
}
}
});

效果如图:

从零开始学习vue(2)
你可以狠狠的点击具体示例查看。

从这几个示例我们也可以看出v-if就是惰性,只有当条件为真时,v-if才会开始渲染。值得注意的就是v-ifv-for不建议合在一起使用。来看一个示例:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>v-if与v-for</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="(item,index) in list" v-bind:key="index" v-if="item.active">
<span>{{ item.value }}</span>
</li>
</ul>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

  var obj = {
list:[
{
value:'html',
active:false
},
{
value:'css',
active:false
},
{
value:"javascript",
active:true
}
]
};
var vm = new Vue({
el: "#app",
data() {
return obj;
}
});

虽然以上代码不会报错,但这会造成很大的渲染开销,因为v-for优先级高于v-if,这就造成每次执行v-if指令时总要先执行v-for遍历一遍数据。你可以点击此处具体示例查看。

遇到这种情况,我们可以使用计算属性。如:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>v-if和v-for</title>
</head>
<body>
<div id="app">
<ul v-if="newList">
<li v-for="(item,index) in newList" v-bind:key="index">
<span>{{ item.value }}</span>
</li>
</ul>
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

var obj = {
list: [
{
value: "html",
active: false
},
{
value: "css",
active: false
},
{
value: "javascript",
active: true
}
]
};
var vm = new Vue({
el: "#app",
//先过滤一次数组
computed: {
newList: function() {
return this.list.filter(function(item) {
return item.active;
});
}
},
data() {
return obj;
}
});

如此一来,就减少了渲染开销,你可以狠狠点击这里具体示例查看。

指令的用法还远不止如此,一些指令是可以带参数的,比如v-bind:title,在这里title其实就是被作为参数。基本上HTML5属性都可以被用作参数。比如图片路径的src属性,再比如超链接的href属性,甚至事件的添加也属于参数,如v-on:click中的click其实就是参数。来看一个示例:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入vue.js开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>param</title>
</head>
<body>
<div id="app">
<a v-bind:href="url">思否</a>
<img :src="src" alt="美女" />
</div>
<script>
//这里写JavaScript代码
</script>
</body>
</html>

js代码:

  var obj = {
url: "https://segmentfault.com/",
src:"http://eveningwater.com/project/imggallary/img/15.jpg"
};
var vm = new Vue({
el: "#app",
data() {
return obj;
}
});

效果如图所示:

从零开始学习vue(2)

你可以点击此处具体示例查看。

v-on指令还可以添加修饰符,v-bindv-on指令还可以缩写成:@。缩写对于我们在繁琐的使用指令的项目当中是一个很不错的帮助。

五.计算属性与侦听器

从零开始学习vue(2)的更多相关文章

  1. 从零开始学习Vue&period;js,学习笔记

    一.为什么学习vue.js methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节. vue.js兼具angular.js和react的优点,并且剔除了他们的缺点 官网:http://cn ...

  2. 从零开始学习Vue&lpar;三&rpar;

    我们从一个例子来学习组件,vuejs2.0实战:仿豆瓣app项目,创建自定义组件tabbar 这个例子用到其他组件,对于初学者来说,一下子要了解那么多组件的使用,会变得一头雾水.所以我把这个例子改写了 ...

  3. 从零开始学习Vue&lpar;一&rpar;

    因为最近有个项目的需求是,微信公众号+IOS/Android APP, 界面都很类似. 以往的做法是APP是调用JSON接口,后台只负责提供接口. 而H5,我以前都是用Jquery,用来写手机网站总是 ...

  4. 从零开始学习Vue&lpar;四&rpar;

    这里引入一个概念SPA(single Page Application), 接着上次的例子,我们在页面底部做了一个Tab的菜单,点击不同的按钮应该是显示不同的内容. 按传统的MVC的思维,我要在Con ...

  5. 从零开始学习Vue&lpar;二&rpar;

    思维方式的变化 WebForm时代, Aspx.cs 取得数据,绑定到前台的Repeater之类的控件.重新渲染整个HTML页面.就是整个页面不断的刷新;后来微软打了个补丁,推出了AJAX控件,比如U ...

  6. VUE 从零开始 学习笔记 一

    最近刚跳到一个新公司 不是很忙 决定系统的学习一下VUE这个前端框架 参考官方API 好了 废话不多说 开始了 首先 说一下吧 现在很火的主流三大前端框架 Vue,Angular.React, 为什么 ...

  7. ASP&period;NET从零开始学习EF的增删改查

           ASP.NET从零开始学习EF的增删改查           最近辞职了,但是离真正的离职还有一段时间,趁着这段空档期,总想着写些东西,想来想去,也不是很明确到底想写个啥,但是闲着也是够 ...

  8. 从零开始学习jQuery &lpar;五&rpar; 事件与事件对象

    本系列文章导航 从零开始学习jQuery (五) 事件与事件对象 一.摘要 事件是脚本编程的灵魂. 所以本章内容也是jQuery学习的重点. 本文将对jQuery中的事件处理以及事件对象进行详细的讲解 ...

  9. 从零开始学习jQuery &lpar;四&rpar; 使用jQuery操作元素的属性与样式

    本系列文章导航 从零开始学习jQuery (四) 使用jQuery操作元素的属性与样式 一.摘要 本篇文章讲解如何使用jQuery获取和操作元素的属性和CSS样式. 其中DOM属性和元素属性的区分值得 ...

随机推荐

  1. handler发消息的形式

    1.onCreate()中写好handler的接受机制,准备接受并处理消息 2.thread中利用handler.post(Runnable r): protected void onCreate(B ...

  2. Universal-Image-Loader完全解析(上)

    Universal-Image-Loader完全解析(上) 基本介绍及使用 大家平时做项目的时候,或多或少都会接触到异步加载图片,或者大量加载图片的问题,而加载图片时候经常会遇到各种问题,如oom,图 ...

  3. 食物链 poj 1182

    C - 食物链 Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Stat ...

  4. boost库学习之开篇

    本系列文章使用boost_1.58.0版本. 一.欢迎使用boost C++库 boost致力于提供一个免费的.便携的源代码级的库. 我们重视那些与C++标准一起工作良好的库.boost库将要成为一个 ...

  5. Java &equals;&equals;,equals&lpar;&rpar; 和hashCode

    Kruger上课讲到==和equals()方法是不同的,经过查询将具体内容整理一下,在查询过程中发现hashCode()方法与equlas()联系紧密,故一起研究. 比较浅显,以后如果理解更多随时更新 ...

  6. ios9 新关键字 &lowbar;&lowbar;kindof 等&lpar;etc&rpar; 小结

    首先__kindof:规定参数为UITableViewCell(举例)这个类或者其子类.比如说一个NSArray<UIView *>*,如果不加__kindof,这个数组只能有UIView ...

  7. 分享Grunt&period;js配置&colon; watch &plus; liveReload 实时监测文件变化自动刷新浏览器

    http://www.tuicool.com/articles/2eaQJn 用Grunt配置watch和liveReload组件,可以实时检测指定的文件变化并自动刷新浏览器.目前基本已经成为了我的必 ...

  8. PHP创建对象的几种形式

    创建对象的几种形式 class  C1{ var  $p1 = 1; //定义一个属性: } 形式1: $o1 = new C1(); //通过一个类,去new出一个对象 形式2: $o2 = new ...

  9. HDU4788&lowbar;Hard Disk Drive

    水题. 但是我写挫了一个地方,Wa了三发.好吧,不能忍了. 还有,本屌不知道如何用printf输出%,哪位学过C++的大仙知道这是什么情况?  告诉我一声啊. #include <iostrea ...

  10. ubuntu apt-get dpkg-scanpackages 制作本地软件源

    1. 收集软件,下载的软件都在/var/cache/apt/archives目录下 例如openstack L版的所有包 keystone,glance nova neutron....... 举例: ...