สิ่งที่ใช้แทน :: ng-deep


94

ฉันกำลังพยายามจัดรูปแบบองค์ประกอบที่วางโดยเต้าเสียบเราเตอร์ในเชิงมุมและต้องการให้แน่ใจว่าองค์ประกอบที่สร้างขึ้นมีความกว้าง 100%

จากคำตอบส่วนใหญ่ฉันเห็นว่าฉันควรใช้::ng-deepตัวเลือก แต่จากเอกสารของ Angular มันกำลังถูกเลิกใช้ มีทางเลือกให้::ng-deepหรือไม่?


2
::ng-deepไม่ไปไหน จะเป็นการตั้งค่าที่คุณสามารถเปิดใช้งานได้เสมอ ไม่มีทางที่พวกเขาจะลบมันออกไปได้อย่างแน่นอนโดยไม่มีฟันเฟืองชุมชนขนาดใหญ่ ดูที่จำนวนผลลัพธ์กลับมาสำหรับการค้นหานี้github.com/search?q=%3A%3Ang-deep&type=Code - มันชอบพูดว่าแบบ CSS !importantคุณสมบัติเป็นไปหายไป
Simon_Weaver

ฉันไม่รู้ - ฉันทำการค้นหาทั้งโปรเจ็กต์ด้วยความอยากรู้อยากเห็นใน mono-repo ของเรา (แอพสำหรับองค์กรขนาดใหญ่หลายตัว) และมีข้อมูลอ้างอิง 69 รายการเท่านั้น ฉันรู้สึกว่านั่นเป็นตัวปรับปฏิกิริยาที่ยอมรับได้อย่างแน่นอนที่จะย้ายออกจากการเลิกใช้งานและยินดีที่จะทำทุกครั้งที่พวกเขานำทางเลือกอื่นออกมา นอกจากนี้!importantยังมีส่วนสำคัญในข้อกำหนด CSS ในขณะที่::deepมักจะเป็นเพียงข้อเสนอเท่านั้น
dudewad

คำตอบ:


103

FWIW ในการวิจัยของฉันฉันไม่พบการทดแทน ng-deep หรือทางเลือกอื่นที่เกี่ยวข้อง นี่เป็นเพราะฉันเชื่อว่าทีม Angular กำลังคล้อยตามข้อกำหนด W3C บน shadow dom ซึ่งในตอนแรกมีตัวเลือกเช่นdeep. อย่างไรก็ตาม W3c ได้ลบคำแนะนำออกไปแล้ว แต่ไม่ได้แทนที่ด้วยคำแนะนำใหม่ จนกว่าจะเป็นเช่นนั้นฉันคิดว่าทีม Angular จะคงไว้::ng-deepและเป็นทางเลือกอื่นที่พร้อมใช้งาน แต่อยู่ในสถานะเลิกใช้งานเนื่องจากสถานะรอการร่างของ W3C ฉันไม่สามารถใช้เวลาในการค้นหาเอกสารเพื่อสำรองข้อมูลนี้ได้ในขณะนี้ แต่เพิ่งเห็นเมื่อเร็ว ๆ นี้

เรื่องสั้นขนาดยาว: ใช้ต่อไป::ng-deepและทางเลือกอื่น ๆ จนกว่าจะมีการสร้างสิ่งทดแทน - การเลิกใช้งานเป็นเพียงการแจ้งให้ทราบล่วงหน้าเพื่อไม่ให้ผู้คนตาบอดเมื่อใดก็ตามที่การเปลี่ยนแปลงเกิดขึ้นจริง

- อัพเดท -

https://drafts.csswg.org/css-scoping-1/ นี่คือร่างข้อเสนอหากคุณสนใจ ดูเหมือนว่าพวกเขากำลังทำงานกับชุดตัวเลือกที่แข็งแกร่งสำหรับองค์ประกอบภายใน Shadow Dom Tree มันเป็นข้อมูลจำเพาะนี้เมื่อได้รับการอนุมัติแล้วฉันคิดว่าจะแจ้งให้โคลนเชิงมุมทราบหากมีอยู่ (เช่นเชิงมุมอาจไม่จำเป็นต้องใช้ตัวเลือกของตัวเองเมื่อสิ่งนี้ใช้งานได้ในเบราว์เซอร์)


