一、vue项目文件加载顺序
index.html、main.js、app.vue、routerindex.js、helloword.vue
二、new Vue
new Vue({
el: '#app',
components:{App},
template: '<App/>'
})
-
components 是声明有哪些组件
-
template 是使用哪个组件
-
el: '#app' 是index.html 的<div id="app"></div>
-
App.vue <div id="app">xxxxxxxx</div> 会替换和index中的<div id="app"></div>
-
index.html 中<div id="app"></div> 这个是convention(约定、习俗),可以改。只要id和生成Vue实例时el的参数值保持一致即可。
vue 2.0以上可以写成
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
-
render函数是vue通过js渲染dom结构的函数createElement,约定可以简写为h; 实际渲染和components:{App},template: '<App/>'一样
-
在Vue构造函数时,需要配置一个el属性,如果没有没有el属性时,可以使用.$mount('#app')进行挂载。
三、export和export default区别
-
导出
-
export
export 可以直接导出或者先定义后导出都可以。 示例: export let i = “hello”; export function myFun(){}; 上面的直接导出,也可以使用下面先定义后导出。 let i = “hello"; function myFun(){}; export {i , myFun}
-
export default
export default是模块的默认对外接口,只有一个,所以只能出现一次。
export default只能直接输出,不能先定义后导出。
-
导入
通过两者导出的对象,导入时也存在写法上的差别。
-
export导出的对象,导入时写法:
import {i, myFun}
-
export default导出的对象,导入时写法:
import 变量名 from ‘模块’ 很明显,模块只有一个默认的导出的接口,所以只有一个对象被导出,导出的对象可以自定义一个变量名
四、Vue.use()使用插件:
-
编写插件
Vue.js插件应该公开一个install
方法。该方法将以Vue
构造函数作为第一个参数以及可能的选项进行调用:
MyPlugin.install = function (Vue, options) {
// 1. add global method or property
// new Vue().myGlobalMethod
Vue.myGlobalMethod = function () {
}
// 2. add a global asset
// v-my-directive
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
}
})
// 3. inject some component options
Vue.mixin({
created: function () {
}
})
// 4. add an instance method
// this.$myMethod
Vue.prototype.$myMethod = function (methodOptions) {
}
}
-
使用插件
通过调用Vue.use()
全局方法来使用插件:
Vue.use(MyPlugin)
您可以选择传递一些选项:
Vue.use(MyPlugin, { someOption: true })
Vue.use
会自动阻止你多次使用同一个插件,所以在同一个插件上多次调用它只会安装一次插件。
五、@和./的区别
./表示相对路径,具体代表当前目录下的同级目录,遵从的是从后往前找文件
@/的意思: 表示的是相对路径(当然这也是简写啦),因为这个在根目录/build/webpack.base.conf.js文件中@是配置的, 比如我的配置文件中@就代表src目录,遵从的是从前往后找,比如’@/components/login’ 就表示的是src/components/login文件
-
/build/webpack.base.conf.js
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
六、Vue.prototype.$xx = xx
为什么初始化的时候运行了Vue.prototype.$utils
, 然后就可以在任意组件内部运行this.$utils()
了呢?
每一个vue组件都是Vue的实例,所以组件内this可以拿到Vue.prototype上添加的属性和方法。
七、过滤器
-
定义
分为全局定义和局部定义两种方式:
// 全局注册
Vue.filter('toRMB', function (value) {
return `¥${value}`
})
// 局部注册 (和method同级)
filters: {
toFixed: function(money) {
return money.toFixed(1)
},
},
-
使用
在双花括号中使用管道符(pipeline) |
隔开,或者v-bind
表达式(v2.1.0以上支持)
<h2>过滤器的使用-添加前缀</h2>
<p>{{352.11 | toRMB}}</p>
<p>{{657 | toRMB}}</p>
<p>{{657.22 | toFixed }}</p>
<p>{{money | toFixed }}</p>
还可以链式使用,注意先后的顺序,如下面的先添加¥符号再进行小数位变换将会出错,因此要注意先后顺序
<p>{{ money | toFixed | toRMB }}</p>
-
过滤器函数的多层参数
是指接收的参数不止value
这一个,还可以添加length
和suffix
参数
suffix参数
<h2>多重参数</h2>
<p>{{text}}</p>
<p>{{text | readMore(20,'...')}}</p>
new Vue({
el: '#app',
data: {
text: 'hello I love u, will u love me ?',
},
filters: {
readMore: function (value,length,suffix) {
return value.substr(0,length) + suffix;
},
}
})
八、axios
语法:
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
axios.get('/user', {
params: {
ID: 12345
}
})
可以通过向 axios
传递相关配置来创建请求 axios(config):
// 发送 POST 请求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
可以使用自定义配置新建一个axios
实例,并配置好基础属性
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
})
//再使用具体相关配置发送请求:
instance(config);
在使用axios发送post请求时,默认的请求头Content-Type
的属性值为application/json
改变Content-Type
可以使用:
import qs from 'qs';
const data = { 'bar': 123 };
const options = {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
url,
};
axios(options);
拦截器
在请求被 then
或 响应被 catch
前处理前拦截它们。
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
如果你想在稍后移除拦截器,可以这样:
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
可以为自定义 axios 实例添加拦截器
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
validateStatus:可以放在config里面,统一配置正确的请求返回状态码
validateStatus: function (status) {
return status >= 200 && status < 300; // 结果返回true都显示请求成功
},
Promise
具体使用时: resolve —>对应then reject —>对应catch 另外,只有调用了resolve 或者reject 才会触发 then 和 catch
九、package.json和package-lock.json的区别
package.json文件只能锁定大版本,即版本号的第一位,不能锁定后面的小版本,你每次npm install时候拉取的该大版本下面最新的版本。所以为了稳定性考虑我们不能随意升级依赖包,而package-lock.json就是来解决包锁定不升级问题的。
如果要升级package-lock.json里面的库包,怎么操作呢?
npm install packageName 或 npm install packageName@x.x.x
十、Computed和Watch的用法及区别
-
计算属性compute(由多个值计算出这个值)
<div id="app">
{{ changewords }} // 渲染 不用写()
</div>
</body>
<script>
var vm = new Vue({
el: "#app",
data:{},
// 计算属性
computed:{
changewords(){
return this.myname.substring(0,1).toUpperCase() + this.myname.substring(1)
}
}
})
</script>
总结:
变量不在 data中定义,而是定义在computed中,写法跟写方法一样,有返回值。函数名直接在页面模板中渲染,不加小括号 。
根据传入的变量的变化 进行结果的更新。
计算属性基于响应式依赖进行缓存。如其中的任意一个值未发生变化,它调用的就是上一次 计算缓存的数据,因此提高了程序的性能。而methods中每调用一次就会重新计算 一次,为了进行不必要的资源消耗,选择用计算属性。
-
监听属性(监听到这个值发生变化从而去改变其它的值)
new Vue({
el: '#id',
template: `<div>
// ...
</div>`,
data: {
firstName: 'Leo',
lastName: 'Alan',
obj1: {
a: 0
}
},
watch: {
// 监听firstName,当firstName发生变化时就会执行该函数
firstName () {
// 执行需要的操作...
// 注:初始化不会执行,只有当被监听的值(firstName)发生变化时才会执行
},
// 监听lastName
lastName: {
handler (newName, oldName) {
// 执行需要的操作...
},
immediate: true // true: 初始化时就会先执行一遍该监听对应的操作
},
obj1: {
handler () {
// 执行需要的操作...
},
deep: true // 该属性默认值为false.
// 当被监听的值是对象,只有deep为true时,对应属性的值(obj1.a)发生变化时才能触发监听事件,但是这样非常消耗性能
},
// 监听对象具体的属性, deep就不需要设置为true了
'obj1.a': {
handler () {
// 执行需要的操作...
}
}
}
})
-
计算属性 和 属性监听的区别:
-
计算属性变量在computed中定义,属性监听在data中定义。
-
计算属性是声明式的描述一个值依赖了其他值,依赖的值改变后重新计算结果更新DOM。属性监听的是定义的变量,当定义的值发生变化时,执行相对应的函数。
十一、$nextTick的使用
当你修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值,因为dom元素还没有更新。 你需要使用$nextTick这个回调,让dom元素更新修改后的data值之后再获取,才能成功。
-
在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作并无作用,而在created()里使用this.$nextTick()可以等待dom生成以后再来获取dom对象
-
在下面方法里直接打印的话, 由于dom元素还没有更新, 因此打印出来的还是未改变之前的值,而通过this.$nextTick()获取到的值为dom更新之后的值
methods: {
get() {
this.value = '你好啊';
console.log(this.$refs['hello'].innerText);
this.$nextTick(() => {
console.log(this.$refs['hello'].innerText);
});
}
},
十二、渐进式框架的理解
答:主张最少;不必一开始就使用全家桶,可以根据不同的需求选择不同的层级;
十三、双向绑定
https://www.cnblogs.com/webcabana/p/11077628.html
https://segmentfault.com/a/1190000014274840
-
observer就是利用 Object.defineProperty当属性发生变化时,会触发set方法,在set里面触发更新函数
-
warcher里面定义了根据data改变view的方法-更新函数,从而更新视图。
-
compile为每个指令的dom绑定了warcher的更新函数 。还有根据view改变data值的方法,此时会触发observer。
十四、生命周期
vue实例有一个完整的生命周期,生命周期也就是指一个实例从开始创建到销毁的这个过程
-
beforeCreate()
在实例创建之间执行,数据未加载状态 -
created()
在实例创建、数据加载后,能初始化数据,dom
渲染之前执行 -
beforeMount()
虚拟dom
已创建完成,在数据渲染前最后一次更改数据 -
mounted()
页面、数据渲染完成,真实dom
挂载完成 -
beforeUpadate()
重新渲染之前触发 -
updated()
数据已经更改完成,dom
也重新render
完成,更改数据会陷入死循环 -
beforeDestory()
和destoryed()
前者是销毁前执行(实例仍然完全可用),后者则是销毁后执行
十五、父子组件之间的传值
-
父向子传值props 父:<child :title="name"> 子:
props: {
title: {
type: String,
default: 'hello world'
}
} -
子组件向父组件传值$emit 父:<child v-on:func="childByValue"></child> 子:this.$emit('childByValue', this.name)
-
在子组件中加上ref即可通过this.$refs.method调用 父: <children ref="refName"></children> this.$refs.refName.childMethods();
-
可以通过$parent和$children获取父子组件的参数
十六、路由router
-
动态路径参数
-
query传参
路由:
var router = new VueRouter({
routes: [
{ path: '/login', component: login },
{ name:'register',path: '/register', component: register }
]
})
导航:
// 注意:这是 query 两种传参方式 一种是直接跳转把字符串传过去 一种是传描述目标位置的对象
<router-link to="/login?id=10&name=zs">登录</router-link>
<router-link :to="{path:'/register',query:{id:5,name:'lili'}}">注册</router-link>
或
<router-link :to="{name:'register',query:{id:5,name:'lili'}}">注册</router-link>
** 注意
:jquery可以通过name或path来引入路由**
-
params传参
路由:
var router = new VueRouter({
routes: [
{ path: '/login/:id/:name', component: login },// 这里不传入对应的参数(:/id/:name) 刷新页面 参数会消失,页面中就丢失了数据
{ name:'register', path: '/register/:id/:name', component: register }
]
})
导航:
// 注意:这是 params 两种传参方式 一种是直接跳转把字符串传过去 一种是传描述目标位置的对象
<router-link to="/login/12/ls">登录</router-link>
<router-link :to="{name:'register',params:{id:10,name:'lili'}}">注册</router-link>
等同于:
this.$router.push('/login/12/ls')
this.$router.push({name:'register',params:{id:10,name:'lili'}})
注意
:params只能通过name来引入路由,path会undefined
params 是路由的一部分,在请求地址上。query 是拼接在 url 后面的参数 params 不设置的时候,刷新页面或者返回参数会丢,query 则不会有这个问题
-
当使用一个通配符时,
$route.params
内会自动添加一个名为pathMatch
参数。它包含了 URL 通过通配符被匹配的部分:
// 给出一个路由 { path: '/user-*' }
this.$router.push('/user-admin')
this.$route.params.pathMatch // 'admin'
// 给出一个路由 { path: '*' }
this.$router.push('/non-existing')
this.$route.params.pathMatch // '/non-existing'
-
$route和$router的区别
$router
为VueRouter
实例,想要导航到不同URL
,则使用$router.push
方法$route
为当前router
跳转对象里面可以获取name
、path
、query
、params
等
-
嵌套路由传参
const router = new VueRouter({
routes: [
{
path: '/user/:id',
component: User,
children: [
// 当 /user/:id 匹配成功,
// UserHome 会被渲染在 User 的 <router-view> 中
{ path: '', component: UserHome },
{
// 当 /user/:id/profile 匹配成功,
// UserProfile 会被渲染在 User 的 <router-view> 中
path: 'profile',
component: UserProfile
},
{
// 当 /user/:id/posts 匹配成功
// UserPosts 会被渲染在 User 的 <router-view> 中
path: 'posts',
component: UserPosts
}
]
}
]
})