传统前端中一个网页应用是由很多.html文件组成,每个html文件又分为三部分,第一部分就是用于展示视图,第二部分是
用于和用户交互,第三部分是
用于控制视图的样式。开发中一般会将js脚本和样式文件单独抽出来作为一个单独的文件。如果想在一个html中嵌入另一个html可以通过
来实现。
现代前端中一个网页应用是由多个.vue文件组成,每个vue文件又分为三部分,第一部分就是用于展示视图,第二部分是
用于和用户交互,第三部分是
用于控制视图的样式。开发中通常都将
、
来导入,在ES6中使用import 变量名 from '文件路径'
语法来导入,作用是将某个文件创建成对象,然后将该对象赋值给一个变量名,可以导入 .js .vue .json文件,其中文件后缀名也可以省略
import commonUtil from '@/utils/CommonUtil.js'
import foo from '@/components/Foo.vue'
两者效果类似
var commonUtil = new CommonUtil();
var foo = new Foo();
export(导出):export default 用于导出一个Vue的实例选项{ }, 被导出的对象可以通过import来导入,从而引用被导入的对象的属性和函数。在导入时可以通过@符号来表示src,导入时当后缀是.js、.vue、.json时是可以省略的,这些配置都可以在build/webpack.base.conf.js下的module.exports.resolve配置。在vue中导出的对象是一个Vue对象(包含name、data、methods等属性),Vue中有多个属性。
build/webpack.base.conf.js
module.exports = {
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
}
},
// 导出默认的Vue对象
export default {
// 配置Vue中的属性,如name、data、methods等
name: 'HelloWorld',
data() {
return { foo: 'foo', bar: 'bar' }
},
methods: {
foo() {
},
bar() {
}
}
}
我们定义一个非常简单的组件YesOrNoSelect.vue,组件中模板只有一个下拉框,导出的Vue实例选项也只有name和data,一个非常简单的样式。我们在另一个组件HelloWorld.vlue中导入importYesOrNoSelect.vue, 然后就可以在HelloWorld.vlue中来访问YesOrNoSelect.vue组件中导出的对象。
YesOrNoSelect.vue
<template>
<select>
<option v-for="item in options" v-bind:key="item.id">{{item.text}}option>
select>
template>
<script>
export default {
name: 'YesOrNoSelector',
data () {
return {
options: [
{id: '', text:'全部'},
{id: 0, text:'否'},
{id: 1, text:'是'}
]
}
}
}
script>
<style scoped>
select {
width: 100px;
height: 30px
}
style>
HelloWorld.vue
<template>
<div>
<span>{{ msg }}span>
div>
template>
<script>
// 导入Vue
import YesOrNoSelect from '@/components/YesOrNoSelect'
export default {
name: 'HelloWorld',
data () {
return {
msg : 'Hello Vue!',
// 引用导入的Vue的实例选项
nameOfImportComponent: YesOrNoSelect.name,
dataOfImportComponent: YesOrNoSelect.data()
}
}
}
script>
style里和传统的css差不多,不同的是支持了更多的语法,比如scss、less、stylus等。
每个.vue文件都对应着一个Vue实例对象,每个Vue实例对象从创建到销毁都会经历以下几个过程:
开发中经常使用created函数做一些初始化工作,比如页面一加载时执行的动作。
<template>
<div>
<span>{{ msg }}span>
div>
template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg : 'Hello Vue!'
}
},
created() {
console.log('init method created :'+ this.msg)
}
}
script>
一个Vue实例包含如下几个属性和函数,这些属性和函数统称为选项options(就像配置参数一样)。下面使用伪代码列举了Vue的一些常用的属性和函数。
/**
* Vue 数据结构伪代码
*/
interface Vue {
/** 组件名称 */
String name;
/** 模板视图 */
String template;
/** 在这里定义方法,可以定义多个 */
Object methods;
/** 局部注册组件 */
Object components;
/** 计算属性 */
Object computed;
/** 过滤器 用于格式化文本(如 金额、日期、货币) */
Object filters;
Object watch;
/** 属性(properties) */
Object props;
/** 局部注册指令 */
Object directives;
Object[] mixins;
/**
* 根据选项返回一个Vue实例
* 类似于构造函数
*/
Vue extend (options) {
}
/**
* 定义双向绑定的变量
* 在Vue实例中可以直接通过this来访问data函数返回值的对象的属性值
*/
public Object data {
return { }
}
/**
* Vue实例创建完成时执行的函数
* 常用与做一些初始化操作,比如页面一加载就需要执行的动作。
*/
public void created {
}
public void activated {
}
}
5.2.1 定义需要被引入的组件YesOrNoSelect.vue
<template>
<select>
<option v-for="item in options" v-bind:key="item.id">{{item.text}}option>
select>
template>
<script>
export default {
name: 'YesOrNoSelector',
data () {
return {
options: [
{id: '', text:'全部'},
{id: 0, text:'否'},
{id: 1, text:'是'}
]
}
}
}
script>
<style scoped>
select {
width: 100px;
height: 30px
}
style>
5.2.2 注册组件
在main.js中全局注册
import YesOrNoSelect from '@/components/YesOrNoSelect'
Vue.component('yes-or-no-select', YesOrNoSelect)
或者在HelloWorld.vue中局部注册
<script>
import YesOrNoSelect from '@/components/YesOrNoSelect'
export default {
name: 'HelloWorld',
components: {
YesOrNoSelect
}
}
</script>
5.2.3 使用自定义的组件 HelloWorld.vue
<template>
<div>
YesOrNo: <yes-or-no-select />
div>
template>
<script>
import YesOrNoSelect from '@/components/YesOrNoSelect'
export default {
name: 'HelloWorld',
data () {
return {
}
}
}
script>
过滤器其实就是对输入的值进行处理,返回处理后的值。
过滤器既可以在文本插值表达式中使用,也可以在v-bind等指令中使用。
5.3.1 在main.js中注册过滤器
// 首字母大写
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
5.3.2 在模板中使用管道命令符 | 来对前面的值进行格式化处理
注意:管道命令符可以同时使用多次
<template>
<div>
文本插值:{{msg | capitalize}} <br>
指令:<input v-bind:value="msg | capitalize" />
div>
template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'shanghai'
}
}
}
script>
在main.js中导入第三方组件并使用组件
import ElementUI from 'element-ui'
// 使用时需要在你调用 new Vue() 启动应用之前完成
Vue.use(ElementUI)
new Vue({
el: '#app',
router,
components: { App },
template: ' '
})
计算属性(computed):插值表达式{{ }}只适合比较简单的计算,如果计算逻辑比较复杂可以放到computed中作为一个函数,然后在插值表达式中直接将这个函数作为一个普通属性来使用。属性名称为计算属性对应的函数名称。
注意计算属性会缓存,当相关依赖没有发生变化时是直接返回缓存中的值而不会重新计算。
<template>
<div>
计算属性: {{upperCase}} <br>
局部过滤器: {{realName | upperCaseFilter}} <br>
方法调用: {{upperCaseMethod(realName)}}
div>
template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
realName: 'zhang san'
}
},
computed: {
upperCase () {
return this.realName.toLowerCase().split(/\s+/).map(function(item) {
return item.slice(0, 1).toUpperCase() + item.slice(1);
}).join(' ');
}
},
filters: {
upperCaseFilter (value) {
return value.toLowerCase().split(/\s+/).map(function(item) {
return item.slice(0, 1).toUpperCase() + item.slice(1);
}).join(' ');
}
},
methods: {
upperCaseMethod(value) {
return value.toLowerCase().split(/\s+/).map(function(item) {
return item.slice(0, 1).toUpperCase() + item.slice(1);
}).join(' ');
}
}
}
script>
使用方式 | 是否会缓存 | 使用场景 | |
---|---|---|---|
计算属性(computed) | 直接作为普通属性来使用 {{ foo }} |
会缓存(当依赖的值没有发生变化时) | 使用比较多,计算比较复杂的 |
过滤器(filter) | 通过管道命令符| 来使用{{value | foo}} |
不会缓存,每次都会执行函数 | 过滤数据或者格式化文本(日期、金额等) |
方法(method) | 方法调用通过小括号() { {foo(value) }} |
不会缓存,每次都会执行函数 | 一般的函数 |
相同点:其实三者都能达到相同的目的,只不过在使用方式上语法上有一点区别,应用场景上有一点点小区别。
监听某个值的改变, 监听的值要和watch中的函数名保持一致。功能上和oninput事件差不多。
<template>
<div>
<input v-model="keyword"/>
div>
template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
keyword: ''
}
},
watch: {
keyword() {
console.log('keyword=' + this.keyword)
}
}
}
script>
<template>
<div>
Vue.extend(options)
div>
template>
<script>
import Vue from 'vue'
let options = {
data () {
return {
msg: 'Hello Vue!',
foo: 'bar'
}
},
created () {
console.log(this.msg)
}
}
// 构造Vue
let Component = Vue.extend(options)
// 创建组件对象,会调用选项中的created函数
let component = new Component()
export default {
}
script>
mixin(混入): 就是预先定义一个Vue选项(options),此时称之为混入(mixin),在创建Vue实例时将混入对象传给Vue选项,由于混入对象定义了一些Vue选项,而在创建Vue实例时也会定义一些选项,两者混合在一起,当重复时会根据一定的优先级是使用混入对象的属性还是使用Vue实例的属性。
<template>
<div>
mixin
div>
template>
<script>
import Vue from 'vue'
let mixin = {
data () {
return {
foo: 'foo mixin',
msg: 'msg mixin'
}
},
methods: {
foobar () {
console.log("foobar method mixin")
}
},
created () {
console.log('created function mixin')
}
}
let vm = new Vue({
mixins: [mixin],
data () {
return {
bar: 'bar self',
msg: 'msg self'
}
},
methods: {
foobar () {
console.log("foobar method self")
}
},
created () {
console.log('created function self')
}
})
console.log(vm.$data)
vm.foobar()
export default {}
script>
props可以为自定义标签(组件)来自定义属性。使用组件时可以通过自定义属性来向子组件传递参数。
props的作用就是父组件(使用子组件的组件)向子组件(被引用的组件)传递参数。
Props类型:
传值方式:
无论静态传值还是动态传值推荐使用v-bind指令
声明了两个自定义属性props,自定义属性可以在指令或者文本插值表达式中使用:
<template>
<label>
<select v-model="index === undefined ? 0 : index">
<option v-for="item in options" v-bind:key="item.id" :value="item.id">{{item.text}}option>
select>
label>
template>
<script>
export default {
name: 'YesOrNoSelect',
props: {
options: Array,
index: Number,
}
}
script>
<style scoped>
select {
width: 100px;
height: 30px;
}
style>
<template>
<div>
YesOrNo: <yes-or-no-select :options="options" :index="2"/> <br>
div>
template>
<script>
import YesOrNoSelect from './YesOrNoSelect'
export default {
name: 'HelloWorld',
components: {YesOrNoSelect},
data () {
return {
options: [
{id: 0, text:'全部'},
{id: 1, text:'否'},
{id: 2, text:'是'}
]
}
}
}
script>
$refs
: 获取子组件对象,先在子组件使用属性ref定义一个引用名称,然后根据this.$refs.引用名称
就能获取到子组件对象。获取到子组件对象是非常重要的,这意味着在父组件中可以和子组件进行通讯。子组件定义了一个getSelectedValue方法,供父组件来调用。
<template>
<label>
<select v-model="index === undefined ? 0 : index">
<option v-for="item in options" v-bind:key="item.id" :value="item.id">{{item.text}}option>
select>
label>
template>
<script>
export default {
name: 'YesOrNoSelect',
props: {
options: Array,
index: Number,
},
methods: {
getSelectedValue() {
return this.index
}
}
}
script>
<style scoped>
select {
width: 100px;
height: 30px;
}
style>
父组件,在自定义标签中使用ref来定义一个引用的名称,然后通过this.$refs.引用名称
就能拿到子组件对象,从而就可以调用子组件的方法。
<template>
<div>
YesOrNo: <yes-or-no-select ref="yesOrNo" :options="options" :index="2"/> <br>
<button @click="getValue">调用子组件的方法button>
div>
template>
<script>
import YesOrNoSelect from './YesOrNoSelect'
export default {
name: 'HelloWorld',
components: {YesOrNoSelect},
data () {
return {
options: [
{id: 0, text:'全部'},
{id: 1, text:'否'},
{id: 2, text:'是'}
],
value: 0
}
},
methods: {
getValue () {
this.value = this.$refs.yesOrNo.getSelectedValue()
console.log(this.$options)
console.log(this.$data)
}
}
}
script>
注意:这里有个警告(Vue warn), 原因是我们在v-model="index === undefined ? 0 : index"
对自定义的属性进行了运算,Vue推荐不应该对父组件传递过来的值进行计算,所以给出了一个警告,这个警告可以通过计算属性来实现,去除警告,但如果使用计算属性来实现那么v-mode的值index就不能随着option的改变而改变了。具体原因请参考官网Prop ,所有的警告都可以在生产环境下来去掉警告提示。
this.$refs.引用名称
来获取到子组件对象,通过调用子组件的方法来获取子组件中的值。这样父组件就能获取到子组件内部的数据。开发中控制台经常报警告(可能是Vue不推荐这样做,但是却是自己想要的效果),如果想关闭警告可以通过Vue.config.productionTip 来配置。
// 生产环境下不警告
// 如果想在开发环境(npm run dev)下去掉警告可以修改dev.env.js 将NODE_ENV改为production值即可
Vue.config.productionTip = false