ฉันเห็นด้วยกับสิ่งนี้ แต่ไม่แนะนำให้เขียนโค้ดใหม่โดยตั้งใจโดยใช้ฟังก์ชันเฟรมเวิร์ก (และเบราว์เซอร์) ที่เลิกใช้แล้ว
MT_

7
ฉันก็เช่นกัน แต่ไม่มีทางเลือกอื่นซึ่งฉันคิดว่าไม่ได้ระบุไว้อย่างชัดเจนที่นี่ คุณมีคำแนะนำที่จะช่วยได้หรือไม่?
dudewad

1
ทางเลือกเดียวที่ฉันคิดได้อย่างรวดเร็วคือการปรับโครงสร้างส่วนประกอบที่ซ้อนกันใหม่ซึ่งอาจจะได้ผลมากกว่าที่คุณมีเวลา แต่อาจให้ผลประโยชน์อื่น ๆ ...
MT_

32
ด้วยไลบรารีของบุคคลที่สามแทบจะเป็นไปไม่ได้เลยที่จะหลีกเลี่ยงการใช้งาน::ng-deepนาน ๆ ครั้ง (หากคุณสนใจว่าไซต์ของคุณจะมีหน้าตาเป็นอย่างไร) แม้จะมีบางอย่างเช่นวัสดุเชิงมุมก็ตาม พวกเขามีข้อบกพร่องที่ไม่ได้รับการแก้ไขเป็นเวลาหลายเดือนและวิธีแก้ปัญหามักเกี่ยวข้องกับ ng-deep และอย่าสับสนกับตัวเลือก "ลึก" ที่เลิกใช้งานต่างกันเพราะเป็นตัวเลือก::ng-deepที่เลิกใช้งานน้อยที่สุด
Simon_Weaver

1
ใช่นี่เป็นส่วนที่น่าเกลียดที่สุดของระบบทั้งหมด แต่การห่อหุ้มคือสิ่งที่ห่อหุ้มคือ คุณต้องทำลายขอบเขตโดยใช้ :: ng-deep ใน css อย่างชัดเจนหรือคุณต้องทำแบบเป็นโปรแกรม บางครั้งเราใช้แอตทริบิวต์บนแท็กองค์ประกอบเพื่อระบุว่า "โหมด" องค์ประกอบใดอยู่ในบริบทใด (เช่นบริบท) จากนั้นรูปแบบจะอยู่ในองค์ประกอบลูกที่มี w / o :: ng-deep ผ่านตัวเลือกแอตทริบิวต์เช่น: :host[some-context] {}- it ขึ้นอยู่กับว่าคุณต้องการความยืดหยุ่น / พกพาแบบไหน ฉันไม่ชอบทั้งสองวิธี แต่นี่คือโลกแห่งการห่อหุ้ม
dudewad

20

ที่จะหลีกเลี่ยงเลิกผมมักจะปิดการใช้งาน::ng-deep ViewEncapsulationแม้ว่านี่จะไม่ใช่แนวทางที่ดีที่สุด แต่ก็ให้บริการฉันได้ดี

หากต้องการปิดใช้งานViewEncapsulationให้ทำดังต่อไปนี้ในคอมโพเนนต์ของคุณ:

import { Component, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss'],
  encapsulation: ViewEncapsulation.None
})

export class HeaderComponent {

}

สิ่งนี้จะทำให้รูปแบบ. scss ในคอมโพเนนต์นี้เป็นสากลสำหรับแอปพลิเคชันทั้งหมด ในการไม่อนุญาตให้สไตล์ขึ้นไปบน chain ไปยังส่วนประกอบหลักและพี่น้องให้ห่อ scss ทั้งหมดด้วยตัวเลือกดังนี้:

app-header {
  // your styles here and any child component styles can go here
}

