【vue】上手vue

Vue实例

安装完vue-loader后,必须,

  • npm installl --save-dev vue-template-compiler
  • 在webpack配置文件的plugins字段添加VueLoaderPlugin
const {VueLoaderPlugin} = require("vue-loader");
module.exports = {
	plugins:[
		new VueLoaderPlugin()
	]
}

webpack打包时,默认加载的是vue/dist/vue.runtime.esm.js,但是如果代码里有字符串模板,则需要编译器将字符串模板编译成render函数,因此需要使用完整版本,即vue/dist/vue.esm.js
此时在webpack.config.js中添加如下配置即可。

module.exports = {
	resolve:{
		"alias":{
			"vue$":"vue/dist/vue.esm.js"
		}
	}
}

比如,

<body>
    <div id="root">
        <p>{{message}}</p>
    </div>
</body>
import Vue from "vue";
const vm = new Vue({
	el:"#root",
	data:{
		message:"hello world"
	}
})

如果直接使用vue的运行时版本,就会遇到这个问题:
vue.runtime.esm.js:638 [Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
这时,使用以上方法就可以解决。

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

创建一个vue实例,并传入选项对象。

<body>
    <div id="root">
        <div>{{a}},{{b}}</div>
    </div>
</body>
import Vue from "vue";

const data = {
    a:"hello",
    b:"world"
}
const vm = new Vue({
    el:"#root",
    data:data
});

console.log(vm.$data === data);
console.log(vm.$el);
vm.$watch("a",function(newValue,oldValue){
    if(newValue!==oldValue){
        console.log(`a is changed to be '${newValue}'`);
    }
})
data.a = "hi"

在这里插入图片描述

  • 在选项属性或者回调函数中,慎用箭头函数,因为this
    在这里插入图片描述
data

data对象中的属性会成为Vue实例vm的属性,所以可以访问vm.avm.b

<body>
    <div id="root">
        <div>{{a}},{{b}}</div>
    </div>
</body>
import Vue from "vue";

const vm = new Vue({
    el:"#root",
    data:{
        "a":"hello",
        "b":"world"
    }
});
console.log(vm.a);
console.log(vm.b);
computed
  • 计算属性也会成为Vue实例vm的属性
    计算属性reversedMessage成为了Vue实例vm的属性,所以可以访问vm.reversedMessage
<body>
    <div id="root">
        <div>{{message}}</div>
        <div>{{reversedMessage}}</div>
    </div>
</body>
import Vue from "vue";

const vm = new Vue({
    el:"#root",
    data:{
        "message":"hello world"
    },
    computed:{
        "reversedMessage":function(){
            return this.message.split("").reverse().join("");
        }
    }
});
console.log(vm.message);
console.log(vm.reversedMessage);
  • 计算属性默认只有getter,如果需要也可以提供setter
<body>
    <div id="root">
        <div>{{fullname}}</div>
    </div>
</body>
import Vue from "vue";

const vm = new Vue({
    el:"#root",
    data:{
        "firstname":"Steve",
        "lastname":"Jobs"
    },
    computed:{
        "fullname":{
            get:function(){
                return this.firstname+" "+this.lastname;
            },
            set:function(val){
                const [firstname,lastname] = val.split(" ");
                this.firstname = firstname;
                this.lastname = lastname;
            }
        }
    }
});

vm.fullname = "Tomas Edison"
watch
<body>
    <div id="root">
        <div><input type="text" v-model="content"></div>
        <div>content is {{content}}</div>
    </div>
</body>
import Vue from "vue";

const vm = new Vue({
    el:"#root",
    data:{
        "content":""
    },
    watch:{
        "content":function(newValue,oldValue){
            console.log(`content is '${newValue}'`);
        }
    }
});
指令
参数

v-bind:参数,如v-bind:title,将元素的title属性与表达式text绑定

<body>
    <div id="root">
        <div v-bind:title="text">hi</div>
    </div>
</body>
import Vue from "vue";

const vm = new Vue({
    el:"#root",
    data:{
        text:"hello world"
    }
});

在这里插入图片描述

v-bind:disabled,将元素的disabled属性与表达式isDisabled绑定。

<body>
    <div id="root">
        <button v-bind:disabled="isDisabled">click me</button>
    </div>
</body>
import Vue from "vue";

const vm = new Vue({
    el:"#root",
    data:{
        isDisabled:true
    }
});

在这里插入图片描述

动态参数

动态参数名最好全小写,如有必要,短横线分隔命名(kebab-case,如v-bind:[titlename]v-on:[eventname],但不要写成v-bind:[titleName]v-on:[eventName],因为浏览器在解析html时,会将元素属性名全部转换成小写。
在这里插入图片描述

组件

组件是可复用的Vue实例,所以它可以接受和new Vue()相同的选项对象,比如datacomputedwatchmethods、生命周期钩子等。唯一的例外就是el,它是根实例特有的。

组件名

放在html里的组件名最好 全部小写,如有必要,短横线分隔命名(kebab-case,因为浏览器在解析html标签时会将大写字母转换成小写字母。看个例子。

<body>
    <div id="root">
        <MyComponent></MyComponent>
    </div>
</body>
import Vue from "vue";

Vue.component("MyComponent",{
    template:"<div>hello world</div>"
})
const vm = new Vue({
    el:"#root"
})

在这里插入图片描述
针对以上问题,以下任一种方式都可以解决。
在这里插入图片描述

组件的data必须是一个函数

根实例的data是一个对象,但组件的data必须是一个函数

每个组件必须只有一个根元素
父组件通过props向子组件传递数据
props名

html里的props名最好全小写,如有必要,短横线分隔命名(kebab-case,因为浏览器在解析html时,会将props名从大写字母转换成小写字母。看个例子。

<body>
    <div id="root">
        <Counter initValue="10"/>
    </div>
</body>
import Vue from "vue";

Vue.component("Counter",{
    template:"<div>{{initValue}}</div>",
    props:["initValue"]
})
const vm = new Vue({
    el:"#root"
})

在这里插入图片描述
针对以上问题,以下任一写法皆可。
在这里插入图片描述

动静态props

props分静态和动态。

  • 静态props和普通的DOM属性差不多,比如title,静态props的值总是一个字符串
<body>
    <div id="root">
        <my-component a="hello" b="world"/>
    </div>
</body>
import Vue from "vue";
Vue.component("my-component",{
    template:'\
    <div>\
        <div>{{a}}</div>\
        <div>{{b}}</div>\
        <div>{{a+b}}</div>\
    </div>\
    ',
    props:["a","b"]
})
const vm = new Vue({
    el:"#root"
})
  • 动态props就是v-bind:名称,如v-bind:title,动态props的值可以是一个数值、布尔值、字符串、数组、对象等任意类型
<body>
    <div id="root">
        <my-component v-bind:a="10" v-bind:b="20"/> 
    </div>
</body>
import Vue from "vue";
Vue.component("my-component",{
    template:'\
    <div>\
        <div>{{a}}</div>\
        <div>{{b}}</div>\
        <div>{{a+b}}</div>\
    </div>\
    ',
    props:["a","b"]
})
const vm = new Vue({
    el:"#root"
})

在这里插入图片描述

<body>
    <div id="root">
        <my-component 
            v-bind:num="10"
            v-bind:is-need="false"
            v-bind:list="[1,2,3]"
            v-bind:obj="{a:'hello',b:'world'}"
        /> 
    </div>
</body>
import Vue from "vue";
Vue.component("my-component",{
    template:'\
    <div>\
    <div>{{num}} is {{Object.prototype.toString.call(num)}}</div>\
    <div>{{isNeed}} is {{Object.prototype.toString.call(isNeed)}}</div>\
    <div>{{list}} is {{Object.prototype.toString.call(list)}}</div>\
    <div>{{obj}} is {{Object.prototype.toString.call(obj)}}</div>\
    </div>\
    ',
    props:["num","isNeed","list","obj"]
})
const vm = new Vue({
    el:"#root"
})

在这里插入图片描述

  • v-bind传递一个对象的所有属性
<body>
    <div id="root">
        <todo-list></todo-list>
    </div>
</body>
import Vue from "vue";
Vue.component("todo-list",{
    template:'<ul>\
        <todo-item \
            v-for="item in list"\
            v-bind:key="item.id"\
            v-bind="item">\
        </todo-item>\
    </ul>',
    data:function(){
        return {
            list:[
                {id:"#1",title:"吃饭",isDone:true},
                {id:"#2",title:"睡觉",isDone:true},
                {id:"#3",title:"打豆豆",isDone:false},
            ]
        }
    }
});

Vue.component("todo-item",{
    props:["title","isDone"],
    template:'<li>\
        <input type="checkbox" v-model="isDone">\
        <span>{{title}}</span>\
    </li>'
});

const vm = new Vue({
    el:"#root"
})

在这里插入图片描述

props验证
<body>
    <div id="root">
        <Counter v-bind:init-value="10"/>
    </div>
</body>
import Vue from "vue";

Vue.component("Counter",{
    // props:{
    //     initValue:[String,Number]
    // },
    props:{
        initValue:{
            type:Number,
            required:true
        }
    },
    data:function(){
        return {
            count:this.initValue
        }
    },
    template:'<div>\
        <span>{{count}}</span>\
    </div>',
})

const vm = new Vue({
    el:"#root"
})

在这里插入图片描述
props的类型还可以是一个构造函数。

<body>
    <div id="root">
        <book-set/>
    </div>
</body>
import Vue from "vue";

function Person(firstname,lastname){
    this.firstname = firstname;
    this.lastname = lastname;
}
Vue.component("Book",{
    props:{
        author:Person
    },
    computed:{
        fullname:function(){
            const {firstname,lastname} = this.author;
            return firstname +" "+lastname;
        }
    },
    template:'<div>\
        <span>The author of the book is {{fullname}}</span>\
    </div>'
})
Vue.component("book-set",{
    data:function(){
        return {
            person:new Person("Steve","Jobs")
        }
    },
    template:'<Book v-bind:author="person"></Book>'
})

const vm = new Vue({
    el:"#root"
})

在这里插入图片描述

非prop的attribute
  • 非props的attributes会被添加到组件根元素上,且可以通过this.$attrs访问
  • 如果不想将 非props的attributes添加到组件的根元素上,使用 inheritAttrs:false
<body>
    <div id="root">
        <Counter v-bind:init-value="10"
                    a="hello"
                    b="world">
        </Counter>
    </div>
</body>
import Vue from "vue";

Vue.component("Counter",{
    inheritAttrs:false,
    props:["initValue"],
    template:'<div>\
    <span>{{count}}</span>\
    </div>',
    data:function(){
        return {
            count:this.initValue
        }
    },
    mounted:function(){
        console.log("this.$attrs",this.$attrs);
    }
})

const vm = new Vue({
    el:"#root"
})

在这里插入图片描述

子组件向父组件传递数据

子组件通过调用this.$emit(事件名称)触发一个事件,父组件则通过v-on:事件名称监听子组件发出的事件。
本例中,子组件this.$emit("message",this.count)$emit()的第二个参数,父组件里的事件处理程序可通过以下任一方式获取。

  • 第一种
    <Counter v-on:message='console.log($event)'/>
    $event的值就是this.count
  • 第二种
    <Counter v-on:message="handleMessage"/>
    事件处理程序handleMessage的第一个参数就是this.count

第一种

<body>
    <div id="root">
        <Counter v-on:message='console.log($event)'/>
    </div>
</body>
import Vue from "vue";

Vue.component("Counter",{
    template:'\
    <div>\
    <span>{{count}}</span>\
    <button v-on:click="handleClick">click me</button>\
    </div>\
    ',
    data:function(){
        return {
            count:0
        }
    },
    methods:{
        handleClick:function(){
            this.count++;
            this.$emit("message",this.count);
        }
    }
})
const vm = new Vue({
    el:"#root",
    data:{
        console:window.console
    }
});

第二种

<body>
    <div id="root">
        <Counter v-on:message="handleMessage"/>
    </div>
</body>
import Vue from "vue";


Vue.component("Counter",{
    template:'\
    <div>\
    <span>{{count}}</span>\
    <button v-on:click="handleClick">click me</button>\
    </div>\
    ',
    data:function(){
        return {
            count:0
        }
    },
    methods:{
        handleClick:function(){
            this.count++;
            this.$emit("message",this.count);
        }
    }
})
const vm = new Vue({
    el:"#root",
    methods:{
        handleMessage:function(a){
            console.log(a)
        }
    },
});
自定义事件

自定义事件名最好全小写,如有必要,使用短横线分隔命名(kebab-case

<body>
    <div id="root">
        <Counter v-on:countInc="handleInc"
                 v-on:countDec="handleDec"/>
    </div>
</body>
import Vue from "vue";


Vue.component("Counter",{
    template:'<div>\
            <span>{{count}}</span>\
            <button v-on:click="onIncrement">+</button>\
            <button v-on:click="onDecrement">-</button>\
            </div>',
    data:function(){
        return {
            count:10
        }
    },
    methods:{
        onIncrement:function(){
            this.count++;
            this.$emit("countInc");
        },
        onDecrement:function(){
            this.count--;
            this.$emit("countDec");
        }
    }
})
const vm = new Vue({
    el:"#root",
    methods:{
        handleInc:function(){
            console.log("handling inc");
        },
        handleDec:function(){
            console.log("handling dec");
        }
    }
})

在这里插入图片描述
针对以上问题,有如下两种解决方法。
在这里插入图片描述

内置组件slot实现内容传递

通过slot往组件中插入内容。

<body>
    <div id="root">
        <my-component>
            <div>world</div>
        </my-component>
    </div>
</body>
import Vue from "vue";

Vue.component("my-component",{
    template:'\
    <div>\
        <div>hello</div>\
        <slot></slot>\
    </div>\
    '
})
const vm = new Vue({
    el:"#root"
})

在这里插入图片描述

is属性

table标签,其子元素必须是theadtbodytrthtd,如果是其他元素,则会被提升到table的外部。举个例子。

<body>
    <div id="root">
        <table>
            <tr>
                <td>hello</td>
                <td>world</td>
            </tr>
            <div>have a nice day</div>
        </table>
    </div>
</body>

在这里插入图片描述

<body>
    <div id="root">
        <table>
            <my-component></my-component>
        </table>
    </div>
</body>
import Vue from "vue";

Vue.component("my-component",{
    template:'\
        <div>\
        <div>hello</div>\
        <div>world</div>\
        </div>\
    '
});
const vm = new Vue({
    el:"#root"
});

在这里插入图片描述
table中的内容被提取到了外面,不符我们的预期,如何破?is属性很给力!

<body>
    <div id="root">
        <table>
            <tr is="my-component"></tr>
        </table>
    </div>
</body>

import Vue from "vue";

Vue.component("my-component",{
    template:'\
        <div>\
        <div>hello</div>\
        <div>world</div>\
        </div>\
    '
});
const vm = new Vue({
    el:"#root"
});

在这里插入图片描述

内置组件component实现动态组件

<component v-bind:is=""></component>实现动态组件

<body>
    <div id="root">
        <component v-bind:is="currentId"></component>
        <button v-on:click="handleClick">toggle</button>
    </div>
</body>
import Vue from "vue";

Vue.component("one-component",{
    template:"<div>hello</div>"
});
Vue.component("two-component",{
    template:"<div>world</div>"
})
const vm = new Vue({
    el:"#root",
    data:{
        currentId:"one-component"
    },
    methods:{
        handleClick:function(){
            if(this.currentId === "one-component"){
                this.currentId = "two-component";
            }else if(this.currentId === "two-component"){
                this.currentId = "one-component";
            }
        }
    }
});

在这里插入图片描述

注意,<component></component>,不要<component/>
因为如果component后有内容,<component/>会导致其后面的内容无法显示。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值