1.项目文件vueCli3.0下:
pulic文件下:favicon.ico是网址上方标题的的小图标。
index.html:是入口文件。
src:项目的主文件:
assets:是存放静态资源(如,图片,css等)的文件。
img:存放图片文件。
iconfont:图标字体文件。
components:可复用的组件。
views:页面。
api:项目的ajax请求请求。
config:项目的配置文件。
index.js:配置,在需要的地方import config from "./config/index.js"引入配置对象即可。
directive:存放vue的自定义指令。
index.js:
lib:
tools.js:存放与业务无关的,纯粹的工具方法。
util.js:存放与业务结合有关的。
router:存放路由有关的,将router.js移入该文件内。
index.js: 存放引入文件,配置路由实例。
router.js: 单独存放处理路由文件,配置路由列表。
store: 存放状态管理的文件。store.js移入到该文件内,修改为index.js。记得修改main.js的入口文件
index.js:
mutations.js:
import getters from "./getters" //相当于计算属性,对state参数的计算
state.js:
actions.js:
mudels:存放模块文件。
user.js:如存放用户的登录信息
mock: 模拟返回的数据,在后台接口还么有完成,前端通过模拟数据。 npm install mockjs -D下载 ,import Mock from "mockjs"引入
index.js: import Mock from "mockjs"引入
vue.config.js:自定义设置文件的配置,如跨域请求地址,简写src为@,设置项目的基本路径。
2. vscode编译器的:添加配置编译器的文件:
在src同级下.editorconfig:
root=true
[*] //表示该编译器配置针对所有文件
charset=utf-8
indent_style=tabs 缩进键
indent-size=2 缩进的大小
然后在编译器中安装editorConfig for VS Code,然后就可运行添加的配置编译器的文件了
3. router-link 是封装了的a标签。router-view渲染路由视图,两者效果一样。
命名路由:即路由有name属性name: 'home',<router-link to="/about"></router-link> 相当于命名路由 <router-link :to="{name:'about'}"></router-link>
3.1 配置路由列表的5种方法:
a.import Home from './views/Home.vue',如果有 name: 'home',表示命名路由
{
path: '/',
alias:'/home_page', //别名,即访问"/home_page"和访问"/"和通过name:"home",访问的效果是一样的
name: 'home',
component: Home //普通写法
},
{
path: '/home1',
name: 'home1', //命名路由
},
b.这样写,有懒加载的作用,即该页面显示时才会加载。不需要import Home from './views/Home.vue'。
{
path: '/about',
name: 'about',
component: () => import('./views/About.vue')
},
c.高级写法,动态加载路由,name是参数,{{$route.params.name}}调用参数name的值。
{
path: '/argu/:name',
props:true, //表示允许组件props:{}中接受name参数值,然后可以直接渲染在页面{{name}}
name: 'argu',
component: () => import( './views/argu.vue')
},
d.嵌套路由。 <div class="parent"> <router-view/> </parent>
{
path: '/parent', //嵌套路由
component: () => import('./views/Argu.vue'),
children:[
{
path:"child1", //注意只有父级需要'/'
component: () => import( './views/child1.vue'),
},
{
path:"child2",
component: () => import('./views/child2.vue'),
},
]
},
e. 命名视图:同时存在多个路由跳转时<router-view/> <router-view name="email"/> <router-view name="tel"/>
{
path: '/name_router',
components: {
default:() => import('./views/about.vue') , //如果<router-view/> 没有name属性值,默认对应该路由
email:() => import('./views/parent.vue') , //<router-view name="email"/> 对应该路由
tel:() => import('./views/argu.vue') //<router-view name="tel"/> 对应该路由
}
},
f. 重定向:重新定义跳转的路径,即本来是访问 '/home',重新绑定跳转到"/"
{
path: '/home',
redirect:"/", //3种重定向的方法
// redirect:{
// name:"home1"
// },
// redirect:to =>{ //如根据参数确定跳转到哪个页面
//// console.log(to)
//// return "/"
// return {
// name:"home1"
// }
// },
},
4. js操作路由(即编程式的导航):
a. 返回/前进一页:返回:this.$router.go(-1)、this.$router.back()。前进:this.$router.go(1)。
b. 跳转到其他页:
this.$router.push("/parent")。
this.$router.push({name:"parent",query:{name:"ace"}),即浏览历史纪录保存着,query是参数。
this.$router.push({path:`/argu/${name}`}) ,es6带参数跳转,针对 path: '/argu/:name',该路由。
this.$router.push({path:"/parent",params:{name:"ace"}) , 带参数跳转。
c. 用其他页替换本页:this.$router.replace("/about")或this.$router.replace({name:"parent"}),即浏览历史纪录没有了。
5. 路由传值:
5.1 基于动态匹配的页面(path: '/argu/:name')传值。
{
path: '/argu/:name',
props:true, //表示允许Argu.vue组件中props:{}中接受name参数值,然后可以直接渲染在页面{{name}}
component: () => import( './views/argu.vue')
},
5.2 基于普通页面传参,对象模式传参。
{
path: '/about',
props:{
food:"香蕉"
}, //表示允许about.vue组件中props:{}中接受food参数值,然后可以直接渲染在页面{{food}}
component: () => import( './views/argu.vue')
},
5.3 基于普通页面传参,函数模式传参。
{
path: '/parent',
props: route=>{
return {
food:route.query.food
}
}, //表示允许parent.vue组件中props:{}中接受food参数值,然后可以直接渲染在页面{{food}}
component: () => import( './views/argu.vue')
}
6. 导航守卫:如根据是否登录或登录者的权限跳转不同的页面,
6.1 全局守卫:即在全局设置一个守卫。在router/index.js中配置全局守卫
const router=new Router({
routes
})
const IS_LOGIN=true //是否登录的判断
router.beforeEach((to,form,next)=>{ //router实例的beforeEach方法是注册一个全局前置守卫,从from路由对象到to路由对象,
if(to.name !=="login"){ //如果即将跳转的页面不是登录页面
if(IS_LOGIN) {
next() //如果已即登录,就直接跳转
}else{
next({name:'login'}) //如果没有登录,就跳转到登录页面
}
}else{ //如果即将跳转的页面是登录页面
if(IS_LOGIN) {
next({name:'home'}) //如果已即登录,就直接跳转首页,{name:'home'}也可是'/home'
}else{
next() //如果没有登录,就直接跳转
}
}
})
router.beforeResolve((to,form,next)=>{ //router实例的beforeResolve方法是注册一个全局守卫,从from路由对象到to路由对象,即页面跳转前所有钩子执行完最后执行该函数 ,
})
router.afterEach((to,form)=>{ //router实例的afterEach方法是注册一个全局钩子,从from路由对象到to路由对象,即页面跳转之后执行,
//loading=false
})
6.2 组件守卫:即该组件独有的守卫。 在router/router.js中配置组件守卫
{
path: '/',
component: Home, //普通写法
beforEnter:(to,from,next)=>{ //该组件独有的守卫
if(from.name="login"){
alert("这是从登陆页面跳转过来的")
}else{
alert("这不是从登陆页面跳转过来的")
}
next() //一定要在最后执行next(),否则不会跳转
},
6.3 在组件里面的3种守卫,如在login.vue组件里面:
a.beforeRouteEnter:即将跳转到当前页面,但是页面还没有渲染,所有里面的this不指向实例vue该组件
beforeRouteEnter(to,from,next){
console.log(to.name)
next(vm=>{
console.log(vm) //而这里的vm就是该组件的实例了。
})
}
b.beforeRouteLeave:即将离开当前页面时执行,如即将离开编辑页面,弹出提醒框,提醒你是否保存编辑内容。
beforeRouteLeave(to,from,next){ //此时组件是已经渲染了,this可以执行vue实例
const leave=confirm("你确定要离开本页面么?")
if(leave){next()}
else{next(false)} //false表示不发生页面跳转
}
c.beforeRouteUpdate:即路由发生改变,组件(复用组件)被复用时,执行。如同一个页面,在url上修改了参数之后,该页面被复用了,就会执行
beforeRouteUpdate(to,from,next){ //此时组件是已经渲染了,this可以执行vue实例
console.log(to.name)
}
注意:整个导航守卫的流程:
a. 导航被触发:即url路由地址发生改变。
b. 在失活的组件:即将离开的页面组件,里调用离开守卫函数(beforeRouteLeave)。
c. 调用全局的前置守卫:即函数beforeEach。
d0. 如果跳转的是重/复用的组件里调用:在复用/重用的组件里调用函数beforeRouteUpdate。
d1. 如果跳转的是新的组件调用:在新的组件里调用beforeRouteEnter。
e. 调用路由独享的守卫:即router/router.js里面的函数beforEnter 。
f. 解析异步路由组件:
g. 在被激活的组件里(即将进入的页面):调用beforeRouteEnter。
h. 调用全局的解析守卫:即调用beforeResolve。
i. 导航被确认。
j. 调用全局的后置守卫:afterEach。
k. 触发DOM的渲染。
l. 用创建好的实例调用beforeRouteEnter守卫传给next()的回调函数。
7. 通过页面组件的meta:字段设置每个页面的window.document.title标题。
如在login.vue组件中:
meta:{ //与生命周期平级。
title:"我是登录页面标题"
}
然后在router/index.js的beforeEach中设置,import {setTitle} from "@/lib/util.js"
to.meta.title && setTitle(to.meta.title)
在lib/util.js中
export const setTitle =(title)=>{
window.document.title=title || "vue-cli3"
}
8. 设置路由跳转时的动画效果:
8.1 静态设置动画效果:
<transition-group name="router"> //一组路由视图,设置动画效果,必须写key值。然后在css中设置.router-enter/leave-to/active样式。
<router-view key="default"/>
<router-view key="email"/>
<router-view key="tel"/>
</transition-group>
8.2 动态设置动画效果:
<transition-group :name="transitionName"> //一组路由视图,设置动画效果,必须写key值。然后在css中设置.router-enter/leave-to/active样式。
<router-view key="default"/>
<router-view key="email"/>
<router-view key="tel"/>
</transition-group>
data(){
return{
transitionName:""
}
},
watch:{
"$route" (a){ //a表示当前页面,表示如果在url传入参数transitionName="router",则a.query.transitionName='router'
a.query && a.query.transitionName && (this.transitionName =a.query.transitionName)
}
}
9. 父组件与子组件的传值:
9.1 父传值给子组件:props传值
父组件:
<div class="parent">
<son-assembly :sendVal="value"></son-assembly>
</div>
子组件:
<div class="son">
{{value}}
</div>
props:{
son:{
type:[String,Number],
default:"123"
}
}
9.2 子传值给父组件:自定义事件传值
子组件:
<div class="son"></div>
this.$emit("aceHandle",val)
父组件:
<div class="parent" @aceHandle="myHandle"></div>
myHandle(val){
console.log("这是自定义事件传值",val)
}
注意:在vue中@input="inputHandle" 表示input输入值改变时触发的内置事件。inputHandle(e){console.log("输入框的值是",e,target.val)}
10.bus传值,状态管理:bus即空的vue实例,如用于简单场景下的兄弟组件之间传值。
10.1 src下创建bus/index.js文件。
import Vue from "vue"
const Bus=new Vue()
export default Bus
10.2 在main.js引入bus,并添加到vue的原型对象里,然后在任何地方都可以不需要在引入,直接使用this.$bus.
import Bus from './bus/index.js'
Vue.prototype.$bus=Bus
10.3 从兄弟组件A传值给兄弟组件B:
A组件:
this.$bus.$emit("myHandle",val)
B组件:
mouted(){
this.$bus.$on("myHandle",(val)=>{ //监听自定义事件myHandle
//在这里处理接收到B组件传递过来的值
})
}
11. vuex传值,状态管理:src下创建store文件用于vuex状态管理
11.1 index.js入口文件的管理: 然后在main.js中引入import store from './store/index.js',然后全局设置new Vue({store}).$mount('#app')
import Vue from 'vue'
import Vuex from 'vuex'
import state from "./state" //全局状态参数管理
import getters from "./getters" //相当于计算属性,对state参数的计算
import mutations from "./mutations"
import actions from "./actions"
import user from "./mudule/user.js" //单独某个模块如用户模块user的状态管理
Vue.use(Vuex)
export default new Vuex.Store({
state , //es6语法相当于state:state
getters,
mutations ,
actions,
mudules:{
user
}
})
11.2 state.js全局状态参数管理:
定义全局参数:
const state={
appName:"我是全局参数,在组件内都可传递值"
}
export default state
调用全局参数值:
方法1:
在某个组件内{{this.$store.state.appName}}就可获取该值了,或通过可在该组件写入到计算属性中computed
computed:{
appName(){
return this.$store.state.appName
}
}
<p>{{appName}}</p>
方法2:
import {mapState} from "vuex"
computed:{
...mapState(["appName"]) //这2种写法一样。...表示展开一个对象。
// ...mapState({
// appName:state=>state.appName
// })
}
<p>{{appName}}</p>
11.3 user.js 获取模块中user.js里面的状态参数管理:
定义单独某个模块中全局参数:
const state={
userName:"我是user模块的参数值"
}
const mutations={}
const actions={}
export default{
state,
mutations,
actions
}
调用单独某个模块全局参数值:
方法1:
在某个组件内{{this.$store.state.user.userName}}就可获取该值了,或通过可在该组件写入到计算属性中computed
computed:{
userName(){
return this.$store.state.user.userName
}
}
<p>{{userName}}</p>
方法2:
import {mapState} from "vuex"
computed:{
...mapState(["userName"]) //这3种写法一样。...表示展开一个对象。
// ...mapState({
// userName:state=>state.user.userName
// })
// ...mapState("user",{ //传入模块名
// userName:state=>state.userName
// })
}
<p>{{userName}}</p>
注意:在模块状态管理中如果有命令空间,即
export default{
namespaced:true, //设置命名空间为true,使得模块更加密闭,不受到外界的干扰
state,
mutations,
actions
}
方法3:
import {createNamespacedHelpers} from "vuex"
const {mapState}=createNamespacedHelpers("user") //参数user是命令空间的名称(模块名,user.js)
computed:{
...mapState(["userName"]) //这2种写法一样。...表示展开一个对象。
// ...mapState({ //不许要在传入模块名了
// userName:state=>state.userName
// })
}
<p>{{userName}}</p>
11.4 getters.js相当于组件的computed计算属性,是对state状态的计算处理。 在模块如user.js中使用getters和使用state方法一样
定义getters(计算属性):
const getters={
appNameVersion:(state)=>{ //依赖于state.js
return state.appName+"v2.0"
}
}
export default getters
调用getters(计算属性的结果):
方法1:
在某个组件内{{this.$store.getters.appNameVersion}}就可获取该值了,或通过可在该组件写入到计算属性中computed
computed:{
appNameVersion(){
return this.$store.getters.appNameVersion
}
}
<p>{{appNameVersion}}</p>
方法2:
import {mapGetters} from "vuex"
computed:{
...mapGetters(["appNameVersion"]) //这3种写法一样。...表示展开一个对象。
// ...mapGetters({
// userName:state=>state.appNameVersion
// })
}
<p>{{appNameVersion}}</p>
11.5 mutations.js修改state状态参数的值;
在mutations定义修改state的事件:
import vue from "vue"
const mutations={
set_app_name(state,params){ //state表示store/state.js,params是要修改state状态中参数的新值,可能是对象,或字符串
state.appName=params //参数时字符串
// state.appName=params.appName //参数时对象
},
set_app_version(state){ //如果stata.js中没改属性参数,这个表示给state.js中添加version并赋值v2.0
vue.set(state,"version","v2.0")
}
}
export default mutations
在组件里调用上面定义的事件:
方法1:
this.$store.commit("set_app_name","我是state.js里新修改的appName的值") //参数是字符串
this.$store.commit("set_app_name",{appName:"我是state.js里新修改的appName的值"}) //参数是对象
this.$store.commit({type:"set_app_name",appName:"我是state.js里新修改的appName的值"}) //参数是对象,且事件也包含在对象里
方法2:
在组件的方法里
import {mapMutations} from "vuex"
methods(){
...mapMutations([
"set_app_name",
"set_app_version"
]),
Handle(){
this.set_app_version("newAppName");
this.set_app_name()
}
}
注意:mutations和getters和actions在模块里面是在模块里且没有命令空间限制,
会默认将模块中的mutations和getters和actions注册在全局store文件下的mutations.js和getters.js和actions.js,如下写,且不需要传入模块名,如"user"
...mapMutations([
"set_app_name",
"set_app_version"
]),
但是如果有命令空间限制namespaced:true, //设置命名空间为true,使得模块更加密闭,不受到外界的干扰
...mapMutations("user",[ //需要传入模块
"set_app_name",
"set_app_version"
]),
11.6 action.js异步修改state.js的状态值,如通过获取后台数据,将state.js的值修改成后台获取的数据:
定义异步修改状态值的方法:
import {getAppName} from "@/api/app.js"
const action={ //异步操作状态的改变,如通过接受接口的api返回的数据,从而改变state.js的状态值
// updateAppName({commit}){ //es6写法:{commit},相当于func(obj){const commit=obj.commit}
// getAppName().then(res=>{
// console.log(res)
//// const {info:{appName}}=res; //es6的
//// commit("set_app_name",appName);
// commit("set_app_name",res.info.appName); //通过commit关联mutations.js中的是set_app_name()方法,从而异步修改state.js状态值
// }).catch(err){
// console.log(err)
// }
// }
async updateAppName({commit}){ //es8的语法,与上面执行结果一样,只是将异步变成同步。
try{
const {info:{appName}} =await getAppName()
commit("set_app_name",appName);
}catch(err){
console.log(err)
}
}
}
export default action
调用异步修改的状态值的方法:
方法1:
import {mapAction} from "vuex"
methods(){
...mapAction([
"updateAppName"
]),
Handle(){
this.updateAppName()
}
}
方法2:
this.$store.dispatch("updateAppName",val)
11.7 在模块中定义 action方法
user.js
const state={}
const mutations={}
const actions={
updateUserName({commit,state,rootState,dispatch}){ //commit用于提交到mutation,state值当前文件下state,rootState值store文件夹下state.js
rootState.appName
}
}
export default{
state,
mutations,
actions
}
11.8 api/app.js模拟后台接口返回数据:
export const getAppName=()=>{
return new Promise((resolve,reject)=>{
const err=null;
setTimeout(()=>{ //模拟接口操作请求
if(!err) resolve({code:200,info:{appName:"newAppName"}})
else reject(err)
})
})
}
12. vuex进阶-store插件----持久本地存储:
新建文件:store/plugin/saveInLocal.js
//定义一个持久化存在在本地的state状态管理的插件,即使每次刷新,也不会影响修改后的值
export default state=>{
console.log('store初始化时执行该函数');
if(localStorage.state){store.replaceState(JSON.stringify(localStorage.state))} //如此本地已经存储了,每次刷新页面(即初始化store时),
//就用mutation提交后的本地存储替换提交前的
store.subscribe((mutation,state)=>{
console.log("每次有提交mutation时就执行"); //每次提交mutation时,时都将state值存储在本地
localStorage.state=JSON.stringify(state); //state 是一个对象,转换为json字符串,存储在本地
})
}
在store/index.js中:
import saveInLocal from './plugin/saveInLocal.js'
export default new Vuex.Store({
state , //es6语法相当于state:state
mutations ,
getters,
actions,
mudules:{
user
},
plugins:[saveInLocal] //加载插件
})
13. store下的严格模式:在严格模式下,不能直接修改state里面的值(this.$store.state.user.userName="newName"),需要在mutation提交中修改,否则会报错(虽然也会修改)
在store/index.js下:
export default new Vuex.Store({
strict:true, //是否开启严格模式,process.env.NODE_ENV ==="devalopment" ,在开发环境下是严格模式,否则不是
state , //es6语法相当于state:state
mutations ,
getters,
actions,
mudules:{
user
},
plugins:[saveInLocal] //加载插件
})
14. v-model:如果绑定的属性不是组件data(){return{} }里面的属性,也是state里面的属性,就存在问题,因为state里面的属性时需要在mutation中修改。
v-model:的本质就是:在组件上绑定一个属性传值,再绑定一个@input事件监听,当输入的值有变化时,就直接替换掉原来的值,
解决双休绑定state值的方法:
方法1:<input :value="stateVal" @input="changeStateVal"/>
...mapMutations({"SET_STATE_VALUE"})
changeStateVal(val){
this.SET_STATE_VALUE(val) //在mutations.js中设置:SET_STATE_VALUE(state,val){state.stateVal=val} ,在state.js中设置stateVal:"abc"
}
方法2:<input v-model="stateVal"/>
...mapMutations({"SET_STATE_VALUE"})
computed:{
stateVal:{ //计算属性里stateVal是对象不是方法,有set()和get()方法
get(){
return this.$store.state.stateVal;
},
set(val){
this.SET_STATE_VALUE(val)
}
}
}
15. ajax请求:
15.1解决跨域问题:
方法1:在vue.config.js里面设置跨域代理请求:
devServer:{ //设置跨域,即将本文件内任何没有匹配到的静态文件,都指向跨域地址http://localhost:4000
proxy:'http://localhost:4000'
}
在发送axios请求里执行:
axios.post("/login",{uname:"Ace",upwd:"1234"}).then(data=>{})
方法二:
在发送axios请求里执行:
axios.post("http://localhost:3000/login",{uname:"Ace",upwd:"1234"}).then(data=>{})
在后台(如node的app.js)设置跨域:
app.all("*",(req,res,next)=>{ //*代表所有请求。
req.header("Access-Contral-Allow-Origin","*");
req.header("Access-Contral-Allow-Headers","X-Requested-Width,Content-Type");
req.header("Access-Contral-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
next();
})
15.2 封装axios:
15.2.1 请求/响应拦截:
创建文件lib/axios.js:
import axios from "axios"
import {baseURL} from "@/config/index.js"
class HttpRequest{ //es6的类的封装
constructor(baseUrl=baseURL){ //类的必须方法,如果没有主动添加,在类里会自动添加一个空的该方法,当new HttpRequest(参数时),该参数就是constructor的参数
this.baseUrl=baseUrl; //baseUrl=baseURL是es6的默认传参
this.queue={}, //一个空对象,用于存放每一次请求的url
}
getInsideConfig(){ //设置全局config配置
const config={
baseUrl:this.baseUrl,
headers:{
//
}
}
return config
}
interceptors(instance,url){ //axios拦截器方法 ,参数axios的实例
instance.interceptors.request.use(config=>{ //请求拦截器,config是发送请求时的配置参数
if(Object.keys(this.queue).length){ //判断this.queue队列是否有请求的url,Object.keys是获取一个对象的所有的key值
//添加一个全局的loding....,如iview中的spin的加载效果标签。
}
this.queue[url]=true; //设置queue对象的key值
console.log(config)
return config;
},error=>{ //error是请求错误时,返回的错误信息
return Promise.reject(error)
})
instance.interceptors.reponse.use(res=>{ //响应拦截器,res是服务端响应返回的数据
//移除一个全局的loding....,如iview中的spin的加载效果标签。
delete this.queue[url] //当请求成功了 ,就可以清除this.queue对列对于的值了
console.log(res)
return res;
},error=>{ //error是响应错误时,返回的错误信息
delete this.queue[url] //当请求失败了 ,就可以清除this.queue对列对于的值了
return Promise.reject(error)
})
}
request(options){ //options是创建请求的config配置,不是全局config配置
const instance=axios.create() //axios.create()创建一个axios实例,参数是配置对象
options=Object.assion(this.getInsideConfig(),options) //将俩个对象合并成一个对象,key相同的,后面的对象值覆盖前面的。
this.interceptors(instance,options.url);
return instance(options)
}
}
export default HttpRequest
15.2.2 在config/index.js配置基础信息:
//用于存放项目的配置
export const baseUrl=process.env.NODE.ENV==="production"
?"http://www.ace.com" //如果是开发环境,就写开发环境的接口
:" " //如果是在开发环境下,且已经设置了本地跨域代理 devServer:{ proxy:'http://localhost:4000'},
//这里设置空字符串,如果没有设置本地跨域代理这里就写'http://localhost:4000'
15.2.3 在api/index.js实例化axios
import HttpRequest from "@/lib/axios"
const axios=new HttpRequest() //创建一个HttpRequest实例
export default axios
15.2.4 在api/user.js中定义login.vue组件的登录接口:
import axios from "./index.js"
export default getUserInfo=({uanme})=>{
return axios.request({
url:"/getUserInfo",
method:'post',
data:{ //post请求,参数写在data里面
uname:uname
}
})
}
15.2.5 在login.vue组件里引入api/user.js中定义好的登录接口方法,然后调用:
import {getUserInfo} from "@/api/user.js"
getInfo(){
getUserInfo({uname:"Ace"}).then(res=>{
console.log(res)
})
}
16. 组件的ID命名,插槽的实现,DOM获取,以及父组件调用子组件的方法:
子:
<div>
<slot name="slot1"></slot>
<span :id="myId" ref="child"> 我是子组件</span>
<slot name="slot2"></slot>
</div>
父:
<div>
<v-child ref="childSpan"></v-child>
</div>
16.1 如何给组件命名id不会冲突其他组件的id名:this._uid在项目中,每个组件都有独一无二的_uid,给里面组件命名时,带上这个独一无二的_uid就会避免与其他组件命名冲突。
computed:{
myId(){
return `child_${this._uid}`
}
}
16.2 怎么获取子组件dom里面的内容(原生js获取和ref获取):
ref获取:this.$refs.child.innerText
原生js获取:document.getElementById(myId).innerText
16.3 父组件怎么调用子组件的方法:
this.$refs.childSpan.getChildInfo()
17. vue中操作dom元素:通过数据操作dom的width/height/top/bottom....
17.1 通过数据操作dom的width/height/top/bottom....
<div ref="div" :style={left:divLeft;width:`${divWidth}px` }>
<span @mousedown="downHandle"></span>
</div>
computed:{
divLeft(){
return ``
},
divWidth(){
return `clac(30%-4px)` //css3的属性clac()计算出百分比和px的结果
}
}
17.2 鼠标按下移动事件:
downHandle(e){
document.addEventListener("mousemove/mouseup",mousemoveHandle/mouseupHanlde) ; //给doucment绑定鼠标移动、松开事件
e.pageX //是获取触发downHandle的是鼠标距离页面左边的距离
this.$refs.div.getBoundingClientRect() ; //返回ref='div'元素dom的width,height,top,bottom,right....等信息的对象。
}
18. 在组件引入外部css的2种方法:
在script里面:import "../index.css"
在style里面:@import "../index.css"