ตอนนี้สไตล์ที่ระบุไว้ที่นี่จะลงไปที่ส่วนประกอบลูก ๆ ดังนั้นคุณต้องเจาะจงเป็นพิเศษกับตัวเลือก css ของคุณและคำนึงถึง p และ q ของคุณเมื่อเพิ่ม CSS (อาจเพิ่มตัวเลือกลูกที่ระบุในแอป Angular ของคุณแล้วตามด้วยสไตล์)

ฉันบอกว่ามันไม่ใช่แนวทางที่ดีที่สุดเนื่องจากย่อหน้าข้างบน แต่สิ่งนี้ให้บริการฉันได้ดี


12
นี่เป็นเพียงวิธีแก้ปัญหาและหากคุณมีโปรเจ็กต์ขนาดใหญ่การปิดViewEncapsulationจะสร้างความเสียหายอย่างมากโดยทำให้สไตล์เหล่านั้นรั่วไหลไปยังส่วนประกอบทั้งหมดได้ ควรใช้คุณลักษณะนี้อย่างชาญฉลาดและด้วยความเข้าใจอย่างถ่องแท้
mpro

5
@mpro ฉันเข้าใจนั่นเป็นเหตุผลที่ฉันให้ข้อแม้และบอกว่านี่ไม่ใช่แนวทางที่ดีที่สุดและคุณต้องคำนึงถึง p และ q ของคุณและต้องเจาะจงเป็นพิเศษ สำหรับฉันวิธีนี้ได้ผลดีจนถึงตอนนี้ :: ng-deep ถูกทำเครื่องหมายสำหรับการเลิกใช้งานและนี่เป็นวิธีแก้ปัญหาชั่วคราว
AliF50

1
ฉันคิดว่านี่เป็นข้อสรุปที่น่าสยดสยองหากคุณทำเช่นนี้เนื่องจากถูกคุกคามจากการเลิกใช้งาน ใช่ฉันรู้ว่าคุณยอมรับมาก แต่ฉันคิดว่าคุณกำลังยิงตัวเองด้วยการทำสิ่งนี้จริงๆ การห่อหุ้มดูมีประโยชน์มากด้วยเหตุผลหลายประการ อย่างไรก็ตามมันก็ไม่ได้เลวร้ายเท่ากับใครก็ตามในทีมเชิงมุมที่เลิกใช้งานโดยไม่มีวิธีแก้ปัญหาเชิงตรรกะและทำให้หลายคนสับสน ในตอนท้ายของวันคุณยังคงเขียนโค้ดสำหรับเว็บเบราว์เซอร์ไม่ใช่เครื่องมือเชิงมุมที่เป็นกรรมสิทธิ์บางประเภท
Simon_Weaver

2
@Simon_Weaver ฉันเคารพความคิดเห็นของคุณและขอบคุณสำหรับการแบ่งปัน ฉันแค่เปิดเผยมันเพราะเป็นสิ่งที่ฉันเคยใช้ในการหลีกเลี่ยงการเลิกใช้งาน ฉันยังปรากฏคำเตือน
AliF50

3
@ AliF50 "Circumventing deprectaion" ไม่ใช่เรื่องจริง ปัญหาที่แท้จริงที่นี่เป็นที่และฉันไม่เคยเห็นแบบนี้มาก่อนในชีวิตของพวกเขาเลิกใช้มันโดยไม่ต้องตั้งชื่อทางเลือก คำตอบของฉัน (ข้อที่ยอมรับข้างต้น) อธิบายถึงสมมติฐานของฉันว่าทำไมพวกเขาถึงทำ (W3C เลิกใช้งาน) เพื่อให้สอดคล้องกับข้อมูลจำเพาะ อย่างไรก็ตามหากคุณอ่านข้อเสนอดูเหมือนว่า :: ng-deep จะถูกแทนที่ด้วยทางเลือกที่เหมาะสมซึ่งหมายความว่าเมื่อพร้อมใช้งานคุณเพียงแค่อัปเดตการอ้างอิง :: ng-deep ของคุณแทนที่จะเป็นแนวทางที่เรียกร้องให้มีตัวอักษร ออกแบบแอปพลิเคชันใหม่ทั้งหมด
dudewad

