Vue.js基础应用笔记
vue.js 笔记
菜鸟教程http://www.runoob.com/vue2/vue-template-syntax.html
中文官方文档https://cn.vuejs.org/v2/guide/index.html#%E7%BB%84%E4%BB%B6%E5%8C%96%E5%BA%94%E7%94%A8%E6%9E%84%E5%BB%BA
中文API文档:https://cn.vuejs.org/v2/api/
vue安装
菜鸟教程http://www.runoob.com/vue2/vue-install.html
Vue.js目录结构
目录解析
目录/文件 | 说明 |
---|---|
build | 项目构建(webpack)相关代码 |
config | 配置目录,包括端口号等。我们初学可以使用默认的。 |
node_modules | npm 加载的项目依赖模块 |
src | 这里是我们要开发的目录,基本上要做的事情都在这个目录里。里面包含了几个目录及文件:assets: 放置一些图片,如logo等。components: 目录里面放了一个组件文件,可以不用。App.vue: 项目入口文件,我们也可以直接将组件写这里,而不使用 components 目录。main.js: 项目的核心文件。 |
static | 静态资源目录,如图片、字体等。 |
test | 初始测试目录,可删除 |
.xxxx文件 | 这些是一些配置文件,包括语法配置,git配置等。 |
index.html | 首页入口文件,你可以添加一些 meta 信息或统计代码啥的。 |
package.json | 项目配置文件。 |
README.md | 项目的说明文档,markdown 格式 |
vue 单文件方式
- 单文件就是以*.vue结尾的文件,最终通过webpack也会编译成*.js在浏览器运行
- 内容:<template></template>+<script></script>+<style></style>
- template 中只能有一个根节点2.x
- script中按照export default(配置)来写
- style中可以设置scoped属性,让其值在template中生效
以单文件的方式启动
-vue-loader,vue-template-compiler,
import Vue from 'Vue';
import App from './app.vue';
new Vue(){
el:'#app',
render:function(create){
return create(APP);
//App包含template/script/style,最终生成DOM结构
}
};
Vue介绍
2014年诞生,2013年react ,09年angular.js
作者:尤雨溪
核心概念:组件化 双向数据流(基于ES5中的defineProperty来实现的),IE9才支持
angular核心:模块化 双向数据绑定(脏检测:–一个数组($watch)
框架对比建议学完vue在比较
双向数据流
1:js内存属性发生改变,影响页面的变化
2:页面的改变,影响js内存属性的变化
vue 初步使用
插值
文本插值:数据绑定最常见的形式就是使用{{…}}(双大括号)的文本插值
HTML:使用v-html指令用于输出html代码
**属性:**HTML属性中的值应使用v-bind指令。示例:
**表达式:**vue.js都提供了完全的javascript表达式支持
<div id='app'>
{{5+5}}</br>
{{ok?'YES':'NO'}}</br>
{{message.split('').reverse().join('')}}
<div v-bind:id="'list-' +id">菜鸟教程</div>
</div>
<script>
new Vue({
el:'#app',
data:{
ok:true,
message:'RUNOOB',
id:1
}
})
</script>
指令
* v-text 是元素的innerText只能在双标签中使用
* v-html 是元素的innerHtml不能包含 双花括号
* v-if 元素是否移除
* v-show 元素是否显示或隐藏
* v-model 双向数据绑定
* v-bind是单向数据绑定,js内存改变影响页面
v-bind:class v-bind:value v-bind:href
简写 :class :value :href
* v-on 绑定事件的方法
v-on:事件名=‘表达式||函数名’
简写:‘@事件名=“表达式||函数名”’
函数名如果没有参数,可以省略() 只给一个函数名称
声明组件内函数,在export default这个对象的根属性加上methods属性
-key是函数名 值是函数体
在export default这个对象的根属性加上data属性,其是一个函数返回一个对象
-对象的属性是我们初始化的变量的名称
* 凡是在template中使用变量或者函数,不需要加this
* 在script中使用就需要加上this
* v-for的使用
可以单独使用操作数组(item,index)
可以使用操作对象(value,key,index)
指令是带有**v-**前缀的特殊属性
指令用于在表达式的值改变时,将某些行为应用到DOM上,如下例子
用户输入 -数据双向绑定
在 input 输入框中我们可以使用 v-model 指令来实现双向数据绑定:
<div id="app">
<p>{{ message }}</p>
<input v-model="message">
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Runoob!'
}
})
</script>
v-model 指令用来在 input、select、text、checkbox、radio 等表单控件元素上创建双向数据绑定,根据表单上的值,自动更新绑定的元素的值。
按钮的事件我们可以使用 v-on 监听事件,并对用户的输入进行响应。
缩写
Vue.js 为两个最为常用的指令提供了特别的缩写:
-
v-bind缩写
<!-- 完整语法 --> <a v-bind:href="url"></a> <!-- 缩写 --> <a :href="url"></a>
-
v-on缩写
<!-- 完整语法 --> <a v-on:click="doSomething"></a> <!-- 缩写 --> <a @click="doSomething"></a>
组件化应用构建
组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:
<div id="app-7">
<ol>
<!--
现在我们为每个 todo-item 提供 todo 对象
todo 对象是变量,即其内容可以是动态的。
我们也需要为每个组件提供一个“key”,稍后再
作详细解释。
-->
<todo-item
v-for="item in groceryList"
v-bind:todo="item"
v-bind:key="item.id"
></todo-item>
</ol>
</div>
<!------------------------>
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
var app7 = new Vue({
el: '#app-7',
data: {
groceryList: [
{ id: 0, text: '蔬菜' },
{ id: 1, text: '奶酪' },
{ id: 2, text: '随便其它什么人吃的东西' }
]
}
})
<!------------输出------------>
<!--
1.蔬菜
2.奶酪
3.随便其他什么人吃的东西
-->
与自定义元素的关系
你可能已经注意到 Vue 组件非常类似于自定义元素——它是 Web 组件规范的一部分,这是因为 Vue 的组件语法部分参考了该规范。例如 Vue 组件实现了 Slot API 与 is
特性。但是,还是有几个关键差别:
- Web Components 规范已经完成并通过,但未被所有浏览器原生实现。目前 Safari 10.1+、Chrome 54+ 和 Firefox 63+ 原生支持 Web Components。相比之下,Vue 组件不需要任何 polyfill,并且在所有支持的浏览器 (IE9 及更高版本) 之下表现一致。必要时,Vue 组件也可以包装于原生自定义元素之内。
- Vue 组件提供了纯自定义元素所不具备的一些重要功能,最突出的是跨组件数据流、自定义事件通信以及构建工具集成。
父子组件使用(父传子)
- 父和子,使用的是父,被用的是子
- 父需要声明子组件,引入子组件对象,声明方式如下
import 子组件对象 from './xxx.vue';
new Vue({
componets:{
组件名:子组件对象
}
})
- 全局组件,使用更为方便,不需要声明,直接用
- 在main.js中引入一次,在main.js中使用用‘vue.component(‘组件名,组件对象’)’
- 所有的组件都可以直接通过组件名使用
父传子
-
父组件通过子组件的属性将值进行传递 方式有2:
- 常量 : prop1=‘常量值’
- 变量: :prop2=‘变量名’
-
子组件需要声明
- 根属性 props:[‘prop1’,‘prop2’]
- 在页面中直接使用{{prop1}}
- 在js中应该如何使用prop1? this.prop1获取
子传父
子传父的思想是通过自定义事件来传递
connecor.js
//作为连接器的文件
import Vue from 'vue';
export default new Vue();
App.vue
<template>
<!--只能有一个根节点-->
<div>
<vue-sub></vue-sub>
<!--开始监听监听-->
<button @click="listener">监听儿子打电话</button>
</div>
</template>
<script>
import connector from './connector';
import vueSub from './components/vueSub'
export default {
//配置
//类似socope.xxx ='初始化'
data() {
return {}
},
methods:
{
listener(){
//需要使用connector.$on()方法
//第一个参数相当于暗号、第二个参数是回调函数
//参数的值是接受到的信息。
connector.$on('phone',(msg)=>{
console.log(msg);
})
}
},
//声明使用哪些组件.全局组件不用声明
components: {
//明确用到哪些组件
vueSub
}
}
</script>
vueSub.vue
<template>
<p>
<input type="text" v-model="msg">
<button @click="call(msg)">儿子组件:回电话给老爸</button>
</p>
</template>
<script>
import connector from '../connector';
export default {
data() {
return {
msg:'吃鸡滴滴'
}
},
methods: {
call(msg){
//使用connector.$emit来回复信息
//第一个参数相当于约定的暗号。第二个参数是回复过去的信息
connector.$emit('phone','儿子回复:'+msg);
}
}
}
</script>
vue深入
重点
- vue组件的使用
- 组件间通信
- vue-router使用
- vue-resource发起http请求
- axios
过滤器
content| 过滤器 ,vue中没有提供相关的内置过滤器,但是可以自定义过滤器
组件内的过滤器+ 全局过滤器
-组件内的过滤器就是options中的一个filters的属性(一个对象)
+多个key就是不同过滤器名,多个value就是与key对应的过滤方式函数体
-Vue.filter(名,fn)
<template>
<div class="secondDay">
请输入内容
<input type="text" v-model="msg">
{{msg | reverse}}
</div>
</template>
<script>
export default {
data(){
return{
msg:'请输入内容'
}
},
methods:{
},
filters:{
reverse(msg){
return msg.split("").reverse().join('');
}
}
}
</script>
总结
全局:范围大,权利小
组件内:范围小,如果出现同名权力大
获取DOM元素
-
前端框架就是为了减少DOM操作,但是特定情况下,也给我们留了后门
-
在指定的元素上,添加ref=“名称A”
-
在获取的地方加上this.$refs.名称A
-
如果ref放在原生DOM元素上,获取的数据就是原生的DOM对象
- 可以直接操作
-
如果ref放在了组件对象上,获取的就是组件对象
- 获取的DOM对象,通过this.el,进行操作
-
对应的事件
- created 完成了数据的初始化,此时还未生成DOM,无法操作DOM
- mounted将数据已经装载到了DOM上,可以操作DOM
-
mint-ui
-
饿了么,element-ui在pc端使用
-
移动端版本,mint-ui
-
使用
-
如果是全部安装的方式
- 1,在template中可以直接使用组件标签
- 2.在script中必须要声明,也就是引入组件对象(按需加载)
-
示例代码
-
import MintUi from 'mint-ui'; import 'mint-ui/lib/style.css'; Vue.use(MintUi);
-
-
vue-router
-
前端路由核心就是锚点值得改变,根据不同的值,渲染指定DOM位置的不同数据
-
ui-router:锚点值改变,如何获取模板?
-
vue中,模板数据不是通过ajax请求,而是调用函数获取到模板内容
-
核心:锚点值改变
-
只要看到vue开头,就知道必须Vue.use
-
vue的核心插件:
- -vue-router路由
- vuex管理全局共享数据
-
使用方式
-
下载‘npm i vue-router -S’
-
在main.js中引入
-
import VueRouter from 'vue-router';
-
-
安装插件 ‘Vue.use(VueRouter)’;
-
创建路由对象并配置路由规则
-
let router = new VueRouter({ routes:[ {path:'/home',component:Home} ] });
-
-
将其路由对象传递给Vue的示例,options中
- options中加入 ‘router:router’
-
留坑
<router-view></router-view>
-
命名路由
-
需求,通过a标签点击,做页面数据的跳转
-
使用router-link标签
-
1直接写地址
-
<router-link to='/beijing'>去北京</rount-link>
-
-
2使用命名的方式-方便维护
-
<router-link :to="{name:bj}">去北京</router-link>
-
更利于维护,如果修改了path,只修改路由配置中的path,该a标签会根据修改后的值生成href属性
-
-
router-link对象方式传递参数
-
在vue-router中,有两大对象被挂载到了实例this
-
router(具备动能的函数)
-
查询字符串
-
1:去哪里
-
//detail是一个组件名。index是放在for循环的index。这里只给出部分代码 <router-link :to="{name:'detail',query:{id:index}}">xxx</router-link>
-
-
2:导航(查询字符串path不用改)
‘{name:‘detail’,path:’/detail’,组件}’
-
-
3,去了干嘛,获取路由参数(要注意是query还时params和对应id名)
-
-
path方式
-
1:去哪里
-
<router-link :to="{name:'detail',params:{id:index}}">xxx</router-link>
-
-
2,导航(path方式需要在路由规则上加/:xxx)
- ‘{name:‘detail’,path:’/detail/:id’,组件}’
-
去了干嘛,获取路由参数(要注意是query还是params和对应的id名)
-
this.$route.params.id
-
-
代码示范
main.js中的路由配置
let router = new VueRouter({
//routes
routes: [
//一个个对象
{name:'list', path: '/list', component: List},
//使用query的方式传递参数,不需要修改路由。
// {name:'detail',path: '/detail', component: Detail}
//使用params的方式传递参数,需要修改路由规则
{name:'detail',path: '/detail/:id', component: Detail}
]
});
list.vue中的部分代码
<template>
<div>
<ul>
<li v-for="(hero ,index ) in heros" :key="index">
{{hero.name}}
<router-link :to="{name:'detail',query:{id:index}}">查看</router-link>
</li>
</ul>
第二种查询方法==================
<ul>
<li v-for="(hero ,index ) in heros" :key="index">
{{hero.name}}
<router-link :to="{name:'detail',params:{id:index}}">查看</router-link>
</li>
</ul>
</div>
</template>
<script>
export default {
data(){
return {
heros:[{name:'李白'},{name:'花木兰'}]
}
}
}
</script>
在detail.vue中的部分代码
<template>
<div>
查看的英雄的ID{{msg}}
</div>
</template>
<script>
export default {
data(){
return{
msg:''
}
},
methods:{
},
filters:{
},
created(){
//创建DOM之前,可以获得从上个页面传过来的参数
this.msg=this.$route.query;
if (this.$route.params){
this.msg=this.$route.params;
}
}
}
</script>
vue-resource(了解)
- 官方团队开发。但已经不维护了
- 有axios代替
代码示例
created(){
//get请求
this.$http.get('url').then(res=>{
this.data=res.body.message;
},err=>{
console.log(err);
});
//post请求
this.$http.post('url',{key:'value'},{emulateJSON:true}).then(res=>{
this.data=res.body.message;
},err=>{
console.log(err);
})
}
axios
- axios中文参考文档
- axios跨域问题解决参考
使用
import Axios from 'axios'
Vue.prototype.$axios = Axios//挂载
代码示例
执行get请求
// 为给定 ID 的 user 创建请求
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 可选地,上面的请求可以这样做
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
执行post请求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
执行多个并发请求
特点:只有两个都请求成功才成功
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// 两个请求现在都执行完成
}));
axios API
可以通过向 axios
传递相关配置来创建请求
axios(config)
// 发送 POST 请求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
axios(url[, config])
// 发送 GET 请求(默认的方法)
axios('/user/12345');
解决跨域问题
这里以访问豆瓣Top250为例,直接访问如下
this.$axios.get("http://api.douban.com/v2/movie/top250")
.then(res=>{
console.log(res)
})
.catch(err=>{
console.log(err)
})
Step1:配置BaseUrl
在main.js
中,配置下我们访问的Url前缀:
import Vue from 'vue'
import App from './App'
import Axios from 'axios'
Vue.prototype.$axios = Axios
Axios.defaults.baseURL = '/api'
Axios.defaults.headers.post['Content-Type'] = 'application/json';
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>'
})
关键代码是:Axios.defaults.baseURL = '/api'
,这样每次发送请求都会带一个/api
的前缀。
Step2:配置代理
修改config文件夹下的index.js
文件,在proxyTable
中加上如下代码:
'/api':{
target: "http://api.douban.com/v2",
changeOrigin:true,
pathRewrite:{
'^/api':''
}
}
Step3:修改请求Url
修改刚刚的axios请求,把url
修改如下:
this.$axios.get("/movie/top250")
.then(res=>{
console.log(res)
})
.catch(err=>{
console.log(err)
})
Step4:重启服务
重启服务后,此时已经能够访问了:
原理:
因为我们给url加上了前缀/api,我们访问/movie/top250就当于访问了:localhost:8080/api/movie/top250(其中localhost:8080是默认的IP和端口)。
在index.js中的proxyTable中拦截了/api,并把/api及其前面的所有替换成了target中的内容,因此实际访问Url是http://api.douban.com/v2/movie/top250。
拦截器
- 过滤,在每一次请求与响应中,添油加醋
- axios.interceptors.request.use(fn) 在请求之前
- function (config){config.headers={xxx};return config} config相当于options对象
- 默认设置defaults范围广,权利小
- Axios.defaults.header={…}
- 单个请求的设置 get(rul,options),范围小,权利中
- 拦截器,范围广,权利大(请求的最后一层)
token(扩展)
- cookie 和 session的机制,cookie自动带一个字符串
- cookie只在浏览器
- 移动端原生应用,也可以使用http协议,1:可以加自定义的投,原生应用没有cookie
- 对于三端来讲,tooken可以作为cookie
- 对拦截器的使用
监视数据变化
- watch可以对(单个)变量进行监视,也可以深度监视
- 如果需求是对于10个变量进行监视?
- 计算属性computed可以监视多个值,并且指定返回数据,并且可以显示在页面
- 都是options中的根属性
- watch监视单个
- computed可以监视多个this相关属性值的改变,如果和原值一样就不会出发函数的调用,并且可以返回对象
对引用类型需要深度监视
watch
实例生命周期钩子
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
比如 created 钩子可以用来在一个实例被创建之后执行代码:
new Vue({
data: {
a: 1
},
created: function () {
// this
指向 vm 实例
console.log('a is: ’ + this.a)
}
})
// => “a is: 1”
也有一些其它的钩子,在实例生命周期的不同阶段被调用,如 mounted、updated 和 destroyed。生命周期钩子的 this 上下文指向调用它的 Vue 实例。
不要在选项属性或回调上使用箭头函数,比如 created: () => console.log(this.a) 或 vm.$watch(‘a’, newValue => this.myMethod())。因为箭头函数是和父级上下文绑定在一起的,this 不会是如你所预期的 Vue 实例,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。
生命周期图示
下图展示了实例的生命周期。你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它的参考价值会越来越高。
扩展
Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze()
返回和传入的参数相同的对象。