15

ทางเลือกที่ง่ายและสะดวกสำหรับสไตล์ลึกคือสไตล์ทั่วไปโดยใช้ตัวเลือกองค์ประกอบขององค์ประกอบหลัก ดังนั้นหากคุณมีสิ่งนี้ใน hero-details.component.css:

:host ::ng-deep h3 {
  font-style: italic;
}

มันจะกลายเป็นสิ่งนี้ใน styles.css:

app-hero-details h3 {
  font-style: italic;
}

โดยพื้นฐานแล้วสไตล์ลึกเป็นสไตล์ที่ไม่มีการห่อหุ้มดังนั้นในแนวความคิดจึงดูเหมือนสไตล์ทั่วไปสำหรับฉันมากกว่าสไตล์ส่วนประกอบ โดยส่วนตัวฉันจะไม่ใช้รูปแบบที่ลึกอีกต่อไป การเปลี่ยนแปลงการทำลายเป็นเรื่องปกติในการอัปเดตเวอร์ชันหลักและการลบคุณลักษณะที่เลิกใช้แล้วถือเป็นเกมที่ยุติธรรม


1
ว้าวตอนนี้ฉันรู้สึกโง่ ขอบคุณ! มาจากเฟรมเวิร์กส่วนหน้าอื่น ๆ ฉันคิดว่าสิ่งนี้เป็นไปไม่ได้
Rafael Vidaurre

1
นี่เป็นประโยชน์จริงๆ เป็นเรื่องเล็กน้อยที่ :: ng-deep ถูกเลิกใช้งานเป็นเวลานานโดยไม่ต้องมีการเปลี่ยน (: host :: ng-deep ทำงานได้ตามที่คาดไว้ แต่ฉันไม่ต้องการใช้สิ่งที่เลิกใช้แล้ว)
Alexei

6

ตามที่มีคนระบุไว้ก่อนหน้านี้หากคุณกำลังใช้ไลบรารีของบุคคลที่สามแทบจะเป็นไปไม่ได้เลยที่จะหลีกเลี่ยงการใช้::ng-deepนาน ๆ ครั้ง แต่คุณจะทำอย่างไรกับโครงการก่อนหน้านี้เมื่อ::ng-deepเบราว์เซอร์ไม่รองรับอีกต่อไป

เพื่อให้พร้อมสำหรับช่วงเวลานั้นฉันจะแนะนำสิ่งต่อไปนี้:

  1. ใช้ViewEncapsulation ไม่มีอย่างชาญฉลาด ซึ่งแปลว่าสำหรับส่วนประกอบที่ต้องการเข้าถึงส่วนประกอบที่ลึกกว่าเท่านั้น
@Component({
      selector: 'app-example',
      templateUrl: './example.component.html',
      styleUrls: ['./example.component.scss'],
      encapsulation: ViewEncapsulation.None
    })
  1. ตอนนี้เพื่อหลีกเลี่ยงการชนและ CSS ความแปลกประหลาดที่คุณควร (เป็นกฎ) เสมอห่อแม่แบบส่วนประกอบของคุณกับชั้นเรียน ดังนั้น example.component.html ควรเป็นดังนี้:
<section class="app-example-container">
<!-- a third party component -->
<mat-tab-group>
<mat-tab label="First"></mat-tab>
<mat-tab label="Second"></mat-tab>
</mat-tab-group>
</section>
  1. อีกครั้งตามกฎแล้วบรรทัดแรกของไฟล์ SCSS ทุกไฟล์จะกำหนดเป้าหมายไปที่คอนเทนเนอร์คอมโพเนนต์ เนื่องจากไม่มีEncapsulationคุณจึงสามารถปรับเปลี่ยนองค์ประกอบของบุคคลที่สามได้โดยกำหนดเป้าหมายชั้นเรียน ที่กล่าวว่าexample.component.scssควรเป็นดังนี้:
.app-example-container {
/* All the CSS code goes here */
.mat-tab-group .mat-tab-label {color: red;}
}

2

นี่ไม่ใช่การแทนที่ทั่วไปสำหรับ :: ng-deep แต่สำหรับกรณีการใช้งานที่อธิบายโดยผู้เขียนคำถาม:

ในกรณีพิเศษที่คุณต้องการจัดรูปแบบองค์ประกอบที่แทรกด้วยเราเตอร์เต้าเสียบมีวิธีแก้ปัญหาที่สวยงามโดยใช้ตัวเลือกเพื่อนบ้านที่อยู่ติดกันใน CSS:

router-outlet+* {
  /* styling here... */
}

สิ่งนี้จะใช้กับองค์ประกอบทั้งหมดที่เป็นเพื่อนบ้านโดยตรงของเราเตอร์เต้าเสียบ

อ่านเพิ่มเติม:
https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_combinator
https://angular.io/guide/router#router-outlet


1
ฉันไม่แนะนำให้ใช้ตัวเลือกนี้ ดูเหมือนว่าคุณกำลังเปิดฝันร้ายของการชนกันโดยเฉพาะอย่างยิ่งเมื่อแอปพลิเคชันของคุณเติบโตขึ้น ยิ่งไปกว่านั้นตัวเลือก * เป็นตัวเลือกเดียวที่ช้าที่สุดในการดำรงอยู่ของ CSS
dudewad

@dudewad ในขณะที่ * selector เป็นตัวเลือกที่ช้าที่สุด แต่จะใช้กับพี่น้องคนต่อไปเท่านั้น (+) ไม่ใช่ทั้ง chain / tree ดังนั้นจึงควรสร้างความแตกต่างเพียงเล็กน้อยเท่านั้น
Erik Philips

ตัวเลือก CSS ของ @ErikPhilips จะแยกวิเคราะห์จากขวาไปซ้ายดังนั้นนี่จึงเป็นสถานการณ์ที่เลวร้ายที่สุด
dudewad

@dudewad ฉันคิดว่าเราขาดอะไรไป *เป็นสถานการณ์ที่เลวร้ายที่สุดตามมาอย่างใกล้ชิดelement *แต่element + *ไม่ใกล้เคียงกับสองครั้งแรก
Erik Philips

ฉันไม่รู้ ... ฉันยังไม่ได้ทดสอบนี่เป็นเพียงสิ่งที่ฉันรู้เกี่ยวกับวิธีที่ตัวแยกวิเคราะห์ CSS ทำสิ่งนั้น
dudewad

1

เพื่อหลีกเลี่ยงการเปลี่ยนการห่อหุ้มเริ่มต้นฉันเขียนตัวช่วยที่ต่อท้ายสไตล์ส่วนกลางสำหรับส่วนประกอบ:

deepStyle.ts

import { ViewContainerRef } from '@angular/core';

export function deepStyle(vcr: ViewContainerRef, csss: string[]){
    let id = 'deep-' + vcr.element.nativeElement.tagName;
    let styleElement = document.getElementById('pierce-' + vcr.element.nativeElement.name);
    if(!styleElement){
        styleElement = document.createElement('style');
        styleElement.id = id;
        styleElement.innerHTML = csss.map(css => vcr.element.nativeElement.tagName + ' ' + css).join('\n');
        document.head.append(styleElement);
    }
}

my-component.ts

import { Component, ViewContainerRef } from '@angular/core';
import { deepStyle } from '../deepStyle';

@Component({
  selector: 'my-component',
  templateUrl: './my-component.html',
  styleUrls: ['./my-component.css']
})
export class MyComponent {
   constructor(vcr: ViewContainerRef) {
    deepStyle(vcr, [`
       img {
         height: 180px;
       }
    `]);
  }
}

ผลลัพธ์:

<head>
...
<style id="deep-MY-COMPONENT">
    MY-COMPONENT img {
      height: 180px;
    }
</style>
...
</head>

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.